mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-23 00:14:25 +00:00
585 lines
17 KiB
C
585 lines
17 KiB
C
/*
|
|
Copyright 1982
|
|
Alcyon Corporation
|
|
8716 Production Ave.
|
|
San Diego, Ca. 92121
|
|
|
|
@(#)stmt.c 1.4 12/27/83
|
|
*/
|
|
|
|
#include "parser.h"
|
|
|
|
#define LABGEN(l,sl) sl=l;l=nextlabel++
|
|
#define DOBODY(l) stmt();OUTLAB((l));clno=lineno;lineno=rinit
|
|
|
|
short bol;
|
|
|
|
/* stmt - process a single statement*/
|
|
stmt() /* returns - none*/
|
|
{
|
|
register short token, lab;
|
|
|
|
while( 1 ) {
|
|
switch(token=gettok(0)) {
|
|
|
|
case LCURBR: /*handle { ... }*/
|
|
scope_decls[scope_level] = 1; /* [vlh] 4.2, block decls */
|
|
dlist(TYPELESS);
|
|
while( !next(EOF) ) {
|
|
if( next(RCURBR) )
|
|
return;
|
|
stmt();
|
|
}
|
|
case EOF:
|
|
error("{ not matched by }");
|
|
case SEMI: /*null statement*/
|
|
return;
|
|
|
|
case RCURBR:
|
|
pbtok(token);
|
|
return;
|
|
|
|
case SYMBOL: /*symbol: statement*/
|
|
if( peekc(':') ) {
|
|
dolabel();
|
|
continue;
|
|
}
|
|
default: /*anything else...*/
|
|
pbtok(token);
|
|
outexpr(expr(0));
|
|
break;
|
|
|
|
case RESWORD:
|
|
switch(cvalue) {
|
|
|
|
case R_BREAK:
|
|
lab = brklabel();
|
|
OUTGOTO(lab); /*branch to break label*/
|
|
break;
|
|
|
|
case R_CASE:
|
|
docase();
|
|
continue;
|
|
|
|
case R_CONTINUE:
|
|
lab = contlabel(); /*branch to continue label*/
|
|
OUTGOTO(lab);
|
|
break;
|
|
|
|
case R_DEFAULT:
|
|
dodefault();
|
|
continue;
|
|
|
|
case R_DO:
|
|
dodo();
|
|
break;
|
|
|
|
case R_FOR:
|
|
dofor();
|
|
return;
|
|
|
|
case R_GOTO:
|
|
lab = gotolabel();
|
|
OUTGOTO(lab);
|
|
break;
|
|
|
|
case R_IF:
|
|
doif();
|
|
return;
|
|
|
|
case R_RETURN:
|
|
doreturn();
|
|
break;
|
|
|
|
case R_SWITCH:
|
|
doswitch();
|
|
return;
|
|
|
|
case R_WHILE:
|
|
dowhile();
|
|
return;
|
|
|
|
case R_ASM:
|
|
doasm();
|
|
return;
|
|
|
|
case R_CHAR:
|
|
case R_INT:
|
|
case R_FLOAT:
|
|
case R_LONG:
|
|
case R_DOUBLE:
|
|
case R_STRUCT:
|
|
case R_UNION:
|
|
case R_REGISTER:
|
|
synerr("invalid declaration");
|
|
return;
|
|
|
|
default:
|
|
synerr("invalid keyword");
|
|
return;
|
|
}
|
|
}
|
|
if( !next(SEMI) )
|
|
synerr("missing semicolon");
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* balpar - handle expression within parenthesis for while and if*/
|
|
/* Merely checks for left and right parens and builds expression.*/
|
|
char *
|
|
balpar() /* returns pointer to expression*/
|
|
{
|
|
register struct tnode *tp;
|
|
|
|
if( next(LPAREN) ) {
|
|
reducep = 1;
|
|
tp = (struct tnode *)expr(0);
|
|
reducep = 0;
|
|
if( next(RPAREN) )
|
|
return((char *)tp);
|
|
}
|
|
synerr("parenthesized expression syntax");
|
|
return(0);
|
|
}
|
|
|
|
/* gotolabel - gets label id for goto*/
|
|
/* This is used for both: goto symbol and if(...)goto symbol*/
|
|
gotolabel() /* returns 0 if not, else label id*/
|
|
{
|
|
register struct symbol *sp;
|
|
|
|
if( !next(SYMBOL) )
|
|
synerr("expected label");
|
|
else {
|
|
sp = csp;
|
|
if( !(sp->s_sc) ) {
|
|
sp->s_type = LLABEL;
|
|
sp->s_scope = FUNC_SCOPE;
|
|
if( !sp->s_offset )
|
|
sp->s_offset = nextlabel++;
|
|
TO_DSK(sp,csp_addr);
|
|
}
|
|
else if (sp->s_scope != FUNC_SCOPE) { /* [vlh] 4.2 */
|
|
csp = lookup(sp->s_symbol,1); /* force individual entry */
|
|
sp = csp;
|
|
sp->s_type = LLABEL;
|
|
sp->s_scope = FUNC_SCOPE;
|
|
if( !sp->s_offset )
|
|
sp->s_offset = nextlabel++;
|
|
TO_DSK(sp,csp_addr);
|
|
}
|
|
if( (!sp->s_sc || sp->s_sc == STATIC ) && sp->s_type == LLABEL )
|
|
return(sp->s_offset);
|
|
synerr("invalid label");
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* dolabel - do statement label
|
|
* Checks current symbol for already being defined, then sets
|
|
* symbol attributes for label.
|
|
**/
|
|
dolabel() /* returns - none*/
|
|
{
|
|
register struct symbol *sp;
|
|
|
|
sp = csp;
|
|
if( sp->s_sc ) { /* [vlh] 4.2 */
|
|
if( sp->s_scope == FUNC_SCOPE ) { /* truly redefined !!!! */
|
|
error("label redeclaration: %.8s",sp->s_symbol);
|
|
return;
|
|
}
|
|
csp = lookup(sp->s_symbol,1); /* force individual entry */
|
|
sp = csp;
|
|
}
|
|
sp->s_attrib |= SDEFINED;
|
|
sp->s_sc = STATIC;
|
|
sp->s_type = LLABEL;
|
|
sp->s_scope = FUNC_SCOPE;
|
|
if( !sp->s_offset )
|
|
sp->s_offset = nextlabel++;
|
|
TO_DSK(sp,csp_addr);
|
|
OUTLAB(sp->s_offset);
|
|
}
|
|
|
|
/* brklabel - generate break label*/
|
|
/* Checks if break label is undefined, and if so, generates message*/
|
|
brklabel() /* returns label number*/
|
|
{
|
|
if( !blabel )
|
|
error("invalid break statement");
|
|
return(blabel);
|
|
}
|
|
|
|
/* contlabel - generate continue label*/
|
|
/* Checks if continue label is undefined, and if so, generates message*/
|
|
contlabel() /* returns label number*/
|
|
{
|
|
if( !clabel )
|
|
error("invalid continue statement");
|
|
return(clabel);
|
|
}
|
|
|
|
/* docase - handles: case constant : statement*/
|
|
/* Checks for being in a switch statement, adds entry to switch table*/
|
|
docase() /* returns - none*/
|
|
{
|
|
register short lab;
|
|
long value;
|
|
|
|
colonstop++;
|
|
value = cexpr(); /*get case value*/
|
|
colonstop--;
|
|
if( !next(COLON) ) /*check for colon*/
|
|
synerr("missing colon");
|
|
if( swp < 0 )
|
|
error("case not inside a switch block");
|
|
else if( swp >= (SWSIZE-1) )
|
|
error("too many cases in switch");
|
|
else {
|
|
if(addswitch(&swtab[cswp],swp-cswp,(int)value,lab=nextlabel)) {
|
|
nextlabel++;
|
|
OUTLAB(lab);
|
|
swp++;
|
|
} /* [vlh] 4.3, only if not duplicate case !!! */
|
|
}
|
|
}
|
|
|
|
/* dodefault - handles: default : statement*/
|
|
/* Checks for colon and being in a switch statement*/
|
|
dodefault() /* returns - none*/
|
|
{
|
|
if( !next(COLON) )
|
|
error("missing colon");
|
|
if( swp < 0 )
|
|
error("default not inside a switch block");
|
|
else {
|
|
dlabel = nextlabel++; /*allocate default label*/
|
|
OUTLAB(dlabel); /*output default label*/
|
|
}
|
|
}
|
|
|
|
/* dodo - handles: do statement while ( expression )*/
|
|
dodo() /* returns - none*/
|
|
{
|
|
register short lab, saveblab, saveclab;
|
|
|
|
LABGEN(blabel,saveblab);
|
|
LABGEN(clabel,saveclab);
|
|
lab = nextlabel++;
|
|
outline(); /*[vlh]4.2 output lineno for debugger*/
|
|
OUTNULL(); /*[vlh]4.2 null tree for line number */
|
|
OUTLAB(lab); /*branch back to here*/
|
|
stmt(); /*do statement*/
|
|
OUTLAB(clabel); /*continue label*/
|
|
if( !nextrw(R_WHILE) ) {
|
|
warning("missing while"); /*only advisory...*/
|
|
OUTGOTO(lab);
|
|
}
|
|
else
|
|
outifgoto(balpar(),TRUE,lab); /*while expression*/
|
|
OUTLAB(blabel); /*break label*/
|
|
blabel = saveblab; /*restore labels*/
|
|
clabel = saveclab;
|
|
}
|
|
|
|
/*
|
|
* dofor - handle: for ( expression ; expression ; expression ) statement
|
|
* Hard part is handling re-initialization expression, which is
|
|
* parsed and saved, then the statement is parsed, then the reinit
|
|
* clause expression tree is output.
|
|
*/
|
|
dofor() /* returns - none*/
|
|
{ /* [vlh] 4.0 reordered */
|
|
register short testlab, stmtlab, saveblab, saveclab;
|
|
register struct tnode *rip, *cp;
|
|
register char *savep;
|
|
short rinit, clno, iscond;
|
|
|
|
LABGEN(blabel,saveblab);
|
|
LABGEN(clabel,saveclab);
|
|
if( !next(LPAREN) ) {
|
|
forerr:
|
|
#ifdef DEBUG
|
|
if (symdebug) printf("invalid for... commastop is %d",commastop);
|
|
#endif
|
|
synerr("invalid for statement");
|
|
return;
|
|
}
|
|
if( !next(SEMI) ) { /*do init expression*/
|
|
outexpr(expr(0));
|
|
if( !next(SEMI) )
|
|
goto forerr;
|
|
}
|
|
savep = exprp; /* save ptr to exprarea */
|
|
if( !next(SEMI) ) { /* do for condition */
|
|
testlab = nextlabel++; /* if condition, get a label */
|
|
OUTGOTO(testlab); /* only goto cond expr if exists*/
|
|
iscond = 1;
|
|
cp = (struct tnode *)expr(0);
|
|
exprp = opap;
|
|
if( !next(SEMI) )
|
|
goto forerr;
|
|
}
|
|
else
|
|
iscond = 0;
|
|
stmtlab = nextlabel++;
|
|
OUTLAB(stmtlab); /* branch back to here */
|
|
rinit = lineno;
|
|
if( next(RPAREN) ) { /*no re-init - easy case*/
|
|
DOBODY(clabel); /*output statement*/
|
|
}
|
|
else { /*there is a re-init clause*/
|
|
rip = (struct tnode *)expr(0); /*save re-init tree until done*/
|
|
exprp = opap;
|
|
if( !next(RPAREN) )
|
|
goto forerr;
|
|
DOBODY(clabel); /*do statment*/
|
|
outexpr(rip); /*output re-init clause*/
|
|
}
|
|
if (iscond) {
|
|
OUTLAB(testlab); /* branch for test */
|
|
outifgoto(cp,TRUE,stmtlab);
|
|
}
|
|
else
|
|
OUTGOTO(stmtlab); /* unconditional branch */
|
|
exprp = savep;
|
|
lineno = clno;
|
|
OUTLAB(blabel); /* break label */
|
|
blabel = saveblab;
|
|
clabel = saveclab; /*restore labels*/
|
|
}
|
|
|
|
/* doif - handles: if ( expression ) statement [ else statement ]*/
|
|
/* Handles special cases for goto, break, continue and return.*/
|
|
doif() /* returns - none*/
|
|
{
|
|
register struct tnode *tp;
|
|
register short elselab, exitlab;
|
|
|
|
outline();
|
|
OUTNULL();
|
|
tp = (struct tnode *)balpar(); /*if( expr )...*/
|
|
exitlab = 0;
|
|
if( nextrw(R_GOTO) )
|
|
exitlab = gotolabel();
|
|
else if( nextrw(R_BREAK) )
|
|
exitlab = brklabel();
|
|
else if( nextrw(R_CONTINUE) )
|
|
exitlab = contlabel();
|
|
else if( nextrw(R_RETURN) ) {
|
|
if( peekc(';') ) {
|
|
exitlab = rlabel;
|
|
putback(';');
|
|
}
|
|
else
|
|
pbtok(RESWORD);
|
|
}
|
|
if( exitlab ) { /*easy goto, do branch if true*/
|
|
outifgoto(tp,TRUE,exitlab);
|
|
if( !next(SEMI) )
|
|
synerr("missing semicolon");
|
|
if( nextrw(R_ELSE) ) /*else clause, just output it*/
|
|
stmt();
|
|
}
|
|
else { /*hard goto, branch over statement*/
|
|
elselab = nextlabel++;
|
|
outifgoto(tp,FALSE,elselab);
|
|
stmt();
|
|
if( nextrw(R_ELSE) ) {
|
|
exitlab = nextlabel++; /*branches over else clause*/
|
|
OUTGOTO(exitlab); /*branch out of then clause*/
|
|
OUTLAB(elselab); /*label to start else clause*/
|
|
stmt(); /*else statement*/
|
|
OUTLAB(exitlab);
|
|
}
|
|
else
|
|
OUTLAB(elselab); /*no else, just branch out*/
|
|
}
|
|
}
|
|
|
|
/*
|
|
* doreturn - handles: return( expression ) ;
|
|
* Expression is the hard part, must create an assignment expression
|
|
* to assign expression to the type of the function, then get it
|
|
* loaded into a specific register.
|
|
*/
|
|
doreturn() /* returns - none*/
|
|
{
|
|
register struct tnode *tp;
|
|
|
|
if (!peekc(';')) {
|
|
if ((tp=(struct tnode *)expr(0)) != 0)
|
|
outforreg(FRETURN,frp,tp);
|
|
else
|
|
putback(';');
|
|
}
|
|
else
|
|
putback(';');
|
|
OUTGOTO(rlabel); /*branch to the return label*/
|
|
}
|
|
|
|
/*
|
|
* doasm - handles: asm( "string" ) ; [vlh] 4.2
|
|
* Outputs the string as literal assembly language code
|
|
*/
|
|
doasm() /* returns - none*/
|
|
{
|
|
outline(); /* [vlh] 4.2 output line number */
|
|
OUTNULL(); /* [vlh]4.2 null tree for line number */
|
|
if( next(LPAREN) ) {
|
|
if (next(STRING))
|
|
if (next(RPAREN)) {
|
|
outasm();
|
|
return;
|
|
}
|
|
}
|
|
synerr("illegal asm syntax");
|
|
}
|
|
|
|
/*
|
|
* doswitch - handles: switch ( expression ) statement
|
|
* Evaluates the expression, forces the result into a known register
|
|
* collects the case statements in swtab, then outputs the switch
|
|
* operator and switch cases.
|
|
*/
|
|
doswitch() /* returns - none*/
|
|
{
|
|
register short saveblab, swlab, savedlab, saveswp, i;
|
|
register struct tnode *tp;
|
|
|
|
LABGEN(blabel,saveblab);
|
|
tp = (struct tnode *)balpar();
|
|
integral(tp,-1); /*must be integral type result*/
|
|
outforreg(ASSIGN,snalloc(INT,AUTO,0,0,0),tp);
|
|
saveswp = swp; /*remember old switch pointer*/
|
|
if( saveswp < 0 )
|
|
swp++;
|
|
i = cswp;
|
|
cswp = swp; /*remember real first entry*/
|
|
swlab = nextlabel++;
|
|
OUTGOTO(swlab); /*branch to switch code*/
|
|
savedlab = dlabel;
|
|
dlabel = 0;
|
|
stmt(); /*do switch statement*/
|
|
OUTGOTO(blabel); /*output branch just in case*/
|
|
OUTLAB(swlab); /*here we now do the switch code*/
|
|
if( !dlabel )
|
|
dlabel = blabel;
|
|
outswitch(swp-cswp,dlabel,&swtab[cswp]);
|
|
OUTLAB(blabel); /*break to here*/
|
|
cswp = i;
|
|
swp = saveswp;
|
|
blabel = saveblab;
|
|
dlabel = savedlab;
|
|
}
|
|
|
|
/* dowhile - handles: while ( expression ) statement*/
|
|
/* This is fairly straight-forward.*/
|
|
dowhile() /* returns - none*/
|
|
{ /* [vlh] 4.0 reworked */
|
|
register short saveclab, saveblab, lab;
|
|
register char *savep;
|
|
register struct tnode *tp;
|
|
|
|
LABGEN(blabel,saveblab);
|
|
LABGEN(clabel,saveclab);
|
|
LABGEN(clabel,lab);
|
|
savep = exprp;
|
|
outline(); /*[vlh]4.2 output line number on cond*/
|
|
OUTNULL(); /*[vlh]4.2 null tree for line number*/
|
|
if((tp = (struct tnode *)balpar()) != 0) /*get condition clause*/
|
|
OUTGOTO(clabel); /*condition label*/
|
|
exprp = opap;
|
|
OUTLAB(lab);
|
|
stmt(); /*statement*/
|
|
OUTLAB(clabel); /*condition test*/
|
|
outifgoto(tp,TRUE,lab); /* branch back to top of loop */
|
|
OUTLAB(blabel); /*break to here*/
|
|
exprp = savep;
|
|
blabel = saveblab;
|
|
clabel = saveclab; /*restore labels*/
|
|
}
|
|
|
|
/* nextrw - is next token the specified reserved word?*/
|
|
nextrw(rw) /* returns 1 if match, 0 otherwise*/
|
|
int rw; /* reserved word to match*/
|
|
{
|
|
register short token;
|
|
|
|
if( (token=gettok(0)) != RESWORD || cvalue != rw ) {
|
|
pbtok(token);
|
|
return(0);
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
* addswitch - add an entry into current switch table, bubble sorting
|
|
* This makes it easier on the code generator and also checks for
|
|
* duplicate labels at the "right" time.
|
|
*/
|
|
addswitch(sp,ncases,nval,nlab) /* returns - none*/
|
|
struct swtch *sp; /* switch table pointer*/
|
|
int ncases; /* number of cases in switch*/
|
|
int nval; /* new value */
|
|
int nlab; /* new label*/
|
|
{
|
|
register struct swtch *nswp, *s;
|
|
register short temp;
|
|
|
|
nswp = &sp[ncases];
|
|
nswp->sw_value = nval;
|
|
nswp->sw_label = nlab;
|
|
s = nswp--;
|
|
for( ; --ncases >= 0; s--, nswp-- ) {
|
|
if( s->sw_value == nswp->sw_value ) {
|
|
error("duplicate case value");
|
|
return(0); /* [vlh] 4.3, don't add it in !!!! */
|
|
}
|
|
if( s->sw_value < nswp->sw_value ) {
|
|
temp = s->sw_value;
|
|
s->sw_value = nswp->sw_value;
|
|
nswp->sw_value = temp;
|
|
temp = s->sw_label;
|
|
s->sw_label = nswp->sw_label;
|
|
nswp->sw_label = temp;
|
|
}
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
/* outforreg - generate assignment for switch and return*/
|
|
outforreg(op,ltp,rtp) /*returns - none*/
|
|
int op; /*operator for build tree*/
|
|
struct tnode *ltp; /*left expression tree*/
|
|
struct tnode *rtp; /*right expression tree*/
|
|
{
|
|
register struct tnode *tp;
|
|
|
|
opp = opstack;
|
|
opdp = opdstack;
|
|
pushopd(ltp);
|
|
pushopd(rtp);
|
|
maketree(op);
|
|
if( tp = (struct tnode *)popopd() )
|
|
outcforreg(tp->t_right);
|
|
opp = 0; opdp = (char **)0;
|
|
}
|
|
|
|
/* outassign - generate assignment for function args*/
|
|
outassign(ltp,rtp) /*returns - none*/
|
|
struct tnode *ltp; /*left expression tree*/
|
|
struct tnode *rtp; /*right expression tree*/
|
|
{
|
|
opp = opstack;
|
|
opdp = opdstack;
|
|
pushopd(ltp);
|
|
pushopd(rtp);
|
|
maketree(ASSIGN);
|
|
outexpr(popopd());
|
|
opp = 0; opdp = (char **)0;
|
|
}
|