Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v102a/al40/c068/stmt.c
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

525 lines
12 KiB
C

/*
Copyright 1982
Alcyon Corporation
8716 Production Ave.
San Diego, Ca. 92121
*/
#include "parser.h"
#define labgen(l,sl) sl=l;l=nextlabel++
int swp -1;
/* stmt - process a single statement*/
stmt() /* returns - none*/
{
register int token, lab, i;
register struct tnode *tp;
register char *p;
while( 1 ) {
switch(token=gettok()) {
case LCURBR: /*handle { ... }*/
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());
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;
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 = expr();
reducep = 0;
if( next(RPAREN) )
return(tp);
}
synerr("parenthesized expression syntax");
return(0);
}
/* synerr - syntax error*/
/* Outputs error message and tries to resyncronize input.*/
synerr(s,x1,x2,x3,x4,x5,x6) /* returns - none*/
char *s; /* printf format string*/
int x1, x2, x3, x4, x5, x6; /* printf arguments*/
{
register int token;
error(s,x1,x2,x3,x4,x5,x6);
while( (token=gettok()) != SEMI && token != EOF && token != LCURBR &&
token != RCURBR )
;
pbtok(token);
}
/* 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;
if( !sp->s_offset )
sp->s_offset = nextlabel++;
}
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 )
error("label redeclaration: %.8s",sp->s_symbol);
else {
sp->s_attrib =| SDEFINED;
sp->s_sc = STATIC;
sp->s_type = LLABEL;
if( !sp->s_offset )
sp->s_offset = nextlabel++;
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 int value, lab;
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 {
addswitch(&swtab[cswp],swp-cswp,value,lab=nextlabel++);
outlab(lab);
swp++;
}
}
/* 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 int lab, saveblab, saveclab;
labgen(blabel,saveblab);
labgen(clabel,saveclab);
lab = nextlabel++;
outlab(lab); /*branch back to here*/
stmt(); /*do statement*/
outlab(clabel); /*continue label*/
if( !nextrw(R_WHILE) ) {
error("missing while"); /*only advisory...*/
outgoto(lab);
}
else
outifgoto(balpar(),TRUE,lab); /*while expression*/
outlab(blabel); /*break label*/
blabel = saveblab; /*restore labels*/
clabel = saveclab;
}
#define dobody(l) stmt();outlab((l));clno=lineno;lineno=rinit
/*
* 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 int testlab, stmtlab, saveblab, saveclab;
register struct tnode *rip, *cp;
register char *savep;
int rinit, clno, iscond;
labgen(blabel,saveblab);
labgen(clabel,saveclab);
if( !next(LPAREN) ) {
forerr:
synerr("invalid for statement");
return;
}
if( !next(SEMI) ) { /*do init expression*/
outexpr(expr());
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 = expr();
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 = expr(); /*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 int elselab, exitlab;
tp = 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(';') ) /*need to compute return?*/
outforreg(FRETURN,frp,expr());
else
putback(';');
outgoto(rlabel); /*branch to the return label*/
}
/*
* 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 int saveblab, swlab, savedlab, saveswp, i;
register struct tnode *tp;
labgen(blabel,saveblab);
tp = 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 int saveclab, saveblab, lab;
register char *savep;
register struct tnode *tp;
labgen(blabel,saveblab);
labgen(clabel,saveclab);
labgen(clabel,lab);
savep = exprp;
if((tp = 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 int token;
if( (token=gettok()) != 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 int temp, i;
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");
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;
}
}
}
/* 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 = popopd() )
outcforreg(tp->t_right);
opp = opdp = 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 = opdp = 0;
}