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

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;
}