diff --git a/lang/basic/src/basic.g b/lang/basic/src/basic.g index 24503f47a..0f7949bf6 100644 --- a/lang/basic/src/basic.g +++ b/lang/basic/src/basic.g @@ -3,797 +3,1333 @@ * See the copyright notice in the ACK home directory, in the file "Copyright". */ -%token ILLEGAL ; -%token ASSYM ; -%token BASESYM ; -%token CALLSYM ; -%token CLEARSYM ; -%token CLOSESYM ; -%token DATASYM ; -%token DEFINTSYM ; -%token DEFSNGSYM ; -%token DEFDBLSYM ; -%token DEFSTRSYM ; -%token DEFSYM ; -%token DIMSYM ; -%token ELSESYM ; -%token ERRSYM ; -%token ERLSYM ; -%token ERRORSYM ; -%token FIELDSYM ; -%token FORSYM ; -%token FUNCTION ; -%token FUNCTID ; -%token INKEYSYM ; -%token GETSYM ; -%token GOSUBSYM ; -%token GOTOSYM ; -%token IFSYM ; -%token INPUTSYM ; -%token LETSYM ; -%token LINESYM ; -%token LSETSYM ; -%token MIDSYM ; -%token NEXTSYM ; -%token ONSYM ; -%token OPENSYM ; -%token OPTIONSYM ; -%token PRINTSYM ; -%token POKESYM ; -%token PUTSYM ; -%token RANDOMIZESYM ; -%token READSYM ; -%token REMSYM ; -%token RESTORESYM ; -%token RETURNSYM ; -%token ENDSYM ; -%token STOPSYM ; -%token STEPSYM ; -%token SWAPSYM ; -%token THENSYM ; -%token TOSYM ; -%token TRONOFFSYM ; -%token USINGSYM ; -%token USRSYM ; -%token WHILESYM ; -%token WENDSYM ; -%token WRITESYM ; +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/basic/src/basic.g + */ + +%token ILLEGAL; +%token ASSYM; +%token BASESYM; +%token CALLSYM; +%token CLEARSYM; +%token CLOSESYM; +%token DATASYM; +%token DEFINTSYM; +%token DEFSNGSYM; +%token DEFDBLSYM; +%token DEFSTRSYM; +%token DEFSYM; +%token DIMSYM; +%token ELSESYM; +%token ERRSYM; +%token ERLSYM; +%token ERRORSYM; +%token FIELDSYM; +%token FORSYM; +%token FUNCTION; +%token FUNCTID; +%token INKEYSYM; +%token GETSYM; +%token GOSUBSYM; +%token GOTOSYM; +%token IFSYM; +%token INPUTSYM; +%token LETSYM; +%token LINESYM; +%token LSETSYM; +%token MIDSYM; +%token NEXTSYM; +%token ONSYM; +%token OPENSYM; +%token OPTIONSYM; +%token PRINTSYM; +%token POKESYM; +%token PUTSYM; +%token RANDOMIZESYM; +%token READSYM; +%token REMSYM; +%token RESTORESYM; +%token RETURNSYM; +%token ENDSYM; +%token STOPSYM; +%token STEPSYM; +%token SWAPSYM; +%token THENSYM; +%token TOSYM; +%token TRONOFFSYM; +%token USINGSYM; +%token USRSYM; +%token WHILESYM; +%token WENDSYM; +%token WRITESYM; /* special tokens */ -%token EOLN ; -%token INTVALUE ; -%token FLTVALUE ; -%token DBLVALUE ; -%token STRVALUE ; -%token UNARYSYM ; -%token IDENTIFIER ; -%token ANDSYM ; -%token ORSYM ; -%token IMPSYM ; -%token EQVSYM ; -%token XORSYM ; -%token VARPTR ; +%token EOLN; +%token INTVALUE; +%token FLTVALUE; +%token DBLVALUE; +%token STRVALUE; +%token UNARYSYM; +%token IDENTIFIER; +%token ANDSYM; +%token ORSYM; +%token IMPSYM; +%token EQVSYM; +%token XORSYM; +%token VARPTR; /* Those were originally %left */ -%token BOOLOP ; -%token NOTSYM ; -%token RELOP ; -%token MODSYM ; +%token BOOLOP; +%token NOTSYM; +%token RELOP; +%token MODSYM; /* Some contstant declared as tokens (?) */ -%token LESYM ; -%token GESYM ; -%token NESYM ; -%token UNARYMINUS ; +%token LESYM; +%token GESYM; +%token NESYM; +%token UNARYMINUS; { -#define YYDEBUG -#include -#include -#include -#include "bem.h" -#include "util.h" -#include "gencode.h" -#include "eval.h" -#include "func.h" -#include "llmess.h" - -typedef union { - int integer ; - Symbol *Sptr ; - char *cptr ; -} YYSTYPE ; - -int basicline; - -int yydebug; - -YYSTYPE yylval; - -int ival; -char *dval; -char *sval; -int in_data = 0; /* set if processing DATA statement */ - -char *formatstring; /* formatstring used for printing */ -Symbol *s; /* Symbol dummy */ - -#include "yylexp.h" -#include "basic.lex" + #define YYDEBUG + #include + #include + #include + #include "bem.h" + #include "util.h" + #include "gencode.h" + #include "eval.h" + #include "func.h" + #include "llmess.h" + + typedef union + { + int integer; + Symbol* Sptr; + char* cptr; + } YYSTYPE; + + int basicline; + + int yydebug; + + YYSTYPE yylval; + + int ival; + char* dval; + char* sval; + int in_data = 0; /* set if processing DATA statement */ + + char* formatstring; /* formatstring used for printing */ + Symbol* s; /* Symbol dummy */ + + #include "yylexp.h" + #include "basic.lex" } %lexical yylexp; - -%start LLparse,programline ; +%start LLparse, programline; programline - : INTVALUE - { basicline = ival;newblock(ival); newemblock(ival); } - stmts EOLN - | '#' INTVALUE STRVALUE EOLN - | EOLN - ; - - -stmts : singlestmt - [ %while ( LLsymb == ':' ) ':' singlestmt ]* - ; - -singlestmt { int d2 ; } - : callstmt - | clearstmt - | CLOSESYM closestmt - | datastmt - | defstmt - | defvarstmt - | dimstmt - | ERRORSYM expression(&d2) { errorstmt(d2); } - | fieldstmt - | forstmt - | getstmt - | gosubstmt - | onstmt - | ifstmt - | illegalstmt - | inputstmt - | letstmt - | lineinputstmt - | lsetstmt - | midstmt - | NEXTSYM nextstmt - | GOTOSYM INTVALUE { gotostmt(ival); } - | openstmt - | optionstmt - | pokestmt - | printstmt - | randomizestmt - | readstmt - | REMSYM - | restorestmt - | returnstmt - | ENDSYM { C_loc((arith) 0 ); - C_cal("_hlt"); - C_asp((arith) BEMINTSIZE); - } - | STOPSYM { C_cal("_stop"); } - | swapstmt - | TRONOFFSYM { tronoff=yylval.integer; } - | whilestmt - | wendstmt - | writestmt - | /* EMPTY STATEMENT */ - ; - -illegalstmt: ILLEGAL { illegalcmd(); } - ; - -callstmt { Symbol *id; int i; } - : CALLSYM - IDENTIFIER { id = yylval.Sptr; } - [ parmlist(&i) - { C_cal(id->symname); - C_asp((arith) (i*BEMPTRSIZE)); - } - | /* empty */ - { C_cal(id->symname); } - ] - ; - -parmlist(int *ip;) { int var ; } - : '(' - variable(&var) { *ip = 1; } - [ ',' variable(&var) { *ip = *ip + 1; } ]* - ')' - ; - - -clearstmt { int exp; } - : CLEARSYM [ ',' expression(&exp) ]*2 - { warning("statement ignored"); } - ; - -closestmt: filelist - | /* empty */ { C_cal("_closeall"); } - ; - -filelist { int intv; } - : cross - intvalue(&intv) - { C_loc((arith) ival); - C_cal("_clochn"); - C_asp((arith) BEMINTSIZE); - } - [ ',' - cross - intvalue(&intv) - { C_loc((arith) ival); - C_cal("_clochn"); - C_asp((arith) BEMINTSIZE); - } - ]* ; - -datastmt: DATASYM { datastmt(); in_data = 1;} - datalist { datprintf("\n"); in_data = 0; } - ; - -dataelm : INTVALUE { datprintf("%d",ival); } - | '-' [ INTVALUE { datprintf("%d",-ival); } - | FLTVALUE { datprintf("-%s",dval); } - ] - | FLTVALUE { datprintf("%s",dval); } - | STRVALUE { datprintf("\"%s\"",sval); } - | IDENTIFIER { datprintf("\"%s\"",sval); } - ; - -datalist: dataelm - [ ',' { datprintf(","); } - dataelm ]* - ; - -defstmt : DEFSYM - [ deffnstmt - | defusrstmt - ] - ; - -deffnstmt { int exp; } - : heading '=' expression(&exp) - { endscope(exp); } - ; - -heading : FUNCTID { newscope(yylval.Sptr); } - [ '(' idlist ')' ]? { heading(); } - ; - -idlist : IDENTIFIER { dclparm(yylval.Sptr); } - [ ',' IDENTIFIER { dclparm(yylval.Sptr); } - ]* - ; - -defvarstmt: DEFINTSYM { setdefaulttype( INTTYPE); } - | DEFSNGSYM { setdefaulttype( FLOATTYPE); } - | DEFDBLSYM { setdefaulttype( DOUBLETYPE); } - | DEFSTRSYM { setdefaulttype( STRINGTYPE); } - ; - -defusrstmt: USRSYM ':' { illegalcmd(); } - ; - -dimstmt { Symbol *symp; } - : DIMSYM arraydcl(&symp) ')' { dclarray(symp); } - [ ',' arraydcl(&symp) ')' { dclarray(symp); } - ]* - ; - -arraydcl(Symbol **sympp;) - : IDENTIFIER { *sympp = s = yylval.Sptr; } - '(' - INTVALUE - { - s->dimlimit[s->dimensions]=ival; - s->dimensions++; - } - [ ',' - INTVALUE - { - if(s->dimensionsdimlimit[s->dimensions]=ival; - s->dimensions++; - } else error("too many dimensions"); - } - ]* ; - -fieldstmt { int intv; } - : FIELDSYM cross intvalue(&intv) - { setchannel(ival); } - ',' fieldlist { notyetimpl(); } - ; - -fieldlist { int intv; int var; } - : intvalue(&intv) ASSYM variable(&var) - [ ',' intvalue(&intv) ASSYM variable(&var) ]* - ; - -forstmt { int exp; } - : FORSYM IDENTIFIER { forinit(yylval.Sptr); } - '=' expression(&exp) { forexpr(exp); } - TOSYM expression(&exp) { forlimit(exp); } - step - ; - -step { int exp; } - : STEPSYM expression(&exp) { forstep(exp); } - | /*EMPTY*/ { - C_loc((arith) 1); - forstep(INTTYPE); - } - ; - -nextstmt: [ IDENTIFIER { nextstmt(yylval.Sptr); } - | /* empty */ { nextstmt((Symbol *)0); } - ] - [ ',' IDENTIFIER { nextstmt(yylval.Sptr); } - ]* - ; - -getstmt { char *cp; int intv; } - : getput(&cp) - [ /* empty */ - { C_loc((arith) 0); - C_cal(cp); - C_asp((arith) BEMINTSIZE); - } - | ',' intvalue(&intv) - { C_loc((arith) ival); - C_cal(cp); - C_asp((arith) BEMINTSIZE); - } - ] - ; - -getput(char **cpp;) { int intv; } - : GETSYM cross intvalue(&intv) - { setchannel(ival); - *cpp = "$_getrec"; - } - | PUTSYM cross intvalue(&intv) - { setchannel(ival); - *cpp = "$_putsym"; - } - ; - -gosubstmt: GOSUBSYM INTVALUE { gosubstmt(ival); } - ; - -returnstmt: RETURNSYM { returnstmt(); } - ; - -ifstmt { int exp; int d1; } - : IFSYM expression(&exp) { d1=ifstmt(exp); } - thenpart { d1=thenpart(d1); } - elsepart { elsepart(d1); } - ; - -thenpart: THENSYM [ INTVALUE { gotostmt(ival); } - | stmts - ] - | GOTOSYM INTVALUE { gotostmt(ival); } - ; - -elsepart: %prefer ELSESYM - [ INTVALUE { gotostmt(ival); } - | stmts - ] - | /* empty */ - ; - -inputstmt { int intv; } - : INPUTSYM [ semiprompt readlist - | '#' intvalue(&intv) - { setchannel(ival); } - ',' readlist - ] - ; - -semiprompt { int str; } - : semi STRVALUE { str = yylval.integer; } - [ ';' { loadstr(str); - prompt(1); - } - | ',' { loadstr(str); - prompt(0); - } - ] - | /*EMPTY*/ - { setchannel(-1); - C_cal("_qstmark"); - } - ; - -semi : ';' - | /* empty */ - ; - -letstmt { int var; int exp; } - : LETSYM - variable(&var) { save_address(); } - '=' expression(&exp) { assign(var,exp); } - | - variable(&var) { save_address(); } - '=' expression(&exp) { assign(var,exp); } - ; - -lineinputstmt { int var; int intv; } - : LINESYM - [ INPUTSYM - semiprompt { setchannel(-1); } - variable(&var) { linestmt(var); } - | '#' - intvalue(&intv) { setchannel(ival); } - ',' - variable(&var) { linestmt(var); } - ] - ; - -readlist: readelm - [ ',' readelm ]* - ; - -readelm { int var; } - : variable(&var) { readelm(var); } - ; - -lsetstmt { int var; int exp; } - : LSETSYM variable(&var) '=' expression(&exp) - { notyetimpl(); } - ; - -midstmt { int exp; } - : MIDSYM '$' midparms '=' expression(&exp) - { C_cal("_midstmt"); - C_asp((arith) (2*BEMINTSIZE + 2*BEMPTRSIZE)); - } - ; - -midparms: '(' midfirst midsec midthird ')' - ; - -midfirst { int exp; } - : expression(&exp) { conversion(exp,STRINGTYPE); } - ; - -midsec { int exp; } - : ',' expression(&exp) { conversion(exp,INTTYPE); } - ; - -midthird { int exp; } - : ',' expression(&exp) { conversion(exp,INTTYPE); } - | /* empty */ { C_loc((arith) -1); } - ; - -onstmt : ONSYM - [ exceptionstmt - | ongotostmt - ] - ; - -exceptionstmt: ERRORSYM GOTOSYM INTVALUE { exceptstmt(ival); } - ; - -ongotostmt { int exp; } - : expression(&exp) - [ GOSUBSYM constantlist { ongosubstmt(exp); } - | GOTOSYM constantlist { ongotostmt(exp); } - ] - ; - -constantlist: INTVALUE { jumpelm(ival); } - [ ',' INTVALUE { jumpelm(ival); } - ]* - ; - -openstmt { int exp; } - : OPENSYM mode openchannel expression(&exp) - { conversion(exp,STRINGTYPE); } - [ /* empty */ { openstmt(0); } - | INTVALUE { openstmt(ival); } - ] - ; - -openchannel: cross INTVALUE ',' { setchannel(ival); } - ; - -mode { int exp; } - : expression(&exp) ',' { conversion(exp,STRINGTYPE); } - | ',' { C_lae_dnam("_iomode",(arith)0); } - ; - -optionstmt { int intv; } - : OPTIONSYM BASESYM intvalue(&intv) { optionbase(ival); } - ; - -printstmt { int plist; } - : PRINTSYM - [ /* empty */ { setchannel(-1); - C_cal("_nl"); - } - | file format printlist(&plist) - { if(plist) - C_cal("_nl"); - } - ] - ; - -file { int intv; } - : '#' intvalue(&intv) ',' { setchannel(ival); } - | /* empty */ { setchannel(-1); } - ; - -format { int var ; } - : USINGSYM - [ STRVALUE { loadstr(yylval.integer); } ';' - | variable(&var) ';' - { if(var!=STRINGTYPE) - error("string variable expected"); - } - ] - | /* empty */ { formatstring=0; } - ; - -printlist(int *ip;) { int exp; } - : [ expression(&exp) { printstmt(exp); *ip=1; } - | ',' { zone(1); *ip=0; } - | ';' { zone(0); *ip=0; } - ]+ - ; - -pokestmt { int exp1; int exp2 ; } - : POKESYM - expression(&exp1) - ',' - expression(&exp2) { pokestmt(exp1,exp2); } - ; - -randomizestmt { int exp; } - : RANDOMIZESYM - [ /* empty */ { C_cal("_randomi"); } - | expression(&exp) - { conversion(exp,INTTYPE); - C_cal("_setrand"); - C_asp((arith) BEMINTSIZE); - } - ] - ; - -readstmt { int var; } - : READSYM { setchannel(0); } - variable(&var) { readelm(var); } - [ ',' variable(&var) { readelm(var); } - ]* - ; - -restorestmt : RESTORESYM - [ INTVALUE { restore(ival); } - | /* empty */ { restore(0); } - ] - ; - -swapstmt { int var1; int var2; } - : SWAPSYM - variable(&var1) - ',' - variable(&var2) { swapstmt(var1,var2); } - ; - -whilestmt { int exp; } - : WHILESYM { whilestart(); } - expression(&exp) { whiletst(exp); } - ; - -wendstmt : WENDSYM { wend(); } - ; - -writestmt: WRITESYM - [ /* empty */ { setchannel(-1); - C_cal("_wrnl"); - } - | file writelist { C_cal("_wrnl"); } - ] - ; - -writelist { int exp; } - : expression(&exp) { writestmt(exp,0); } - [ ',' expression(&exp) { writestmt(exp,1); } - ]* - ; - -cross: '#' | /* empty */ ; - -intvalue(int *ip;) - : INTVALUE { *ip = yylval.integer; } - ; - -variable(int *ip;) { Symbol *symp; int exp; } - : identifier(&symp) - [ %avoid /* empty */ { *ip = loadaddr(symp); } - | '(' { newarrayload(symp); } - expression(&exp) { loadarray(exp); } - [ ',' expression(&exp) { loadarray(exp); } ]* - ')' { *ip = endarrayload(); } - ] - | ERRSYM { C_lae_dnam("_errsym",(arith) 0); - *ip = INTTYPE; - } - | ERLSYM { C_lae_dnam("_erlsym",(arith) 0); - *ip = INTTYPE; - } - ; - -expression(int *ip;) { int neg; } /* NIEUW */ - : expression1(&neg) { *ip = neg; } - [ - IMPSYM - expression(&neg) { *ip = boolop(*ip,neg,IMPSYM); } - ]? - ; - - -expression1(int *ip;) { int neg; } - : expression2(&neg) { *ip = neg; } - [ EQVSYM - expression2(&neg) { *ip = boolop(*ip,neg,EQVSYM); } - ]* - ; - -expression2(int *ip;) { int neg; } - : expression3(&neg) { *ip = neg; } - [ XORSYM - expression3(&neg) { *ip = boolop(*ip,neg,XORSYM); } - ]* - ; - -expression3(int *ip;) { int neg; } - : expression4(&neg) { *ip = neg; } - [ ORSYM - expression4(&neg) { *ip = boolop(*ip,neg,ORSYM); } - ]* - ; - -expression4(int *ip;) { int neg; } - : negation(&neg) { *ip = neg; } - [ ANDSYM - negation(&neg) { *ip = boolop(*ip,neg,ANDSYM); } - ]* - ; - -negation(int *ip;) { int comp; } - : NOTSYM compare(&comp) { *ip=boolop(comp,0,NOTSYM); } - | compare(ip) - ; - -compare(int *ip;) { int sum1,sum2,rel; } - : sum(&sum1) - [ /* empty */ { *ip = sum1; } - | RELOP { rel=yylval.integer; } - sum(&sum2) { *ip=relop(sum1,sum2,rel); } - | '=' sum(&sum2) { *ip=relop(sum1,sum2,'='); } - ] - ; - -sum(int *ip;) { int term1; } - : term(&term1) { *ip = term1; } - [ %while(1) - '-' term(&term1) { *ip=plusmin(*ip,term1,'-'); } - | '+' term(&term1) { *ip=plusmin(*ip,term1,'+'); } - ]* - ; - -term(int *ip;) { int fac1; } - : factor(&fac1) { *ip = fac1; } - [ '*' factor(&fac1) { *ip=muldiv(*ip,fac1,'*'); } - | '\\' factor(&fac1) { *ip=muldiv(*ip,fac1,'\\'); } - | '/' factor(&fac1) { *ip=muldiv(*ip,fac1,'/'); } - | MODSYM factor(&fac1) { *ip=muldiv(*ip,fac1,MODSYM); } - ]* - ; - -factor(int *ip;) - : '-' factor(ip) { *ip=negate(*ip); } - | factor1(ip) - ; - -factor1(int *ip;) { int mant,exp; } - : factor2(&mant) - [ /* empty */ { *ip = mant; } - | '^' factor1(&exp) { *ip = power(mant,exp); } - ] - ; - -factor2(int *ip;) - { int var,func,expl,funcc,exp,intv,funcn,inpt; int typetable[10]; } - : INTVALUE { *ip=loadint(ival); } - | '(' expression(&exp) ')' { *ip=exp; } - | FLTVALUE { *ip=loaddbl(dval); } - | STRVALUE - { *ip= STRINGTYPE; - loadstr(yylval.integer); - } - | variable(&var) - { *ip=var; - loadvar(var); - } - | INKEYSYM '$' { C_cal("_inkey"); - C_lfr((arith) BEMPTRSIZE); - *ip= STRINGTYPE; - } - | VARPTR '(' '#' intvalue(&intv) ')' - { warning("Not supported"); - *ip=INTTYPE; - } - | FUNCTION { func=yylval.integer; } - [ %avoid /* empty */ { *ip= callfcn(yylval.integer,0, typetable); } - | '(' cross exprlist(&expl, typetable) ')' - { *ip=callfcn(func,expl, typetable); } - ] - | funcname(&funcn) - [ %avoid /* empty */ { *ip=fcnend(0); } - | funccall(&funcc) ')' { *ip=fcnend(funcc); } - ] - | MIDSYM '$' midparms - { - C_cal("_mid"); - C_asp((arith) (2*BEMINTSIZE+BEMPTRSIZE)); - C_lfr((arith) BEMPTRSIZE); - *ip= STRINGTYPE; - } - | INPUTSYM '$' '(' expression(&exp) inputtail(&inpt) - { /*waar worden inpt en exp gebruikt?*/ - C_cal("_inpfcn"); - C_asp((arith) (2*BEMINTSIZE+BEMPTRSIZE)); - *ip= STRINGTYPE; - } - ; - -inputtail(int *ip;) { int exp; } - : ',' cross expression(&exp) ')' - { conversion(exp,INTTYPE); - *ip= INTTYPE; - } - | ')' - { C_loc((arith) -1); - *ip= INTTYPE; - } - ; - -funcname(int *ip;) - : FUNCTID { *ip=fcncall(yylval.Sptr); } - ; - -funccall(int *ip;) { int exp; } - : '(' expression(&exp) { callparm(0,exp);*ip=1; } - [ ',' expression(&exp) { callparm(*ip,exp); - *ip = *ip+1; - } - ]* - ; - -identifier(Symbol **ident;) - : IDENTIFIER { dcltype(yylval.Sptr); - *ident=yylval.Sptr; - } - ; - -exprlist(int *ip; int *typetable;) { int exp; } - : expression(&exp) { typetable[0]=exp; - *ip=1; - } - [ ',' expression(&exp) { typetable[*ip]=exp; - *ip = *ip+1; - } - ]* - ; + : INTVALUE + { + basicline = ival; + newblock(ival); + newemblock(ival); + } + stmts EOLN + | '#' INTVALUE STRVALUE EOLN + | EOLN + ; + +stmts + : singlestmt + [ + %while (LLsymb == ':') + ':' singlestmt + ]* + ; + +singlestmt + { + int d2; + } + : callstmt + | clearstmt + | CLOSESYM closestmt + | datastmt + | defstmt + | defvarstmt + | dimstmt + | ERRORSYM + expression(&d2) + { errorstmt(d2); } + | fieldstmt + | forstmt + | getstmt + | gosubstmt + | onstmt + | ifstmt + | illegalstmt + | inputstmt + | letstmt + | lineinputstmt + | lsetstmt + | midstmt + | NEXTSYM nextstmt + | GOTOSYM INTVALUE + { gotostmt(ival); } + | openstmt + | optionstmt + | pokestmt + | printstmt + | randomizestmt + | readstmt + | REMSYM + | restorestmt + | returnstmt + | ENDSYM + { + C_loc((arith)0); + C_cal("_hlt"); + C_asp((arith)BEMINTSIZE); + } + | STOPSYM + { C_cal("_stop"); } + | swapstmt + | TRONOFFSYM + { tronoff = yylval.integer; } + | whilestmt + | wendstmt + | writestmt + | + /* EMPTY STATEMENT */ + ; + +illegalstmt + : ILLEGAL + { illegalcmd(); } + ; + +callstmt + { + Symbol* id; + int i; + } + : CALLSYM IDENTIFIER + { id = yylval.Sptr; } + [ + parmlist(&i) + { + C_cal(id->symname); + C_asp((arith)(i * BEMPTRSIZE)); + } + | + /* empty */ + { C_cal(id->symname); } + ] + ; + +parmlist(int* ip;) + { + int var; + } + : '(' + variable(&var) + { *ip = 1; } + [ + ',' + variable(&var) + { *ip = *ip + 1; } + ]* + ')' + ; + +clearstmt + { + int exp; + } + : CLEARSYM + [ + ',' + expression(&exp) + ]*2 + { warning("statement ignored"); } + ; + +closestmt + : filelist + | + /* empty */ + { C_cal("_closeall"); } + ; + +filelist + { + int intv; + } + : cross + intvalue(&intv) + { + C_loc((arith)ival); + C_cal("_clochn"); + C_asp((arith)BEMINTSIZE); + } + [ + ',' cross + intvalue(&intv) + { + C_loc((arith)ival); + C_cal("_clochn"); + C_asp((arith)BEMINTSIZE); + } + ]* + ; + +datastmt + : DATASYM + { + datastmt(); + in_data = 1; + } + datalist + { + datprintf("\n"); + in_data = 0; + } + ; + +dataelm + : INTVALUE + { datprintf("%d", ival); } + | '-' + [ + INTVALUE + { datprintf("%d", -ival); } + | FLTVALUE + { datprintf("-%s", dval); } + ] + | FLTVALUE + { datprintf("%s", dval); } + | STRVALUE + { datprintf("\"%s\"", sval); } + | IDENTIFIER + { datprintf("\"%s\"", sval); } + ; + +datalist + : dataelm + [ + ',' + { datprintf(","); } + dataelm + ]* + ; + +defstmt + : DEFSYM + [ + deffnstmt + | defusrstmt + ] + ; + +deffnstmt + { + int exp; + } + : heading '=' + expression(&exp) + { endscope(exp); } + ; + +heading + : FUNCTID + { newscope(yylval.Sptr); } + [ + '(' idlist ')' + ]? + { heading(); } + ; + +idlist + : IDENTIFIER + { dclparm(yylval.Sptr); } + [ + ',' IDENTIFIER + { dclparm(yylval.Sptr); } + ]* + ; + +defvarstmt + : DEFINTSYM + { setdefaulttype(INTTYPE); } + | DEFSNGSYM + { setdefaulttype(FLOATTYPE); } + | DEFDBLSYM + { setdefaulttype(DOUBLETYPE); } + | DEFSTRSYM + { setdefaulttype(STRINGTYPE); } + ; + +defusrstmt + : USRSYM ':' + { illegalcmd(); } + ; + +dimstmt + { + Symbol* symp; + } + : DIMSYM + arraydcl(&symp) + ')' + { dclarray(symp); } + [ + ',' + arraydcl(&symp) + ')' + { dclarray(symp); } + ]* + ; + +arraydcl(Symbol** sympp;) + : IDENTIFIER + { *sympp = s = yylval.Sptr; } + '(' INTVALUE + { + s->dimlimit[s->dimensions] = ival; + s->dimensions++; + } + [ + ',' INTVALUE + { + if (s->dimensions < MAXDIMENSIONS) + { + s->dimlimit[s->dimensions] = ival; + s->dimensions++; + } + else + error("too many dimensions"); + } + ]* + ; + +fieldstmt + { + int intv; + } + : FIELDSYM cross + intvalue(&intv) + { setchannel(ival); } + ',' fieldlist + { notyetimpl(); } + ; + +fieldlist + { + int intv; + int var; + } + : intvalue(&intv) + ASSYM + variable(&var) + [ + ',' + intvalue(&intv) + ASSYM + variable(&var) + ]* + ; + +forstmt + { + int exp; + } + : FORSYM IDENTIFIER + { forinit(yylval.Sptr); } + '=' + expression(&exp) + { forexpr(exp); } + TOSYM + expression(&exp) + { forlimit(exp); } + step + ; + +step + { + int exp; + } + : STEPSYM + expression(&exp) + { forstep(exp); } + | + /*EMPTY*/ + { + C_loc((arith)1); + forstep(INTTYPE); + } + ; + +nextstmt + : [ + IDENTIFIER + { nextstmt(yylval.Sptr); } + | + /* empty */ + { nextstmt((Symbol*)0); } + ] + [ + ',' IDENTIFIER + { nextstmt(yylval.Sptr); } + ]* + ; + +getstmt + { + char* cp; + int intv; + } + : getput(&cp) + [ + /* empty */ + { + C_loc((arith)0); + C_cal(cp); + C_asp((arith)BEMINTSIZE); + } + | ',' + intvalue(&intv) + { + C_loc((arith)ival); + C_cal(cp); + C_asp((arith)BEMINTSIZE); + } + ] + ; + +getput(char** cpp;) + { + int intv; + } + : GETSYM cross + intvalue(&intv) + { + setchannel(ival); + *cpp = "$_getrec"; + } + | PUTSYM cross + intvalue(&intv) + { + setchannel(ival); + *cpp = "$_putsym"; + } + ; + +gosubstmt + : GOSUBSYM INTVALUE + { gosubstmt(ival); } + ; + +returnstmt + : RETURNSYM + { returnstmt(); } + ; + +ifstmt + { + int exp; + int d1; + } + : IFSYM + expression(&exp) + { d1 = ifstmt(exp); } + thenpart + { d1 = thenpart(d1); } + elsepart + { elsepart(d1); } + ; + +thenpart + : THENSYM + [ + INTVALUE + { gotostmt(ival); } + | stmts + ] + | GOTOSYM INTVALUE + { gotostmt(ival); } + ; + +elsepart + : %prefer + ELSESYM + [ + INTVALUE + { gotostmt(ival); } + | stmts + ] + | + /* empty */ + ; + +inputstmt + { + int intv; + } + : INPUTSYM + [ + semiprompt readlist + | '#' + intvalue(&intv) + { setchannel(ival); } + ',' readlist + ] + ; + +semiprompt + { + int str; + } + : semi STRVALUE + { str = yylval.integer; } + [ + ';' + { + loadstr(str); + prompt(1); + } + | ',' + { + loadstr(str); + prompt(0); + } + ] + | + /*EMPTY*/ + { + setchannel(-1); + C_cal("_qstmark"); + } + ; + +semi + : ';' + | + /* empty */ + ; + +letstmt + { + int var; + int exp; + } + : LETSYM + variable(&var) + { save_address(); } + '=' + expression(&exp) + { assign(var, exp); } + | variable(&var) + { save_address(); } + '=' + expression(&exp) + { assign(var, exp); } + ; + +lineinputstmt + { + int var; + int intv; + } + : LINESYM + [ + INPUTSYM semiprompt + { setchannel(-1); } + variable(&var) + { linestmt(var); } + | '#' + intvalue(&intv) + { setchannel(ival); } + ',' + variable(&var) + { linestmt(var); } + ] + ; + +readlist + : readelm + [ + ',' readelm + ]* + ; + +readelm + { + int var; + } + : variable(&var) + { readelm(var); } + ; + +lsetstmt + { + int var; + int exp; + } + : LSETSYM + variable(&var) + '=' + expression(&exp) + { notyetimpl(); } + ; + +midstmt + { + int exp; + } + : MIDSYM '$' midparms '=' + expression(&exp) + { + C_cal("_midstmt"); + C_asp((arith)(2 * BEMINTSIZE + 2 * BEMPTRSIZE)); + } + ; + +midparms + : '(' midfirst midsec midthird ')' + ; + +midfirst + { + int exp; + } + : expression(&exp) + { conversion(exp, STRINGTYPE); } + ; + +midsec + { + int exp; + } + : ',' + expression(&exp) + { conversion(exp, INTTYPE); } + ; + +midthird + { + int exp; + } + : ',' + expression(&exp) + { conversion(exp, INTTYPE); } + | + /* empty */ + { C_loc((arith)-1); } + ; + +onstmt + : ONSYM + [ + exceptionstmt + | ongotostmt + ] + ; + +exceptionstmt + : ERRORSYM GOTOSYM INTVALUE + { exceptstmt(ival); } + ; + +ongotostmt + { + int exp; + } + : expression(&exp) + [ + GOSUBSYM constantlist + { ongosubstmt(exp); } + | GOTOSYM constantlist + { ongotostmt(exp); } + ] + ; + +constantlist + : INTVALUE + { jumpelm(ival); } + [ + ',' INTVALUE + { jumpelm(ival); } + ]* + ; + +openstmt + { + int exp; + } + : OPENSYM mode openchannel + expression(&exp) + { conversion(exp, STRINGTYPE); } + [ + /* empty */ + { openstmt(0); } + | INTVALUE + { openstmt(ival); } + ] + ; + +openchannel + : cross INTVALUE ',' + { setchannel(ival); } + ; + +mode + { + int exp; + } + : expression(&exp) + ',' + { conversion(exp, STRINGTYPE); } + | ',' + { C_lae_dnam("_iomode", (arith)0); } + ; + +optionstmt + { + int intv; + } + : OPTIONSYM BASESYM + intvalue(&intv) + { optionbase(ival); } + ; + +printstmt + { + int plist; + } + : PRINTSYM + [ + /* empty */ + { + setchannel(-1); + C_cal("_nl"); + } + | file format + printlist(&plist) + { if (plist) C_cal("_nl"); } + ] + ; + +file + { + int intv; + } + : '#' + intvalue(&intv) + ',' + { setchannel(ival); } + | + /* empty */ + { setchannel(-1); } + ; + +format + { + int var; + } + : USINGSYM + [ + STRVALUE + { loadstr(yylval.integer); } + ';' + | variable(&var) + ';' + { if (var != STRINGTYPE) error("string variable expected"); } + ] + | + /* empty */ + { formatstring = 0; } + ; + +printlist(int* ip;) + { + int exp; + } + : [ + expression(&exp) + { + printstmt(exp); + *ip = 1; + } + | ',' + { + zone(1); + *ip = 0; + } + | ';' + { + zone(0); + *ip = 0; + } + ]+ + ; + +pokestmt + { + int exp1; + int exp2; + } + : POKESYM + expression(&exp1) + ',' + expression(&exp2) + { pokestmt(exp1, exp2); } + ; + +randomizestmt + { + int exp; + } + : RANDOMIZESYM + [ + /* empty */ + { C_cal("_randomi"); } + | expression(&exp) + { + conversion(exp, INTTYPE); + C_cal("_setrand"); + C_asp((arith)BEMINTSIZE); + } + ] + ; + +readstmt + { + int var; + } + : READSYM + { setchannel(0); } + variable(&var) + { readelm(var); } + [ + ',' + variable(&var) + { readelm(var); } + ]* + ; + +restorestmt + : RESTORESYM + [ + INTVALUE + { restore(ival); } + | + /* empty */ + { restore(0); } + ] + ; + +swapstmt + { + int var1; + int var2; + } + : SWAPSYM + variable(&var1) + ',' + variable(&var2) + { swapstmt(var1, var2); } + ; + +whilestmt + { + int exp; + } + : WHILESYM + { whilestart(); } + expression(&exp) + { whiletst(exp); } + ; + +wendstmt + : WENDSYM + { wend(); } + ; + +writestmt + : WRITESYM + [ + /* empty */ + { + setchannel(-1); + C_cal("_wrnl"); + } + | file writelist + { C_cal("_wrnl"); } + ] + ; + +writelist + { + int exp; + } + : expression(&exp) + { writestmt(exp, 0); } + [ + ',' + expression(&exp) + { writestmt(exp, 1); } + ]* + ; + +cross + : '#' + | + /* empty */ + ; + +intvalue(int* ip;) + : INTVALUE + { *ip = yylval.integer; } + ; + +variable(int* ip;) + { + Symbol* symp; + int exp; + } + : identifier(&symp) + [ + %avoid + /* empty */ + { *ip = loadaddr(symp); } + | '(' + { newarrayload(symp); } + expression(&exp) + { loadarray(exp); } + [ + ',' + expression(&exp) + { loadarray(exp); } + ]* + ')' + { *ip = endarrayload(); } + ] + | ERRSYM + { + C_lae_dnam("_errsym", (arith)0); + *ip = INTTYPE; + } + | ERLSYM + { + C_lae_dnam("_erlsym", (arith)0); + *ip = INTTYPE; + } + ; + +expression(int* ip;) + { + int neg; + } + /* NIEUW */ + : expression1(&neg) + { *ip = neg; } + [ + IMPSYM + expression(&neg) + { *ip = boolop(*ip, neg, IMPSYM); } + ]? + ; + +expression1(int* ip;) + { + int neg; + } + : expression2(&neg) + { *ip = neg; } + [ + EQVSYM + expression2(&neg) + { *ip = boolop(*ip, neg, EQVSYM); } + ]* + ; + +expression2(int* ip;) + { + int neg; + } + : expression3(&neg) + { *ip = neg; } + [ + XORSYM + expression3(&neg) + { *ip = boolop(*ip, neg, XORSYM); } + ]* + ; + +expression3(int* ip;) + { + int neg; + } + : expression4(&neg) + { *ip = neg; } + [ + ORSYM + expression4(&neg) + { *ip = boolop(*ip, neg, ORSYM); } + ]* + ; + +expression4(int* ip;) + { + int neg; + } + : negation(&neg) + { *ip = neg; } + [ + ANDSYM + negation(&neg) + { *ip = boolop(*ip, neg, ANDSYM); } + ]* + ; + +negation(int* ip;) + { + int comp; + } + : NOTSYM + compare(&comp) + { *ip = boolop(comp, 0, NOTSYM); } + | compare(ip) + ; + +compare(int* ip;) + { + int sum1, sum2, rel; + } + : sum(&sum1) + [ + /* empty */ + { *ip = sum1; } + | RELOP + { rel = yylval.integer; } + sum(&sum2) + { *ip = relop(sum1, sum2, rel); } + | '=' + sum(&sum2) + { *ip = relop(sum1, sum2, '='); } + ] + ; + +sum(int* ip;) + { + int term1; + } + : term(&term1) + { *ip = term1; } + [ + %while (1) + '-' + term(&term1) + { *ip = plusmin(*ip, term1, '-'); } + | '+' + term(&term1) + { *ip = plusmin(*ip, term1, '+'); } + ]* + ; + +term(int* ip;) + { + int fac1; + } + : factor(&fac1) + { *ip = fac1; } + [ + '*' + factor(&fac1) + { *ip = muldiv(*ip, fac1, '*'); } + | '\\' + factor(&fac1) + { *ip = muldiv(*ip, fac1, '\\'); } + | '/' + factor(&fac1) + { *ip = muldiv(*ip, fac1, '/'); } + | MODSYM + factor(&fac1) + { *ip = muldiv(*ip, fac1, MODSYM); } + ]* + ; + +factor(int* ip;) + : '-' + factor(ip) + { *ip = negate(*ip); } + | factor1(ip) + ; + +factor1(int* ip;) + { + int mant, exp; + } + : factor2(&mant) + [ + /* empty */ + { *ip = mant; } + | '^' + factor1(&exp) + { *ip = power(mant, exp); } + ] + ; + +factor2(int* ip;) + { + int var, func, expl, funcc, exp, intv, funcn, inpt; + int typetable[10]; + } + : INTVALUE + { *ip = loadint(ival); } + | '(' + expression(&exp) + ')' + { *ip = exp; } + | FLTVALUE + { *ip = loaddbl(dval); } + | STRVALUE + { + *ip = STRINGTYPE; + loadstr(yylval.integer); + } + | variable(&var) + { + *ip = var; + loadvar(var); + } + | INKEYSYM '$' + { + C_cal("_inkey"); + C_lfr((arith)BEMPTRSIZE); + *ip = STRINGTYPE; + } + | VARPTR '(' '#' + intvalue(&intv) + ')' + { + warning("Not supported"); + *ip = INTTYPE; + } + | FUNCTION + { func = yylval.integer; } + [ + %avoid + /* empty */ + { *ip = callfcn(yylval.integer, 0, typetable); } + | '(' cross + exprlist(&expl, typetable) + ')' + { *ip = callfcn(func, expl, typetable); } + ] + | funcname(&funcn) + [ + %avoid + /* empty */ + { *ip = fcnend(0); } + | funccall(&funcc) + ')' + { *ip = fcnend(funcc); } + ] + | MIDSYM '$' midparms + { + C_cal("_mid"); + C_asp((arith)(2 * BEMINTSIZE + BEMPTRSIZE)); + C_lfr((arith)BEMPTRSIZE); + *ip = STRINGTYPE; + } + | INPUTSYM '$' '(' + expression(&exp) + inputtail(&inpt) + { + /*waar worden inpt en exp gebruikt?*/ + C_cal("_inpfcn"); + C_asp((arith)(2 * BEMINTSIZE + BEMPTRSIZE)); + *ip = STRINGTYPE; + } + ; + +inputtail(int* ip;) + { + int exp; + } + : ',' cross + expression(&exp) + ')' + { + conversion(exp, INTTYPE); + *ip = INTTYPE; + } + | ')' + { + C_loc((arith)-1); + *ip = INTTYPE; + } + ; + +funcname(int* ip;) + : FUNCTID + { *ip = fcncall(yylval.Sptr); } + ; + +funccall(int* ip;) + { + int exp; + } + : '(' + expression(&exp) + { + callparm(0, exp); + *ip = 1; + } + [ + ',' + expression(&exp) + { + callparm(*ip, exp); + *ip = *ip + 1; + } + ]* + ; + +identifier(Symbol** ident;) + : IDENTIFIER + { + dcltype(yylval.Sptr); + *ident = yylval.Sptr; + } + ; + +exprlist(int* ip; int* typetable;) + { + int exp; + } + : expression(&exp) + { + typetable[0] = exp; + *ip = 1; + } + [ + ',' + expression(&exp) + { + typetable[*ip] = exp; + *ip = *ip + 1; + } + ]* + ; { -#ifndef NORCSID -static char rcs_id[] = "$Id$" ; -#endif + #ifndef NORCSID + static char rcs_id[] = "$Id$"; + #endif } diff --git a/lang/cem/cemcom.ansi/declar.g b/lang/cem/cemcom.ansi/declar.g index f75fa7c08..e6de398ab 100644 --- a/lang/cem/cemcom.ansi/declar.g +++ b/lang/cem/cemcom.ansi/declar.g @@ -2,773 +2,827 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cemcom.ansi/declar.g + */ /* $Id$ */ /* DECLARATION SYNTAX PARSER */ { -#include "parameters.h" -#include -#include -#include -#include -#include "idf.h" -#include "arith.h" -#include "LLlex.h" -#include "label.h" -#include "code.h" -#include "type.h" -#include "proto.h" -#include "struct.h" -#include "field.h" -#include "decspecs.h" -#include "declarator.h" -#include "def.h" -#include "declar.h" -#include "label.h" -#include "expr.h" -#include "sizes.h" -#include "level.h" -#include "error.h" -#include "stab.h" - -#ifdef LINT -#include "l_lint.h" -#endif /* LINT */ - -extern char options[]; + #include "parameters.h" + #include + #include + #include + #include + #include "idf.h" + #include "arith.h" + #include "LLlex.h" + #include "label.h" + #include "code.h" + #include "type.h" + #include "proto.h" + #include "struct.h" + #include "field.h" + #include "decspecs.h" + #include "declarator.h" + #include "def.h" + #include "declar.h" + #include "label.h" + #include "expr.h" + #include "sizes.h" + #include "level.h" + #include "error.h" + #include "stab.h" + + #ifdef LINT + #include "l_lint.h" + #endif /* LINT */ + + extern char options[]; } /* 3.5 */ declaration - {struct decspecs Ds;} -: - {Ds = null_decspecs;} - decl_specifiers(&Ds) - init_declarator_list(&Ds)? - ';' -; + { + struct decspecs Ds; + } + : + { Ds = null_decspecs; } + decl_specifiers(&Ds) + init_declarator_list(&Ds)? + ';' + ; /* A `decl_specifiers' describes a sequence of a storage_class_specifier, - an unsigned_specifier, a size_specifier and a simple type_specifier, - which may occur in arbitrary order and each of which may be absent; - at least one of them must be present, however, since the totally - empty case has already be dealt with in `external_definition'. - This means that something like: - unsigned extern int short xx; - is perfectly legal C. - - On top of that, multiple occurrences of storage_class_specifiers, - unsigned_specifiers and size_specifiers are errors, but a second - type_specifier should end the decl_specifiers and be treated as - the name to be declared. - Such a language is not easily expressed in a grammar; enumeration - of the permutations is unattractive. We solve the problem by - having a regular grammar for the "soft" items, handling the single - occurrence of the type_specifier in the grammar (we have no choice), - collecting all data in a `struct decspecs' and turning that data - structure into what we want. - - The existence of declarations like - short typedef yepp; - makes all hope of writing a specific grammar for typedefs illusory. +an unsigned_specifier, a size_specifier and a simple type_specifier, +which may occur in arbitrary order and each of which may be absent; +at least one of them must be present, however, since the totally +empty case has already be dealt with in `external_definition'. +This means that something like: +unsigned extern int short xx; +is perfectly legal C. + +On top of that, multiple occurrences of storage_class_specifiers, +unsigned_specifiers and size_specifiers are errors, but a second +type_specifier should end the decl_specifiers and be treated as +the name to be declared. +Such a language is not easily expressed in a grammar; enumeration +of the permutations is unattractive. We solve the problem by +having a regular grammar for the "soft" items, handling the single +occurrence of the type_specifier in the grammar (we have no choice), +collecting all data in a `struct decspecs' and turning that data +structure into what we want. + +The existence of declarations like +short typedef yepp; +makes all hope of writing a specific grammar for typedefs illusory. */ /* Accept a single declaration specifier. Then accept zero or more - declaration specifiers. There can be a conflict on both - TYPE_IDENTIFIER and IDENTIFIER. - The following rule is used: - When we see a TYPE_IDENTIFIER, we accept it if no type-specifier was - given, and it is not directly followed by an identifier. If a - type-specifier was given, it is taken as the identifier being - declared. If it is followed by an identifier, we assume that an - error has been made, (e.g. unsigned typedeffed_int x;) and that - this will be detected later on. - When we see an IDENTIFIER, directly followed by another IDENTIFIER, - we assume that a typing mistake has been made, and we accept it as - an erroneous type-identifier. +declaration specifiers. There can be a conflict on both +TYPE_IDENTIFIER and IDENTIFIER. +The following rule is used: +When we see a TYPE_IDENTIFIER, we accept it if no type-specifier was +given, and it is not directly followed by an identifier. If a +type-specifier was given, it is taken as the identifier being +declared. If it is followed by an identifier, we assume that an +error has been made, (e.g. unsigned typedeffed_int x;) and that +this will be detected later on. +When we see an IDENTIFIER, directly followed by another IDENTIFIER, +we assume that a typing mistake has been made, and we accept it as +an erroneous type-identifier. */ -decl_specifiers /* non-empty */ (struct decspecs *ds;) - /* Reads a non-empty decl_specifiers and fills the struct - decspecs *ds. - */ -: - single_decl_specifier(ds) - [ %while( (DOT==TYPE_IDENTIFIER - && ds->ds_size == 0 - && ds->ds_unsigned == 0 - && ds->ds_type == (struct type *)0) - || AHEAD == IDENTIFIER) /* always an error */ - single_decl_specifier(ds) - ]* - {do_decspecs(ds);} -; - -single_decl_specifier /* non_empty */ (struct decspecs *ds;) -: - [ AUTO | STATIC | EXTERN | TYPEDEF | REGISTER ] - { if (ds->ds_sc_given) - error("repeated storage class specifier"); - ds->ds_sc_given = 1; - ds->ds_sc = DOT; - } -| - VOLATILE - { if (ds->ds_typequal & TQ_VOLATILE) - error("repeated type qualifier"); - ds->ds_typequal |= TQ_VOLATILE; - } -| - CONST - { if (ds->ds_typequal & TQ_CONST) - error("repeated type qualifier"); - ds->ds_typequal |= TQ_CONST; - } -| - [ SHORT | LONG ] - { if (ds->ds_size == LONG && DOT == LONG) - ds->ds_size = LNGLNG; - else { - if (ds->ds_size) - error("repeated size specifier"); - ds->ds_size = DOT; - } - } -| - [ SIGNED | UNSIGNED ] - { if (ds->ds_unsigned != 0) - error("repeated sign specifier"); - ds->ds_unsigned = DOT; - } -| - [ VOID | CHAR | INT | FLOAT | DOUBLE ] - { - idf2type(dot.tk_idf, &ds->ds_type); - ds->ds_typedef = 0; - } -| - %default TYPE_IDENTIFIER - { - idf2type(dot.tk_idf, &ds->ds_type); - ds->ds_typedef = 1; - } -| - %erroneous - IDENTIFIER - { - error("%s is not a type identifier", dot.tk_idf->id_text); - ds->ds_type = error_type; - if (dot.tk_idf->id_def) { - dot.tk_idf->id_def->df_type = error_type; - dot.tk_idf->id_def->df_sc = TYPEDEF; - } - } -| - %illegal - IDENTIFIER -| - struct_or_union_specifier(&ds->ds_type) -| - enum_specifier(&ds->ds_type) -; +decl_specifiers + /* non-empty */ +(struct decspecs* ds;) + /* Reads a non-empty decl_specifiers and fills the struct + decspecs *ds. + */ + : single_decl_specifier(ds) + [ + %while ((DOT == TYPE_IDENTIFIER && ds->ds_size == 0 && ds->ds_unsigned == 0 + && ds->ds_type == (struct type*)0) + || AHEAD == IDENTIFIER) + /* always an error */ + single_decl_specifier(ds) + ]* + { do_decspecs(ds); } + ; + +single_decl_specifier + /* non_empty */ +(struct decspecs* ds;) + : [ + AUTO + | STATIC + | EXTERN + | TYPEDEF + | REGISTER + ] + { + if (ds->ds_sc_given) + error("repeated storage class specifier"); + ds->ds_sc_given = 1; + ds->ds_sc = DOT; + } + | VOLATILE + { + if (ds->ds_typequal & TQ_VOLATILE) + error("repeated type qualifier"); + ds->ds_typequal |= TQ_VOLATILE; + } + | CONST + { + if (ds->ds_typequal & TQ_CONST) + error("repeated type qualifier"); + ds->ds_typequal |= TQ_CONST; + } + | [ + SHORT + | LONG + ] + { + if (ds->ds_size == LONG && DOT == LONG) + ds->ds_size = LNGLNG; + else + { + if (ds->ds_size) + error("repeated size specifier"); + ds->ds_size = DOT; + } + } + | [ + SIGNED + | UNSIGNED + ] + { + if (ds->ds_unsigned != 0) + error("repeated sign specifier"); + ds->ds_unsigned = DOT; + } + | [ + VOID + | CHAR + | INT + | FLOAT + | DOUBLE + ] + { + idf2type(dot.tk_idf, &ds->ds_type); + ds->ds_typedef = 0; + } + | %default + TYPE_IDENTIFIER + { + idf2type(dot.tk_idf, &ds->ds_type); + ds->ds_typedef = 1; + } + | %erroneous IDENTIFIER + { + error("%s is not a type identifier", dot.tk_idf->id_text); + ds->ds_type = error_type; + if (dot.tk_idf->id_def) + { + dot.tk_idf->id_def->df_type = error_type; + dot.tk_idf->id_def->df_sc = TYPEDEF; + } + } + | %illegal + IDENTIFIER + | struct_or_union_specifier(&ds->ds_type) + | enum_specifier(&ds->ds_type) + ; /* 3.5.2 */ -type_specifier(struct type **tpp;) - /* Used in struct/union declarations and in casts; only the - type is relevant. - */ - {struct decspecs Ds; Ds = null_decspecs;} -: - decl_specifiers(&Ds) - { - if (Ds.ds_sc_given) - error("storage class ignored"); - if (Ds.ds_sc == REGISTER) - error("register ignored"); - } - {*tpp = Ds.ds_type;} -; +type_specifier(struct type** tpp;) + /* Used in struct/union declarations and in casts; only the + type is relevant. + */ + { + struct decspecs Ds; + Ds = null_decspecs; + } + : decl_specifiers(&Ds) + { + if (Ds.ds_sc_given) + error("storage class ignored"); + if (Ds.ds_sc == REGISTER) + error("register ignored"); + } + { *tpp = Ds.ds_type; } + ; /* 3.5 */ -init_declarator_list(struct decspecs *ds;): - init_declarator(ds) - [ ',' init_declarator(ds) ]* -; - -init_declarator(struct decspecs *ds;) - { - struct declarator Dc; - } -: - { - Dc = null_declarator; - } -[ - declarator(&Dc) - { - reject_params(&Dc); - declare_idf(ds, &Dc, level); -#ifdef LINT - lint_declare_idf(Dc.dc_idf, ds->ds_sc); -#endif /* LINT */ - } - [ - initializer(Dc.dc_idf, ds->ds_sc) - | - { code_declaration(Dc.dc_idf, (struct expr *) 0, level, ds->ds_sc); } - ] -] - { -#ifdef LINT - add_auto(Dc.dc_idf); -#endif /* LINT */ - remove_declarator(&Dc); - } -; +init_declarator_list(struct decspecs* ds;) + : init_declarator(ds) + [ + ',' + init_declarator(ds) + ]* + ; + +init_declarator(struct decspecs* ds;) + { + struct declarator Dc; + } + : + { Dc = null_declarator; } + [ + declarator(&Dc) + { + reject_params(&Dc); + declare_idf(ds, &Dc, level); + #ifdef LINT + lint_declare_idf(Dc.dc_idf, ds->ds_sc); + #endif /* LINT */ + } + [ + initializer(Dc.dc_idf, ds->ds_sc) + | + { code_declaration(Dc.dc_idf, (struct expr*)0, level, ds->ds_sc); } + ] + ] + { + #ifdef LINT + add_auto(Dc.dc_idf); + #endif /* LINT */ + remove_declarator(&Dc); + } + ; /* 3.5.7: initializer */ -initializer(struct idf *idf; int sc;) - { - struct expr *expr = (struct expr *) 0; - int fund = idf->id_def->df_type->tp_fund; - int autoagg = (level >= L_LOCAL - && sc != STATIC - && ( fund == STRUCT - || fund == UNION - || fund == ARRAY)); - int globalflag = level == L_GLOBAL - || (level >= L_LOCAL && sc == STATIC); - } -: - { if (idf->id_def->df_type->tp_fund == FUNCTION) { - error("illegal initialization of function"); - idf->id_def->df_type->tp_fund = ERRONEOUS; - } - if (level == L_FORMAL2) - error("illegal initialization of formal parameter"); - } - '=' - { - if (AHEAD != '{' && AHEAD != STRING ) autoagg = 0; -#ifdef LINT - lint_statement(); -#endif /* LINT */ - if (globalflag) { - struct expr ex; - code_declaration(idf, &ex, level, sc); - } - else if (autoagg) - loc_init((struct expr *) 0, idf); - } - initial_value((globalflag || autoagg) ? - &(idf->id_def->df_type) - : (struct type **)0, - &expr) - { if (! globalflag) { - if (idf->id_def->df_type->tp_fund == FUNCTION) { - free_expression(expr); - expr = 0; - } -#ifdef DEBUG - print_expr("initializer-expression", expr); -#endif /* DEBUG */ -#ifdef LINT - change_state(idf, SET); -#endif /* LINT */ -#ifdef DBSYMTAB - if (options['g'] && level >= L_LOCAL && expr) { - db_line(expr->ex_file, (unsigned) expr->ex_line); - } -#endif /* DBSYMTAB */ - if (autoagg) - loc_init((struct expr *) 0, idf); - else code_declaration(idf, expr, level, sc); - } -#ifdef DBSYMTAB - if (options['g'] && globalflag) { - stb_string(idf->id_def, sc, idf->id_text); - } -#endif /* DBSYMTAB */ - idf_initialized(idf); - } -; +initializer(struct idf* idf; int sc;) + { + struct expr* expr = (struct expr*)0; + int fund = idf->id_def->df_type->tp_fund; + int autoagg = (level >= L_LOCAL && sc != STATIC + && (fund == STRUCT || fund == UNION || fund == ARRAY)); + int globalflag = level == L_GLOBAL || (level >= L_LOCAL && sc == STATIC); + } + : + { + if (idf->id_def->df_type->tp_fund == FUNCTION) + { + error("illegal initialization of function"); + idf->id_def->df_type->tp_fund = ERRONEOUS; + } + if (level == L_FORMAL2) + error("illegal initialization of formal parameter"); + } + '=' + { + if (AHEAD != '{' && AHEAD != STRING) + autoagg = 0; + #ifdef LINT + lint_statement(); + #endif /* LINT */ + if (globalflag) + { + struct expr ex; + code_declaration(idf, &ex, level, sc); + } + else if (autoagg) + loc_init((struct expr*)0, idf); + } + initial_value((globalflag || autoagg) ? &(idf->id_def->df_type) : (struct type**)0, &expr) + { + if (!globalflag) + { + if (idf->id_def->df_type->tp_fund == FUNCTION) + { + free_expression(expr); + expr = 0; + } + #ifdef DEBUG + print_expr("initializer-expression", expr); + #endif /* DEBUG */ + #ifdef LINT + change_state(idf, SET); + #endif /* LINT */ + #ifdef DBSYMTAB + if (options['g'] && level >= L_LOCAL && expr) + { + db_line(expr->ex_file, (unsigned)expr->ex_line); + } + #endif /* DBSYMTAB */ + if (autoagg) + loc_init((struct expr*)0, idf); + else + code_declaration(idf, expr, level, sc); + } + #ifdef DBSYMTAB + if (options['g'] && globalflag) + { + stb_string(idf->id_def, sc, idf->id_text); + } + #endif /* DBSYMTAB */ + idf_initialized(idf); + } + ; /* - Functions yielding pointers to functions must be declared as, e.g., - int (*hehe(par1, par2))() char *par1, *par2; {} - Since the function heading is read as a normal declarator, - we just include the (formal) parameter list in the declarator - description list dc. +Functions yielding pointers to functions must be declared as, e.g., +int (*hehe(par1, par2))() char *par1, *par2; {} +Since the function heading is read as a normal declarator, +we just include the (formal) parameter list in the declarator +description list dc. */ /* 3.5.4 */ -declarator(struct declarator *dc;) - { struct formal *fm = NO_PARAMS; - struct proto *pl = NO_PROTO; - arith count; - int qual; - } -: - primary_declarator(dc) - [/*%while(1)*/ - '(' - [ %if (DOT != IDENTIFIER) - parameter_type_list(&pl) - | - formal_list(&fm) - | - /* empty */ - ] - ')' - { add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl); - fm = NO_PARAMS; - } - | - arrayer(&count) - {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);} - ]* -| - pointer(&qual) declarator(dc) - {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);} -; - -primary_declarator(struct declarator *dc;) : - identifier(&dc->dc_idf) -| - '(' declarator(dc) ')' -; - -arrayer(arith *sizep;) - { struct expr *expr; } -: - '[' - { *sizep = (arith)-1; } - [ - constant_expression(&expr) - { - check_array_subscript(expr); - *sizep = (arith)expr->VL_VALUE; - free_expression(expr); - } - ]? - ']' -; - -formal_list (struct formal **fmp;) -: - formal(fmp) [ %persistent ',' formal(fmp) ]* -; - -formal(struct formal **fmp;) - {struct idf *idf; } -: - identifier(&idf) - { - struct formal *new = new_formal(); - - new->fm_idf = idf; - new->next = *fmp; - *fmp = new; - if (idf->id_def && idf->id_def->df_sc == TYPEDEF) { - error("typedef name %s may not be redeclared as a parameter", idf->id_text); - } - } -; +declarator(struct declarator* dc;) + { + struct formal* fm = NO_PARAMS; + struct proto* pl = NO_PROTO; + arith count; + int qual; + } + : primary_declarator(dc) + [ + /*%while(1)*/ + '(' + [ + %if (DOT != IDENTIFIER) + parameter_type_list(&pl) + | formal_list(&fm) + | + /* empty */ + ] + ')' + { + add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl); + fm = NO_PARAMS; + } + | arrayer(&count) + { add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO); } + ]* + | pointer(&qual) + declarator(dc) + { add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO); } + ; + +primary_declarator(struct declarator* dc;) + : identifier(&dc->dc_idf) + | '(' + declarator(dc) + ')' + ; + +arrayer(arith* sizep;) + { + struct expr* expr; + } + : '[' + { *sizep = (arith)-1; } + [ + constant_expression(&expr) + { + check_array_subscript(expr); + *sizep = (arith)expr->VL_VALUE; + free_expression(expr); + } + ]? + ']' + ; + +formal_list(struct formal** fmp;) + : formal(fmp) + [ + %persistent + ',' + formal(fmp) + ]* + ; + +formal(struct formal** fmp;) + { + struct idf* idf; + } + : identifier(&idf) + { + struct formal* new = new_formal(); + + new->fm_idf = idf; + new->next = *fmp; + *fmp = new; + if (idf->id_def && idf->id_def->df_sc == TYPEDEF) + { + error("typedef name %s may not be redeclared as a parameter", idf->id_text); + } + } + ; /* Change 2 */ -enum_specifier(struct type **tpp;) - { - struct idf *idf; - arith l = (arith)0; - } -: - {if (*tpp) error("multiple types in declaration");} - ENUM - [ - {declare_struct(ENUM, (struct idf *) 0, tpp);} - enumerator_pack(*tpp, &l) - | - identifier(&idf) - [ - {declare_struct(ENUM, idf, tpp);} - enumerator_pack(*tpp, &l) - { -#ifdef DBSYMTAB - if (options['g']) { - stb_tag(idf->id_tag, idf->id_text); - } -#endif /*DBSYMTAB */ - } - | - {apply_struct(ENUM, idf, tpp);} - /* empty */ - ] - ] -; - -enumerator_pack(struct type *tp; arith *lp;) : - '{' - enumerator(tp, lp) - [%while (AHEAD != '}') - ',' - enumerator(tp, lp) - ]* - [ - ',' {warning("unexpected trailing comma in enumerator pack");} - ]? - '}' - {tp->tp_size = int_size;} - /* fancy implementations that put small enums in 1 byte - or so should start here. - */ -; - -enumerator(struct type *tp; arith *lp;) - { - struct idf *idf; - struct expr *expr; - } -: - identifier(&idf) - [ - '=' - constant_expression(&expr) - { - *lp = (arith)expr->VL_VALUE; - free_expression(expr); - } - ]? - {declare_enum(tp, idf, (*lp)++);} -; +enum_specifier(struct type** tpp;) + { + struct idf* idf; + arith l = (arith)0; + } + : + { if (*tpp) error("multiple types in declaration"); } + ENUM + [ + { declare_struct(ENUM, (struct idf*)0, tpp); } + enumerator_pack(*tpp, &l) + | identifier(&idf) + [ + { declare_struct(ENUM, idf, tpp); } + enumerator_pack(*tpp, &l) + { + #ifdef DBSYMTAB + if (options['g']) + { + stb_tag(idf->id_tag, idf->id_text); + } + #endif /*DBSYMTAB */ + } + | + { apply_struct(ENUM, idf, tpp); } + /* empty */ + ] + ] + ; + +enumerator_pack(struct type* tp; arith* lp;) + : '{' + enumerator(tp, lp) + [ + %while (AHEAD != '}') + ',' + enumerator(tp, lp) + ]* + [ + ',' + { warning("unexpected trailing comma in enumerator pack"); } + ]? + '}' + { tp->tp_size = int_size; } + /* fancy implementations that put small enums in 1 byte + or so should start here. + */ + ; + +enumerator(struct type* tp; arith* lp;) + { + struct idf* idf; + struct expr* expr; + } + : identifier(&idf) + [ + '=' + constant_expression(&expr) + { + *lp = (arith)expr->VL_VALUE; + free_expression(expr); + } + ]? + { declare_enum(tp, idf, (*lp)++); } + ; /* 8.5 */ -struct_or_union_specifier(struct type **tpp;) - { - int fund; - struct idf *idfX; - struct idf *idf; - } -: - {if (*tpp) error("multiple types in declaration");} - [ STRUCT | UNION ] - {fund = DOT;} - [ - { - declare_struct(fund, (struct idf *)0, tpp); - } - struct_declaration_pack(*tpp) - | - identifier(&idfX) { idf = idfX; } - [ - { - declare_struct(fund, idf, tpp); - (idf->id_tag->tg_busy)++; - } - struct_declaration_pack(*tpp) - { - (idf->id_tag->tg_busy)--; -#ifdef DBSYMTAB - if (options['g']) { - stb_tag(idf->id_tag, idf->id_text); - } -#endif /*DBSYMTAB */ - } - | - { - /* a ';' means an empty declaration (probably) - * this means that we have to declare a new - * structure. (yegh) - */ - if (DOT == ';' && - ( !idf->id_tag || - idf->id_tag->tg_level != level || - idf->id_tag->tg_type->tp_size < 0 - )) declare_struct(fund, idf, tpp); - else apply_struct(fund, idf, tpp); - } - /* empty */ - ] - ] -; - -struct_declaration_pack(struct type *stp;) - { - struct sdef **sdefp = &stp->tp_sdef; - arith size = (arith)0; - } -: - /* The size is only filled in after the whole struct has - been read, to prevent recursive definitions. - */ - '{' - struct_declaration(stp, &sdefp, &size)+ - '}' - {stp->tp_size = align(size, stp->tp_align); - completed(stp); - } -; - -struct_declaration(struct type *stp; struct sdef ***sdefpp; arith *szp;) - {struct type *tp;} -: - type_specifier(&tp) struct_declarator_list(tp, stp, sdefpp, szp) ';' -; - -struct_declarator_list(struct type *tp; struct type *stp; - struct sdef ***sdefpp; arith *szp;) -: - struct_declarator(tp, stp, sdefpp, szp) - [ ',' struct_declarator(tp, stp, sdefpp, szp) ]* -; - -struct_declarator(struct type *tp; struct type *stp; - struct sdef ***sdefpp; arith *szp;) - { - struct declarator Dc; - struct field *fd = 0; - } -: - { - Dc = null_declarator; - } -[ - declarator(&Dc) - {reject_params(&Dc);} - bit_expression(&fd)? -| - {Dc.dc_idf = gen_idf();} - bit_expression(&fd) -] - {add_sel(stp, declare_type(tp, &Dc), Dc.dc_idf, sdefpp, szp, fd);} - {remove_declarator(&Dc);} -; - -bit_expression(struct field **fd;) - { struct expr *expr; } -: - { - *fd = new_field(); - } - ':' - constant_expression(&expr) - { - (*fd)->fd_width = (arith)expr->VL_VALUE; - free_expression(expr); -#ifdef NOBITFIELD - error("bitfields are not implemented"); -#endif /* NOBITFIELD */ - } -; +struct_or_union_specifier(struct type** tpp;) + { + int fund; + struct idf* idfX; + struct idf* idf; + } + : + { if (*tpp) error("multiple types in declaration"); } + [ + STRUCT + | UNION + ] + { fund = DOT; } + [ + { declare_struct(fund, (struct idf*)0, tpp); } + struct_declaration_pack(*tpp) + | identifier(&idfX) + { idf = idfX; } + [ + { + declare_struct(fund, idf, tpp); + (idf->id_tag->tg_busy)++; + } + struct_declaration_pack(*tpp) + { + (idf->id_tag->tg_busy)--; + #ifdef DBSYMTAB + if (options['g']) + { + stb_tag(idf->id_tag, idf->id_text); + } + #endif /*DBSYMTAB */ + } + | + { + /* a ';' means an empty declaration (probably) + * this means that we have to declare a new + * structure. (yegh) + */ + if (DOT == ';' + && (!idf->id_tag || idf->id_tag->tg_level != level + || idf->id_tag->tg_type->tp_size < 0)) + declare_struct(fund, idf, tpp); + else + apply_struct(fund, idf, tpp); + } + /* empty */ + ] + ] + ; + +struct_declaration_pack(struct type* stp;) + { + struct sdef** sdefp = &stp->tp_sdef; + arith size = (arith)0; + } + : + /* The size is only filled in after the whole struct has + been read, to prevent recursive definitions. + */ + '{' + struct_declaration(stp, &sdefp, &size)+ + '}' + { + stp->tp_size = align(size, stp->tp_align); + completed(stp); + } + ; + +struct_declaration(struct type* stp; struct sdef*** sdefpp; arith* szp;) + { + struct type* tp; + } + : type_specifier(&tp) + struct_declarator_list(tp, stp, sdefpp, szp) + ';' + ; + +struct_declarator_list(struct type* tp; struct type* stp; struct sdef*** sdefpp; arith* szp;) + : struct_declarator(tp, stp, sdefpp, szp) + [ + ',' + struct_declarator(tp, stp, sdefpp, szp) + ]* + ; + +struct_declarator(struct type* tp; struct type* stp; struct sdef*** sdefpp; arith* szp;) + { + struct declarator Dc; + struct field* fd = 0; + } + : + { Dc = null_declarator; } + [ + declarator(&Dc) + { reject_params(&Dc); } + bit_expression(&fd)? + | + { Dc.dc_idf = gen_idf(); } + bit_expression(&fd) + ] + { add_sel(stp, declare_type(tp, &Dc), Dc.dc_idf, sdefpp, szp, fd); } + { remove_declarator(&Dc); } + ; + +bit_expression(struct field** fd;) + { + struct expr* expr; + } + : + { *fd = new_field(); } + ':' + constant_expression(&expr) + { + (*fd)->fd_width = (arith)expr->VL_VALUE; + free_expression(expr); + #ifdef NOBITFIELD + error("bitfields are not implemented"); + #endif /* NOBITFIELD */ + } + ; /* 8.7 */ -cast(struct type **tpp;) - {struct declarator Dc;} -: - {Dc = null_declarator;} - '(' - type_specifier(tpp) - abstract_declarator(&Dc) - ')' - {*tpp = declare_type(*tpp, &Dc);} - {remove_declarator(&Dc);} -; +cast(struct type** tpp;) + { + struct declarator Dc; + } + : + { Dc = null_declarator; } + '(' + type_specifier(tpp) + abstract_declarator(&Dc) + ')' + { *tpp = declare_type(*tpp, &Dc); } + { remove_declarator(&Dc); } + ; /* This code is an abject copy of that of 'declarator', for lack of - a two-level grammar. +a two-level grammar. */ -abstract_declarator(struct declarator *dc;) - { struct proto *pl = NO_PROTO; - arith count; - int qual; - } -: - primary_abstract_declarator(dc) - [ - '(' - [ - parameter_type_list(&pl) - | - /* empty */ - ] - ')' - {add_decl_unary(dc, FUNCTION, 0, (arith)0, NO_PARAMS, pl); - if (pl) remove_proto_idfs(pl); - } - | - arrayer(&count) - {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);} - ]* -| - pointer(&qual) abstract_declarator(dc) - {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);} -; +abstract_declarator(struct declarator* dc;) + { + struct proto* pl = NO_PROTO; + arith count; + int qual; + } + : primary_abstract_declarator(dc) + [ + '(' + [ + parameter_type_list(&pl) + | + /* empty */ + ] + ')' + { + add_decl_unary(dc, FUNCTION, 0, (arith)0, NO_PARAMS, pl); + if (pl) + remove_proto_idfs(pl); + } + | arrayer(&count) + { add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO); } + ]* + | pointer(&qual) + abstract_declarator(dc) + { add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO); } + ; %first first_of_parameter_type_list, parameter_type_list; -primary_abstract_declarator(struct declarator *dc;) -: -[%if (AHEAD == ')' || first_of_parameter_type_list(AHEAD)) - /* empty */ -| - '(' abstract_declarator(dc) ')' -] -; - -parameter_type_list(struct proto **plp;) - { int save_level; } -: - { if (level > L_PROTO) { - save_level = level; - level = L_PROTO; - } else level--; - } - parameter_decl_list(plp) - [ - ',' ELLIPSIS - { struct proto *new = new_proto(); - - new->next = *plp; - new->pl_flag = PL_ELLIPSIS; - *plp = new; - } - - ]? - { check_for_void(*plp); - if (level == L_PROTO) - level = save_level; - else level++; - } -; - -parameter_decl_list(struct proto **plp;) -: - parameter_decl(plp) - [ %while (AHEAD != ELLIPSIS) - %persistent - ',' parameter_decl(plp) - ]* -; - -parameter_decl(struct proto **plp;) - { struct proto *new = new_proto(); - struct declarator Dc; - struct decspecs Ds; - } -: - { Dc = null_declarator; - Ds = null_decspecs; - } - decl_specifiers(&Ds) - parameter_declarator(&Dc) - { add_proto(new, &Ds, &Dc, level); - new->next = *plp; - *plp = new; - remove_declarator(&Dc); - } -; +primary_abstract_declarator(struct declarator* dc;) + : [ + %if (AHEAD == ')' || first_of_parameter_type_list(AHEAD)) + /* empty */ + | '(' + abstract_declarator(dc) + ')' + ] + ; + +parameter_type_list(struct proto** plp;) + { + int save_level; + } + : + { if (level > L_PROTO) { save_level = level; level = L_PROTO; } else level--; } + parameter_decl_list(plp) + [ + ',' ELLIPSIS + { + struct proto* new = new_proto(); + + new->next = *plp; + new->pl_flag = PL_ELLIPSIS; + *plp = new; + } + ]? + { + check_for_void(*plp); + if (level == L_PROTO) + level = save_level; + else + level++; + } + ; + +parameter_decl_list(struct proto** plp;) + : parameter_decl(plp) + [ + %while (AHEAD != ELLIPSIS) + %persistent + ',' + parameter_decl(plp) + ]* + ; + +parameter_decl(struct proto** plp;) + { + struct proto* new = new_proto(); + struct declarator Dc; + struct decspecs Ds; + } + : + { + Dc = null_declarator; + Ds = null_decspecs; + } + decl_specifiers(&Ds) + parameter_declarator(&Dc) + { + add_proto(new, &Ds, &Dc, level); + new->next = *plp; + *plp = new; + remove_declarator(&Dc); + } + ; /* This is weird. Due to the LR structure of the ANSI C grammar - we have to duplicate the actions of 'declarator' and - 'abstract_declarator'. Calling these separately, as in - - parameter_decl: - decl_specifiers - [ - declarator - | - abstract_declarator - ] - - - gives us a conflict on the terminals '(' and '*'. E.i. on - some input, it is impossible to decide which rule we take. - Combining the two declarators into one common declarator - is out of the question, since this results in an empty - string for the non-terminal 'declarator'. - So we combine the two only for the use of parameter_decl, - since this is the only place where they don't give - conflicts. However, this makes the grammar messy. -*/ -parameter_declarator(struct declarator *dc;) - { struct formal *fm = NO_PARAMS; - struct proto *pl = NO_PROTO; - arith count; - int qual; - } -: - primary_parameter_declarator(dc) - [ - '(' - [ %if (DOT != IDENTIFIER) - parameter_type_list(&pl) - | - formal_list(&fm) - | - /* empty */ - ] - ')' - { add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl); - reject_params(dc); - } - | - arrayer(&count) - {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);} - ]* -| - pointer(&qual) parameter_declarator(dc) - {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);} -; - -primary_parameter_declarator(struct declarator *dc;) -: -[%if (AHEAD == ')' || first_of_parameter_type_list(AHEAD) - && (AHEAD != IDENTIFIER)) - /* empty */ -| - identifier(&dc->dc_idf) +we have to duplicate the actions of 'declarator' and +'abstract_declarator'. Calling these separately, as in + +parameter_decl: +decl_specifiers +[ +declarator | - '(' parameter_declarator(dc) ')' +abstract_declarator ] -; -pointer(int *qual;) -: - '*' type_qualifier_list(qual) -; + +gives us a conflict on the terminals '(' and '*'. E.i. on +some input, it is impossible to decide which rule we take. +Combining the two declarators into one common declarator +is out of the question, since this results in an empty +string for the non-terminal 'declarator'. +So we combine the two only for the use of parameter_decl, +since this is the only place where they don't give +conflicts. However, this makes the grammar messy. +*/ +parameter_declarator(struct declarator* dc;) + { + struct formal* fm = NO_PARAMS; + struct proto* pl = NO_PROTO; + arith count; + int qual; + } + : primary_parameter_declarator(dc) + [ + '(' + [ + %if (DOT != IDENTIFIER) + parameter_type_list(&pl) + | formal_list(&fm) + | + /* empty */ + ] + ')' + { + add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl); + reject_params(dc); + } + | arrayer(&count) + { add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO); } + ]* + | pointer(&qual) + parameter_declarator(dc) + { add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO); } + ; + +primary_parameter_declarator(struct declarator* dc;) + : [ + %if (AHEAD == ')' || first_of_parameter_type_list(AHEAD) && (AHEAD != IDENTIFIER)) + /* empty */ + | identifier(&dc->dc_idf) + | '(' + parameter_declarator(dc) + ')' + ] + ; + +pointer(int* qual;) + : '*' + type_qualifier_list(qual) + ; /* Type qualifiers may come in three flavours: - volatile, const, const volatile. - These all have different semantic properties: +volatile, const, const volatile. +These all have different semantic properties: - volatile: - means that the object can be modified - without prior knowledge of the implementation. +volatile: +means that the object can be modified +without prior knowledge of the implementation. - const: - means that the object can not be modified; thus - it's illegal to use this as a l-value. +const: +means that the object can not be modified; thus +it's illegal to use this as a l-value. - const volatile: - means that the object can be modified without - prior knowledge of the implementation, but may - not be used as a l-value. +const volatile: +means that the object can be modified without +prior knowledge of the implementation, but may +not be used as a l-value. */ /* 3.5.4 */ -type_qualifier_list(int *qual;) -: - { *qual = 0; } - [ - VOLATILE - { if (*qual & TQ_VOLATILE) - error("repeated type qualifier"); - *qual |= TQ_VOLATILE; - } - | - CONST - { if (*qual & TQ_CONST) - error("repeated type qualifier"); - *qual |= TQ_CONST; - } - ]* -; - -empty: -; +type_qualifier_list(int* qual;) + : + { *qual = 0; } + [ + VOLATILE + { + if (*qual & TQ_VOLATILE) + error("repeated type qualifier"); + *qual |= TQ_VOLATILE; + } + | CONST + { + if (*qual & TQ_CONST) + error("repeated type qualifier"); + *qual |= TQ_CONST; + } + ]* + ; + +empty + : + ; diff --git a/lang/cem/cemcom.ansi/expression.g b/lang/cem/cemcom.ansi/expression.g index b2cba80b9..1d7643ada 100644 --- a/lang/cem/cemcom.ansi/expression.g +++ b/lang/cem/cemcom.ansi/expression.g @@ -2,353 +2,441 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cemcom.ansi/expression.g + */ /* $Id$ */ /* EXPRESSION SYNTAX PARSER */ { -#include -#include -#include "parameters.h" -#include -#include "arith.h" -#include "LLlex.h" -#include "type.h" -#include "label.h" -#include "expr.h" -#include "code.h" -#include "error.h" -#include "ch3.h" -#include "ch3bin.h" -#include "ch3mon.h" -#include "proto.h" -#include "sizes.h" + #include + #include + #include "parameters.h" + #include + #include "arith.h" + #include "LLlex.h" + #include "type.h" + #include "label.h" + #include "expr.h" + #include "code.h" + #include "error.h" + #include "ch3.h" + #include "ch3bin.h" + #include "ch3mon.h" + #include "proto.h" + #include "sizes.h" -int InSizeof = 0; /* inside a sizeof- expression */ -int ResultKnown = 0; /* result of the expression is already known */ + int InSizeof = 0; /* inside a sizeof- expression */ + int ResultKnown = 0; /* result of the expression is already known */ -/* Since the grammar in the standard is not LL(n), it is modified so that - * it accepts basically the same grammar. This means that there is no 1-1 - * mapping from the grammar in the standard to the grammar given here. - * Such is life. - */ + /* Since the grammar in the standard is not LL(n), it is modified so that + * it accepts basically the same grammar. This means that there is no 1-1 + * mapping from the grammar in the standard to the grammar given here. + * Such is life. + */ } /* 3.3.1 */ -primary(struct expr **expp;) : - IDENTIFIER - {dot2expr(expp);} -| - constant(expp) -| - string(expp) -| - '(' expression(expp) ')' - { (*expp)->ex_flags |= EX_PARENS; } -; +primary(struct expr** expp;) + : IDENTIFIER + { dot2expr(expp); } + | constant(expp) + | string(expp) + | '(' + expression(expp) + ')' + { (*expp)->ex_flags |= EX_PARENS; } + ; /* Character string literals that are adjacent tokens * are concatenated into a single character string * literal. */ -string(struct expr **expp;) - { int i, len; - char *str; - int fund; - } -: - STRING - { str = dot.tk_bts; - len = dot.tk_len; - fund = dot.tk_fund; - } - [ - STRING - { /* A pasted string keeps the type of the first - * string literal. - * The pasting of normal strings and wide - * character strings are stated as having an - * undefined behaviour. - */ - if (dot.tk_fund != fund) - warning("illegal pasting of string literals"); - str = realloc(str, (unsigned) (--len + dot.tk_len)); - for (i = 0; i < dot.tk_len; i++) - str[len++] = dot.tk_bts[i]; - } - ]* - { string2expr(expp, str, len); } -; +string(struct expr** expp;) + { + int i, len; + char* str; + int fund; + } + : STRING + { + str = dot.tk_bts; + len = dot.tk_len; + fund = dot.tk_fund; + } + [ + STRING + { + /* A pasted string keeps the type of the first + * string literal. + * The pasting of normal strings and wide + * character strings are stated as having an + * undefined behaviour. + */ + if (dot.tk_fund != fund) + warning("illegal pasting of string literals"); + str = realloc(str, (unsigned)(--len + dot.tk_len)); + for (i = 0; i < dot.tk_len; i++) + str[len++] = dot.tk_bts[i]; + } + ]* + { string2expr(expp, str, len); } + ; /* 3.3.2 */ -postfix_expression(struct expr **expp;) - { int oper; - struct expr *e1 = 0; - struct idf *idf; - } -: - primary(expp) - [ - '[' expression(&e1) ']' - { ch3bin(expp, '[', e1); e1 = 0; } - | - '(' parameter_list(&e1)? ')' - { ch3bin(expp, '(', e1); call_proto(expp); e1 = 0; } - | - [ '.' | ARROW ] { oper = DOT; } - identifier(&idf) { ch3sel(expp, oper, idf); } - | - [ - PLUSPLUS { oper = POSTINCR; } - | - MINMIN { oper = POSTDECR; } - ] - { ch3incr(expp, oper); } - ]* -; +postfix_expression(struct expr** expp;) + { + int oper; + struct expr* e1 = 0; + struct idf* idf; + } + : primary(expp) + [ + '[' + expression(&e1) + ']' + { + ch3bin(expp, '[', e1); + e1 = 0; + } + | '(' + parameter_list(&e1)? + ')' + { + ch3bin(expp, '(', e1); + call_proto(expp); + e1 = 0; + } + | [ + '.' + | ARROW + ] + { oper = DOT; } + identifier(&idf) + { ch3sel(expp, oper, idf); } + | [ + PLUSPLUS + { oper = POSTINCR; } + | MINMIN + { oper = POSTDECR; } + ] + { ch3incr(expp, oper); } + ]* + ; -parameter_list(struct expr **expp;) - {struct expr *e1 = 0;} -: - assignment_expression(expp) - {any2opnd(expp, PARCOMMA);} - [ %persistent - ',' - assignment_expression(&e1) - {any2opnd(&e1, PARCOMMA);} - {ch3bin(expp, PARCOMMA, e1);} - ]* -; +parameter_list(struct expr** expp;) + { + struct expr* e1 = 0; + } + : assignment_expression(expp) + { any2opnd(expp, PARCOMMA); } + [ + %persistent + ',' + assignment_expression(&e1) + { any2opnd(&e1, PARCOMMA); } + { ch3bin(expp, PARCOMMA, e1); } + ]* + ; -%first first_of_type_specifier, type_specifier; +%first first_of_type_specifier, type_specifier; /* 3.3.3 & 3.3.4 */ -unary(struct expr **expp;) - {struct type *tp; int oper;} -: -%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) - cast(&tp) unary(expp) - { ch3cast(expp, CAST, tp); - (*expp)->ex_flags |= EX_CAST; - if (int_size != pointer_size) - (*expp)->ex_flags &= ~EX_PTRDIFF; - } -| - postfix_expression(expp) -| - unop(&oper) unary(expp) - {ch3mon(oper, expp);} -| - size_of(expp) -; +unary(struct expr** expp;) + { + struct type* tp; + int oper; + } + : %if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) + cast(&tp) + unary(expp) + { + ch3cast(expp, CAST, tp); + (*expp)->ex_flags |= EX_CAST; + if (int_size != pointer_size) + (*expp)->ex_flags &= ~EX_PTRDIFF; + } + | postfix_expression(expp) + | unop(&oper) + unary(expp) + { ch3mon(oper, expp); } + | size_of(expp) + ; /* When an identifier is used in a sizeof()-expression, we must stil not * mark it as used. * extern int i; .... sizeof(i) .... need not have a definition for i */ -size_of(struct expr **expp;) - {struct type *tp;} -: - SIZEOF { InSizeof++; } /* handle (sizeof(sizeof(int))) too */ - [%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) - cast(&tp) - { - *expp = intexpr(size_of_type(tp, "type"), UNSIGNED); - (*expp)->ex_flags |= EX_SIZEOF; - } - | - unary(expp) - {ch3mon(SIZEOF, expp);} - ] - { InSizeof--; } -; +size_of(struct expr** expp;) + { + struct type* tp; + } + : SIZEOF + { InSizeof++; } + /* handle (sizeof(sizeof(int))) too */ + [ + %if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) + cast(&tp) + { + *expp = intexpr(size_of_type(tp, "type"), UNSIGNED); + (*expp)->ex_flags |= EX_SIZEOF; + } + | unary(expp) + { ch3mon(SIZEOF, expp); } + ] + { InSizeof--; } + ; /* 3.3.5-3.3.17 */ /* The set of operators in C is stratified in 15 levels, with level - N being treated in RM 7.N (although this is not the standard - anymore). The standard describes this in phrase-structure-grammar, - which we are unable to parse. The description that follows comes - from the old C-compiler. +N being treated in RM 7.N (although this is not the standard +anymore). The standard describes this in phrase-structure-grammar, +which we are unable to parse. The description that follows comes +from the old C-compiler. - In principle each operator is assigned a rank, ranging - from 1 to 15. Such an expression can be parsed by a construct - like: - binary_expression(int maxrank;) - {int oper;} - : - binary_expression(maxrank - 1) - [%if (rank_of(DOT) <= maxrank) - binop(&oper) - binary_expression(rank_of(oper)-1) - ]? - ; - except that some call of 'unary' is necessary, depending on the - grammar. - - This simple view is marred by three complications: - 1. Level 15 (comma operator) is not allowed in many - contexts and is different. - 2. Level 13 (conditional operator) is a ternary operator, - which does not fit this scheme at all. - 3. Level 14 (assignment operators) group right-to-left, as - opposed to 2-12, which group left-to-right (or are - immaterial). - 4. The operators in level 14 start with operators in levels - 2-13 (RM 7.14: The two parts of a compound assignment - operator are separate tokens.) This causes LL1 problems. - This forces us to have four rules: - binary_expression for level 2-12 - conditional_expression for level 13 - assignment_expression for level 14 and - expression for the most general expression -*/ - -binary_expression(int maxrank; struct expr **expp;) - {int oper, OldResultKnown; struct expr *e1;} +In principle each operator is assigned a rank, ranging +from 1 to 15. Such an expression can be parsed by a construct +like: +binary_expression(int maxrank;) +{int oper;} : - unary(expp) - [%while (rank_of(DOT) <= maxrank ) - /* '?', '=', and ',' are no binops - */ - binop(&oper) - { OldResultKnown = ResultKnown; - if (oper == OR || oper == AND) { - if (is_cp_cst(*expp) || is_fp_cst(*expp)) { - if (is_zero_cst(*expp)) { - if (oper == AND) ResultKnown++; - } else if (oper == OR) ResultKnown++; - } - } - } - binary_expression(rank_of(oper)-1, &e1) - { - ch3bin(expp, oper, e1); - ResultKnown = OldResultKnown; - } - ]* +binary_expression(maxrank - 1) +[%if (rank_of(DOT) <= maxrank) +binop(&oper) +binary_expression(rank_of(oper)-1) +]? ; +except that some call of 'unary' is necessary, depending on the +grammar. + +This simple view is marred by three complications: +1. Level 15 (comma operator) is not allowed in many +contexts and is different. +2. Level 13 (conditional operator) is a ternary operator, +which does not fit this scheme at all. +3. Level 14 (assignment operators) group right-to-left, as +opposed to 2-12, which group left-to-right (or are +immaterial). +4. The operators in level 14 start with operators in levels +2-13 (RM 7.14: The two parts of a compound assignment +operator are separate tokens.) This causes LL1 problems. +This forces us to have four rules: +binary_expression for level 2-12 +conditional_expression for level 13 +assignment_expression for level 14 and +expression for the most general expression +*/ + +binary_expression(int maxrank; struct expr** expp;) + { + int oper, OldResultKnown; + struct expr* e1; + } + : unary(expp) + [ + %while (rank_of(DOT) <= maxrank) + /* '?', '=', and ',' are no binops + */ + binop(&oper) + { + OldResultKnown = ResultKnown; + if (oper == OR || oper == AND) + { + if (is_cp_cst(*expp) || is_fp_cst(*expp)) + { + if (is_zero_cst(*expp)) + { + if (oper == AND) + ResultKnown++; + } + else if (oper == OR) + ResultKnown++; + } + } + } + binary_expression(rank_of(oper) - 1, &e1) + { + ch3bin(expp, oper, e1); + ResultKnown = OldResultKnown; + } + ]* + ; /* 3.3.15 */ -conditional_expression(struct expr **expp;) - {struct expr *e1 = 0, *e2 = 0; int OldResultKnown, ConstExpr=0;} -: - /* allow all binary operators */ - binary_expression(rank_of('?') - 1, expp) - [ '?' - { OldResultKnown = ResultKnown; - if (is_cp_cst(*expp) || is_fp_cst(*expp)) { - ConstExpr++; - if (is_zero_cst(*expp)) ResultKnown++; - } - } - expression(&e1) - ':' - { if (ConstExpr) { - if (OldResultKnown == ResultKnown) ResultKnown++; - else ResultKnown = OldResultKnown; - } - } - conditional_expression(&e2) - { - ResultKnown = OldResultKnown; - ch3bin(&e1, ':', e2); - opnd2test(expp, '?'); - ch3bin(expp, '?', e1); - } - ]? -; +conditional_expression(struct expr** expp;) + { + struct expr *e1 = 0, *e2 = 0; + int OldResultKnown, ConstExpr = 0; + } + : + /* allow all binary operators */ + binary_expression(rank_of('?') - 1, expp) + [ + '?' + { + OldResultKnown = ResultKnown; + if (is_cp_cst(*expp) || is_fp_cst(*expp)) + { + ConstExpr++; + if (is_zero_cst(*expp)) + ResultKnown++; + } + } + expression(&e1) + ':' + { + if (ConstExpr) + { + if (OldResultKnown == ResultKnown) + ResultKnown++; + else + ResultKnown = OldResultKnown; + } + } + conditional_expression(&e2) + { + ResultKnown = OldResultKnown; + ch3bin(&e1, ':', e2); + opnd2test(expp, '?'); + ch3bin(expp, '?', e1); + } + ]? + ; /* 3.3.16 */ -assignment_expression(struct expr **expp;) - { int oper; - struct expr *e1 = 0; - } -: - conditional_expression(expp) - [ - asgnop(&oper) - assignment_expression(&e1) - {ch3asgn(expp, oper, e1);} - | - empty /* LLgen artefact ??? */ - ] -; +assignment_expression(struct expr** expp;) + { + int oper; + struct expr* e1 = 0; + } + : conditional_expression(expp) + [ + asgnop(&oper) + assignment_expression(&e1) + { ch3asgn(expp, oper, e1); } + | empty + /* LLgen artefact ??? */ + ] + ; /* 3.3.17 */ -expression(struct expr **expp;) - {struct expr *e1;} -: - assignment_expression(expp) - [ ',' - assignment_expression(&e1) - { - ch3bin(expp, ',', e1); - } - ]* -; +expression(struct expr** expp;) + { + struct expr* e1; + } + : assignment_expression(expp) + [ + ',' + assignment_expression(&e1) + { ch3bin(expp, ',', e1); } + ]* + ; -unop(int *oper;) : - ['*' | '&' | '-' | '+' | '!' | '~' | PLUSPLUS | MINMIN] - { if (DOT == '&') DOT = ADDRESSOF; - *oper = DOT; - } -; +unop(int* oper;) + : [ + '*' + | '&' + | '-' + | '+' + | '!' + | '~' + | PLUSPLUS + | MINMIN + ] + { + if (DOT == '&') + DOT = ADDRESSOF; + *oper = DOT; + } + ; -multop: - '*' | '/' | '%' -; +multop + : '*' + | '/' + | '%' + ; -addop: - '+' | '-' -; +addop + : '+' + | '-' + ; -shiftop: - LEFT | RIGHT -; +shiftop + : LEFT + | RIGHT + ; -relop: - '<' | '>' | LESSEQ | GREATEREQ -; +relop + : '<' + | '>' + | LESSEQ + | GREATEREQ + ; -eqop: - EQUAL | NOTEQUAL -; +eqop + : EQUAL + | NOTEQUAL + ; -arithop: - multop | addop | shiftop -| - '&' | '^' | '|' -; +arithop + : multop + | addop + | shiftop + | '&' + | '^' + | '|' + ; -binop(int *oper;) : - [ arithop | relop | eqop | AND | OR ] - {*oper = DOT;} -; +binop(int* oper;) + : [ + arithop + | relop + | eqop + | AND + | OR + ] + { *oper = DOT; } + ; -asgnop(int *oper;): - [ '=' | PLUSAB | MINAB | TIMESAB | DIVAB | MODAB - | LEFTAB | RIGHTAB | ANDAB | XORAB | ORAB ] - { *oper = DOT; } +asgnop(int* oper;) + : [ + '=' + | PLUSAB + | MINAB + | TIMESAB + | DIVAB + | MODAB + | LEFTAB + | RIGHTAB + | ANDAB + | XORAB + | ORAB + ] + { *oper = DOT; } + ; -; - -constant(struct expr **expp;) : -[ - INTEGER -| - FLOATING -] {dot2expr(expp);} -; +constant(struct expr** expp;) + : [ + INTEGER + | FLOATING + ] + { dot2expr(expp); } + ; /* 3.4 */ -constant_expression (struct expr **expp;) : - conditional_expression(expp) - { chk_cst_expr(expp); } -; +constant_expression(struct expr** expp;) + : conditional_expression(expp) + { chk_cst_expr(expp); } + ; -identifier(struct idf **idfp;) : -[ IDENTIFIER -| TYPE_IDENTIFIER -] - { *idfp = dot.tk_idf; } -; +identifier(struct idf** idfp;) + : [ + IDENTIFIER + | TYPE_IDENTIFIER + ] + { *idfp = dot.tk_idf; } + ; diff --git a/lang/cem/cemcom.ansi/ival.g b/lang/cem/cemcom.ansi/ival.g index c6bb26042..ccfd5c72d 100644 --- a/lang/cem/cemcom.ansi/ival.g +++ b/lang/cem/cemcom.ansi/ival.g @@ -2,758 +2,828 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cemcom.ansi/ival.g + */ /* $Id$ */ /* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */ { -#include -#include -#include "parameters.h" -#ifndef LINT -#include -#else -#include "l_em.h" -#include "l_lint.h" -#endif /* LINT */ -#include -#include -#include -#include -#include -#include "idf.h" -#include "arith.h" -#include "label.h" -#include "expr.h" -#include "type.h" -#include "proto.h" -#include "struct.h" -#include "field.h" -#include "Lpars.h" -#include "sizes.h" -#include "align.h" -#include "level.h" -#include "error.h" -#include "def.h" -#include "LLlex.h" -#include "estack.h" -#include "stack.h" -#include "ch3.h" - -#define con_nullbyte() C_con_ucon("0", (arith)1) -#define aggregate_type(tp) ((tp)->tp_fund == ARRAY || (tp)->tp_fund == STRUCT) - -extern char options[]; -static int gen_error; -static int pack_level; -struct e_stack *p_stack; - -void gen_tpcheck(struct type **); -void gen_simple_exp(struct type **, struct expr **); -struct type **arr_elem(struct type **, struct e_stack *); -struct sdef *next_field(struct sdef *,struct e_stack *); -struct type **gen_tphead(struct type **, int); -struct type **gen_tpmiddle(void); -struct sdef *gen_align_to_next(struct e_stack *); -void gen_tpend(void); -void check_and_pad(struct expr **, struct type **); -void pad(struct type *); -void check_ival(struct expr **, struct type *); -void ch_array(struct type **, /* type tp = array of characters */ - struct expr *); -void str_cst(char *, int, int); -#ifndef NOBITFIELD -void put_bf(struct type *, arith ); -#endif /* NOBITFIELD */ -int zero_bytes(struct sdef *); -int valid_type(struct type *, char *); -void con_int(struct expr *); -void illegal_init_cst(struct expr *); -void too_many_initialisers(void); - + #include + #include + #include "parameters.h" + #ifndef LINT + #include + #else + #include "l_em.h" + #include "l_lint.h" + #endif /* LINT */ + #include + #include + #include + #include + #include + #include "idf.h" + #include "arith.h" + #include "label.h" + #include "expr.h" + #include "type.h" + #include "proto.h" + #include "struct.h" + #include "field.h" + #include "Lpars.h" + #include "sizes.h" + #include "align.h" + #include "level.h" + #include "error.h" + #include "def.h" + #include "LLlex.h" + #include "estack.h" + #include "stack.h" + #include "ch3.h" + + #define con_nullbyte() C_con_ucon("0", (arith)1) + #define aggregate_type(tp) ((tp)->tp_fund == ARRAY || (tp)->tp_fund == STRUCT) + + extern char options[]; + static int gen_error; + static int pack_level; + struct e_stack* p_stack; + + void gen_tpcheck(struct type**); + void gen_simple_exp(struct type**, struct expr**); + struct type** arr_elem(struct type**, struct e_stack*); + struct sdef* next_field(struct sdef*, struct e_stack*); + struct type** gen_tphead(struct type**, int); + struct type** gen_tpmiddle(void); + struct sdef* gen_align_to_next(struct e_stack*); + void gen_tpend(void); + void check_and_pad(struct expr**, struct type**); + void pad(struct type*); + void check_ival(struct expr**, struct type*); + void ch_array(struct type**, /* type tp = array of characters */ + struct expr*); + void str_cst(char*, int, int); + #ifndef NOBITFIELD + void put_bf(struct type*, arith); + #endif /* NOBITFIELD */ + int zero_bytes(struct sdef*); + int valid_type(struct type*, char*); + void con_int(struct expr*); + void illegal_init_cst(struct expr*); + void too_many_initialisers(void); } /* initial_value recursively guides the initialisation expression. */ /* 3.5 */ -initial_value(struct type **tpp; struct expr **expp;) : - { if (tpp) gen_tpcheck(tpp); } -[ - { if (pack_level == 0) gen_error = 0; } - assignment_expression(expp) - { -#ifdef LINT - lint_expr(*expp, USED); -#endif /* LINT */ - if ((*expp)->ex_type->tp_fund == ARRAY) - array2pointer(*expp); - if (tpp) { - if (level >= L_LOCAL - || is_ld_cst(*expp) - || is_fp_cst(*expp) - || (*expp)->ex_class == String) { - gen_simple_exp(tpp, expp); - free_expression(*expp); - *expp = 0; - } else { - expr_error(*expp,"illegal initialization"); - free_expression(*expp); - *expp = 0; - } - } - } -| - initial_value_pack(tpp, expp) -] -; - -initial_value_pack(struct type **tpp; struct expr **expp;) -: - '{' - { if (pack_level == 0) gen_error = 0; pack_level++; } - initial_value_list(tpp, expp) - { pack_level--; - if (!pack_level) { - while (p_stack) { - struct e_stack *p = p_stack->next; - - free_e_stack(p_stack); - p_stack = p; - } - } - if (pack_level < gen_error) gen_error = 0; - } - '}' -; - -initial_value_list(struct type **tpp; struct expr **expp;) - { struct expr *e1; - struct type **tpp2 = 0; - int err_flag = gen_error; - } -: - { if (tpp) tpp2 = gen_tphead(tpp, 0); } - initial_value(tpp2, &e1) - { if (!tpp) init_expression(&expp, e1); } - [%while (AHEAD != '}') /* >>> conflict on ',' */ - ',' - { if (tpp) tpp2 = gen_tpmiddle(); } - initial_value(tpp2, &e1) - { if (!tpp) init_expression(&expp, e1); } - ]* - { if (tpp && ! err_flag) gen_tpend(); } - ','? /* optional trailing comma */ -; - -{ -void gen_tpcheck(struct type **tpp) -{ - struct type *tp; - - if (gen_error) return; - switch((tp = *tpp)->tp_fund) { - case ARRAY: - if (! valid_type(tp->tp_up, "array element")) - gen_error = pack_level; - break; - case STRUCT: - if (! valid_type(tp, "struct")) - gen_error = pack_level; - break; - case UNION: - if (! valid_type(tp, "union")) - gen_error = pack_level; - break; - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - break; - } -} - -void gen_simple_exp(struct type **tpp, struct expr **expp) -{ - struct type *tp; - - if (gen_error) return; - tp = *tpp; - switch(tp->tp_fund) { - case ARRAY: - if ((*expp)->ex_class == String && tp->tp_up->tp_fund == CHAR) { - ch_array(tpp,*expp); - break; - } - /* Fall through */ - case UNION: - case STRUCT: - check_and_pad(expp, tpp); - break; - case ERRONEOUS: - case FUNCTION: - case VOID: - gen_error = pack_level; - break; - default: - check_ival(expp, tp); - break; - } -} - -struct type **arr_elem(struct type **tpp, struct e_stack *p) -{ - struct type *tp = *tpp; - - if (tp->tp_up->tp_fund == CHAR && AHEAD == STRING && p->elem_count == 1) { - p->nelem = 1; - return tpp; - } - if (AHEAD == '{' || (! aggregate_type(tp->tp_up) && tp->tp_up->tp_fund != UNION)) - return &(tp->tp_up); - return gen_tphead(&(tp->tp_up), 1); -} - -struct sdef *next_field(struct sdef *sd, - struct e_stack *p) -{ - if (sd->sd_sdef) - p->bytes_upto_here += zero_bytes(sd); - p->bytes_upto_here += - size_of_type(sd->sd_type, "selector"); - p->last_offset = sd->sd_offset; - return sd->sd_sdef; -} - -struct type **gen_tphead(struct type **tpp, int nest) -{ - struct type *tp = *tpp; - struct e_stack *p; - struct sdef *sd; - - if (tpp && *tpp == error_type) { - gen_error = pack_level; - return 0; - } - if (gen_error) return tpp; - if (tp->tp_fund == UNION) { - /* Here, we saw a {, which could be the start of a union - initializer. It could, however, also be the start of the - initializer for the first union field ... - */ - sd = tp->tp_sdef; - if (AHEAD != '{' && - (aggregate_type(sd->sd_type) || - sd->sd_type->tp_fund == UNION)) { - /* In this case, assume that it is the start of the - initializer of the union field, so: - */ - return gen_tphead(&(tp->tp_sdef->sd_type), nest); - } - } - p = new_e_stack(); - p->next = p_stack; - p_stack = p; - p->s_nested = nest; - p->s_tpp = tpp; - switch(tp->tp_fund) { - case UNION: - p->s_def = sd = tp->tp_sdef; - p->bytes_upto_here = 0; - return &(sd->sd_type); - case ARRAY: - p->nelem = -1; - p->elem_count = 1; - if (tp->tp_size != (arith) -1) { - p->nelem = (tp->tp_size / tp->tp_up->tp_size); - } - return arr_elem(tpp, p); - case STRUCT: - p->s_def = sd = tp->tp_sdef; - p->bytes_upto_here = 0; - p->last_offset = -1; -#ifndef NOBITFIELD - while (sd && is_anon_idf(sd->sd_idf)) { - put_bf(sd->sd_type, (arith) 0); - sd = next_field(sd, p); - } -#endif - if (! sd) { - /* something wrong with this struct */ - gen_error = pack_level; - p_stack = p->next; - free_e_stack(p); - return 0; - } - p->s_def = sd; - if (AHEAD != '{' && aggregate_type(sd->sd_type)) { - return gen_tphead(&(sd->sd_type), 1); - } - return &(sd->sd_type); - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - /* fall through */ - default: - p->nelem = 1; - p->elem_count = 1; - return tpp; - } -} - -struct type **gen_tpmiddle(void) -{ - struct type *tp; - struct sdef *sd; - struct e_stack *p = p_stack; - - if (gen_error) { - if (p) return p->s_tpp; - return 0; - } -again: - tp = *(p->s_tpp); - switch(tp->tp_fund) { - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - return p->s_tpp; - case UNION: - sd = p->s_def; - p->bytes_upto_here += - size_of_type(sd->sd_type, "selector"); - return p->s_tpp; - default: - if (p->elem_count == p->nelem && p->s_nested) { - p = p->next; - free_e_stack(p_stack); - p_stack = p; - goto again; - } - p->elem_count++; - if (p->nelem >= 0 && p->elem_count > p->nelem) { - too_many_initialisers(); - return p->s_tpp; - } - if (tp->tp_fund == ARRAY) { - return arr_elem(p->s_tpp, p); - } - return p->s_tpp; - case STRUCT: - sd = gen_align_to_next(p); - if (! sd) { - while (p->bytes_upto_here++ < tp->tp_size) - con_nullbyte(); - if (p->s_nested) { - p = p->next; - free_e_stack(p_stack); - p_stack = p; - goto again; - } - too_many_initialisers(); - return p->s_tpp; - } - if (AHEAD != '{' && aggregate_type(sd->sd_type)) { - return gen_tphead(&(sd->sd_type), 1); - } - return &(sd->sd_type); - } -} - -struct sdef *gen_align_to_next(struct e_stack *p) -{ - struct sdef *sd = p->s_def; - - if (! sd) return sd; -#ifndef NOBITFIELD - do { - if (is_anon_idf(sd->sd_idf)) put_bf(sd->sd_type, (arith) 0); -#endif - sd = next_field(sd, p); -#ifndef NOBITFIELD - } while (sd && is_anon_idf(sd->sd_idf)); -#endif - p->s_def = sd; - return sd; -} - -void gen_tpend(void) -{ - struct e_stack *p = p_stack; - struct type *tp; - struct sdef *sd; - int getout = 0; - - while (!getout && p) { - if (!gen_error) { - tp = *(p->s_tpp); - switch(tp->tp_fund) { - case UNION: - sd = p->s_def; - p->bytes_upto_here += - size_of_type(sd->sd_type, "selector"); - while (p->bytes_upto_here++ < tp->tp_size) - con_nullbyte(); - break; - case ARRAY: - if (tp->tp_size == -1) { - *(p->s_tpp) = construct_type(ARRAY, tp->tp_up, - 0, p->elem_count, NO_PROTO); - } - else { - while (p->nelem-- > p->elem_count) { - pad(tp->tp_up); - } - } - break; - case STRUCT: - sd = gen_align_to_next(p); - while (sd) { - pad(sd->sd_type); - if (sd->sd_sdef) - p->bytes_upto_here += zero_bytes(sd); - p->bytes_upto_here += - size_of_type(sd->sd_type, "selector"); - sd = sd->sd_sdef; - } - while (p->bytes_upto_here++ < tp->tp_size) - con_nullbyte(); - break; - } - } - if (! p->s_nested) getout = 1; - p = p->next; - free_e_stack(p_stack); - p_stack = p; - } -} - -/* check_and_pad() is given a simple initialisation expression - where the type can be either a simple or an aggregate type. - In the latter case, only the first member is initialised and - the rest is zeroed. -*/ -void check_and_pad(struct expr **expp, struct type **tpp) -{ - struct type *tp = *tpp; - - if (tp->tp_fund == ARRAY) { - check_and_pad(expp, &(tp->tp_up)); /* first member */ - if (tp->tp_size == (arith)-1) - /* no size specified upto here: just - set it to the size of one member. - */ - tp = *tpp = construct_type(ARRAY, tp->tp_up, - 0, (arith)1, NO_PROTO); - else { - int dim = tp->tp_size / tp->tp_up->tp_size; - /* pad remaining members with zeroes */ - while (--dim > 0) - pad(tp->tp_up); - } - } - else - if (tp->tp_fund == STRUCT) { - struct sdef *sd = tp->tp_sdef; - - check_and_pad(expp, &(sd->sd_type)); - /* next selector is aligned by adding extra zeroes */ - if (sd->sd_sdef) - zero_bytes(sd); - while ( (sd = sd->sd_sdef)!=0) { /* pad remaining selectors */ - pad(sd->sd_type); - if (sd->sd_sdef) - zero_bytes(sd); - } - } - else if (tp->tp_fund == UNION) { - /* only the first selector can be initialized */ - struct sdef *sd = tp->tp_sdef; - - check_and_pad(expp, &(sd->sd_type)); - } - else /* simple type */ - check_ival(expp, tp); -} - -/* pad() fills an element of type tp with zeroes. - If the element is an aggregate, pad() is called recursively. -*/ -void pad(struct type *tpx) -{ - struct type *tp = tpx; - arith sz = tp->tp_size; - - gen_tpcheck(&tpx); - if (gen_error) return; -#ifndef NOBITFIELD - if (tp->tp_fund == FIELD) { - put_bf(tp, (arith)0); - return; - } -#endif /* NOBITFIELD */ - - if (tp->tp_align >= word_align) while (sz >= word_size) { - C_con_cst((arith) 0); - sz -= word_size; - } - while (sz) { - C_con_icon("0", (arith) 1); - sz--; - } -} +initial_value(struct type** tpp; struct expr** expp;) + : + { if (tpp) gen_tpcheck(tpp); } + [ + { if (pack_level == 0) gen_error = 0; } + assignment_expression(expp) + { + #ifdef LINT + lint_expr(*expp, USED); + #endif /* LINT */ + if ((*expp)->ex_type->tp_fund == ARRAY) + array2pointer(*expp); + if (tpp) + { + if (level >= L_LOCAL || is_ld_cst(*expp) || is_fp_cst(*expp) + || (*expp)->ex_class == String) + { + gen_simple_exp(tpp, expp); + free_expression(*expp); + *expp = 0; + } + else + { + expr_error(*expp, "illegal initialization"); + free_expression(*expp); + *expp = 0; + } + } + } + | initial_value_pack(tpp, expp) + ] + ; + +initial_value_pack(struct type** tpp; struct expr** expp;) + : '{' + { + if (pack_level == 0) + gen_error = 0; + pack_level++; + } + initial_value_list(tpp, expp) + { + pack_level--; + if (!pack_level) + { + while (p_stack) + { + struct e_stack* p = p_stack->next; + + free_e_stack(p_stack); + p_stack = p; + } + } + if (pack_level < gen_error) + gen_error = 0; + } + '}' + ; + +initial_value_list(struct type** tpp; struct expr** expp;) + { + struct expr* e1; + struct type** tpp2 = 0; + int err_flag = gen_error; + } + : + { if (tpp) tpp2 = gen_tphead(tpp, 0); } + initial_value(tpp2, &e1) + { if (!tpp) init_expression(&expp, e1); } + [ + %while (AHEAD != '}') + /* >>> conflict on ',' */ + ',' + { if (tpp) tpp2 = gen_tpmiddle(); } + initial_value(tpp2, &e1) + { if (!tpp) init_expression(&expp, e1); } + ]* + { if (tpp && !err_flag) gen_tpend(); } + ','? + /* optional trailing comma */ + ; -/* check_ival() checks whether the initialisation of an element - of a fundamental type is legal and, if so, performs the initialisation - by directly generating the necessary code. - No further comment is needed to explain the internal structure - of this straightforward function. -*/ -void check_ival(struct expr **expp, struct type *tp) { - /* The philosophy here is that ch3cast puts an explicit - conversion node in front of the expression if the types - are not compatible. In this case, the initialisation - expression is no longer a constant. - */ - struct expr *expr = *expp; - - switch (tp->tp_fund) { - case CHAR: - case SHORT: - case INT: - case LONG: - case LNGLNG: - case ENUM: - case POINTER: - ch3cast(expp, '=', tp); - expr = *expp; -#ifdef DEBUG - print_expr("init-expr after cast", expr); -#endif /* DEBUG */ - if (!is_ld_cst(expr)) - illegal_init_cst(expr); - else - if (expr->VL_CLASS == Const) - con_int(expr); - else - if (expr->VL_CLASS == Name) { - struct idf *idf = expr->VL_IDF; - - if (idf->id_def->df_level >= L_LOCAL - && idf->id_def->df_sc != GLOBAL - && idf->id_def->df_sc != EXTERN) { - illegal_init_cst(expr); - } - else /* e.g., int f(); int p = f; */ - if (idf->id_def->df_type->tp_fund == FUNCTION) - C_con_pnam(idf->id_text); - else /* e.g., int a; int *p = &a; */ - C_con_dnam(idf->id_text, (arith)expr->VL_VALUE); - } - else { - assert(expr->VL_CLASS == Label); - C_con_dlb(expr->VL_LBL, (arith)expr->VL_VALUE); - } - break; - case FLOAT: - case DOUBLE: - case LNGDBL: - ch3cast(expp, '=', tp); - expr = *expp; -#ifdef DEBUG - print_expr("init-expr after cast", expr); -#endif /* DEBUG */ - if (expr->ex_class == Float) { - char buf[FLT_STRLEN]; - - flt_flt2str(&(expr->FL_ARITH), buf, FLT_STRLEN); - C_con_fcon(buf, expr->ex_type->tp_size); - } -#ifdef NOTDEF - -Coercion from int to float is now always done compile time. -This, to accept declarations like -double x = -(double)1; + void gen_tpcheck(struct type** tpp) + { + struct type* tp; + + if (gen_error) + return; + switch ((tp = *tpp)->tp_fund) + { + case ARRAY: + if (!valid_type(tp->tp_up, "array element")) + gen_error = pack_level; + break; + case STRUCT: + if (!valid_type(tp, "struct")) + gen_error = pack_level; + break; + case UNION: + if (!valid_type(tp, "union")) + gen_error = pack_level; + break; + case ERRONEOUS: + if (!gen_error) + gen_error = pack_level; + break; + } + } + + void gen_simple_exp(struct type** tpp, struct expr** expp) + { + struct type* tp; + + if (gen_error) + return; + tp = *tpp; + switch (tp->tp_fund) + { + case ARRAY: + if ((*expp)->ex_class == String && tp->tp_up->tp_fund == CHAR) + { + ch_array(tpp, *expp); + break; + } + /* Fall through */ + case UNION: + case STRUCT: + check_and_pad(expp, tpp); + break; + case ERRONEOUS: + case FUNCTION: + case VOID: + gen_error = pack_level; + break; + default: + check_ival(expp, tp); + break; + } + } + + struct type** arr_elem(struct type** tpp, struct e_stack* p) + { + struct type* tp = *tpp; + + if (tp->tp_up->tp_fund == CHAR && AHEAD == STRING && p->elem_count == 1) + { + p->nelem = 1; + return tpp; + } + if (AHEAD == '{' || (!aggregate_type(tp->tp_up) && tp->tp_up->tp_fund != UNION)) + return &(tp->tp_up); + return gen_tphead(&(tp->tp_up), 1); + } + + struct sdef* next_field(struct sdef* sd, struct e_stack* p) + { + if (sd->sd_sdef) + p->bytes_upto_here += zero_bytes(sd); + p->bytes_upto_here += size_of_type(sd->sd_type, "selector"); + p->last_offset = sd->sd_offset; + return sd->sd_sdef; + } + + struct type** gen_tphead(struct type** tpp, int nest) + { + struct type* tp = *tpp; + struct e_stack* p; + struct sdef* sd; + + if (tpp && *tpp == error_type) + { + gen_error = pack_level; + return 0; + } + if (gen_error) + return tpp; + if (tp->tp_fund == UNION) + { + /* Here, we saw a {, which could be the start of a union + initializer. It could, however, also be the start of the + initializer for the first union field ... + */ + sd = tp->tp_sdef; + if (AHEAD != '{' && (aggregate_type(sd->sd_type) || sd->sd_type->tp_fund == UNION)) + { + /* In this case, assume that it is the start of the + initializer of the union field, so: + */ + return gen_tphead(&(tp->tp_sdef->sd_type), nest); + } + } + p = new_e_stack(); + p->next = p_stack; + p_stack = p; + p->s_nested = nest; + p->s_tpp = tpp; + switch (tp->tp_fund) + { + case UNION: + p->s_def = sd = tp->tp_sdef; + p->bytes_upto_here = 0; + return &(sd->sd_type); + case ARRAY: + p->nelem = -1; + p->elem_count = 1; + if (tp->tp_size != (arith)-1) + { + p->nelem = (tp->tp_size / tp->tp_up->tp_size); + } + return arr_elem(tpp, p); + case STRUCT: + p->s_def = sd = tp->tp_sdef; + p->bytes_upto_here = 0; + p->last_offset = -1; + #ifndef NOBITFIELD + while (sd && is_anon_idf(sd->sd_idf)) + { + put_bf(sd->sd_type, (arith)0); + sd = next_field(sd, p); + } + #endif + if (!sd) + { + /* something wrong with this struct */ + gen_error = pack_level; + p_stack = p->next; + free_e_stack(p); + return 0; + } + p->s_def = sd; + if (AHEAD != '{' && aggregate_type(sd->sd_type)) + { + return gen_tphead(&(sd->sd_type), 1); + } + return &(sd->sd_type); + case ERRONEOUS: + if (!gen_error) + gen_error = pack_level; + /* fall through */ + default: + p->nelem = 1; + p->elem_count = 1; + return tpp; + } + } + + struct type** gen_tpmiddle(void) + { + struct type* tp; + struct sdef* sd; + struct e_stack* p = p_stack; + + if (gen_error) + { + if (p) + return p->s_tpp; + return 0; + } + again: + tp = *(p->s_tpp); + switch (tp->tp_fund) + { + case ERRONEOUS: + if (!gen_error) + gen_error = pack_level; + return p->s_tpp; + case UNION: + sd = p->s_def; + p->bytes_upto_here += size_of_type(sd->sd_type, "selector"); + return p->s_tpp; + default: + if (p->elem_count == p->nelem && p->s_nested) + { + p = p->next; + free_e_stack(p_stack); + p_stack = p; + goto again; + } + p->elem_count++; + if (p->nelem >= 0 && p->elem_count > p->nelem) + { + too_many_initialisers(); + return p->s_tpp; + } + if (tp->tp_fund == ARRAY) + { + return arr_elem(p->s_tpp, p); + } + return p->s_tpp; + case STRUCT: + sd = gen_align_to_next(p); + if (!sd) + { + while (p->bytes_upto_here++ < tp->tp_size) + con_nullbyte(); + if (p->s_nested) + { + p = p->next; + free_e_stack(p_stack); + p_stack = p; + goto again; + } + too_many_initialisers(); + return p->s_tpp; + } + if (AHEAD != '{' && aggregate_type(sd->sd_type)) + { + return gen_tphead(&(sd->sd_type), 1); + } + return &(sd->sd_type); + } + } + + struct sdef* gen_align_to_next(struct e_stack* p) + { + struct sdef* sd = p->s_def; + + if (!sd) + return sd; + #ifndef NOBITFIELD + do + { + if (is_anon_idf(sd->sd_idf)) + put_bf(sd->sd_type, (arith)0); + #endif + sd = next_field(sd, p); + #ifndef NOBITFIELD + } while (sd && is_anon_idf(sd->sd_idf)); + #endif + p->s_def = sd; + return sd; + } + + void gen_tpend(void) + { + struct e_stack* p = p_stack; + struct type* tp; + struct sdef* sd; + int getout = 0; + + while (!getout && p) + { + if (!gen_error) + { + tp = *(p->s_tpp); + switch (tp->tp_fund) + { + case UNION: + sd = p->s_def; + p->bytes_upto_here += size_of_type(sd->sd_type, "selector"); + while (p->bytes_upto_here++ < tp->tp_size) + con_nullbyte(); + break; + case ARRAY: + if (tp->tp_size == -1) + { + *(p->s_tpp) + = construct_type(ARRAY, tp->tp_up, 0, p->elem_count, NO_PROTO); + } + else + { + while (p->nelem-- > p->elem_count) + { + pad(tp->tp_up); + } + } + break; + case STRUCT: + sd = gen_align_to_next(p); + while (sd) + { + pad(sd->sd_type); + if (sd->sd_sdef) + p->bytes_upto_here += zero_bytes(sd); + p->bytes_upto_here += size_of_type(sd->sd_type, "selector"); + sd = sd->sd_sdef; + } + while (p->bytes_upto_here++ < tp->tp_size) + con_nullbyte(); + break; + } + } + if (!p->s_nested) + getout = 1; + p = p->next; + free_e_stack(p_stack); + p_stack = p; + } + } + + /* check_and_pad() is given a simple initialisation expression + where the type can be either a simple or an aggregate type. + In the latter case, only the first member is initialised and + the rest is zeroed. + */ + void check_and_pad(struct expr** expp, struct type** tpp) + { + struct type* tp = *tpp; + + if (tp->tp_fund == ARRAY) + { + check_and_pad(expp, &(tp->tp_up)); /* first member */ + if (tp->tp_size == (arith)-1) + /* no size specified upto here: just + set it to the size of one member. + */ + tp = *tpp = construct_type(ARRAY, tp->tp_up, 0, (arith)1, NO_PROTO); + else + { + int dim = tp->tp_size / tp->tp_up->tp_size; + /* pad remaining members with zeroes */ + while (--dim > 0) + pad(tp->tp_up); + } + } + else if (tp->tp_fund == STRUCT) + { + struct sdef* sd = tp->tp_sdef; + + check_and_pad(expp, &(sd->sd_type)); + /* next selector is aligned by adding extra zeroes */ + if (sd->sd_sdef) + zero_bytes(sd); + while ((sd = sd->sd_sdef) != 0) + { /* pad remaining selectors */ + pad(sd->sd_type); + if (sd->sd_sdef) + zero_bytes(sd); + } + } + else if (tp->tp_fund == UNION) + { + /* only the first selector can be initialized */ + struct sdef* sd = tp->tp_sdef; + + check_and_pad(expp, &(sd->sd_type)); + } + else /* simple type */ + check_ival(expp, tp); + } + + /* pad() fills an element of type tp with zeroes. + If the element is an aggregate, pad() is called recursively. + */ + void pad(struct type* tpx) + { + struct type* tp = tpx; + arith sz = tp->tp_size; + + gen_tpcheck(&tpx); + if (gen_error) + return; + #ifndef NOBITFIELD + if (tp->tp_fund == FIELD) + { + put_bf(tp, (arith)0); + return; + } + #endif /* NOBITFIELD */ + + if (tp->tp_align >= word_align) + while (sz >= word_size) + { + C_con_cst((arith)0); + sz -= word_size; + } + while (sz) + { + C_con_icon("0", (arith)1); + sz--; + } + } + + /* check_ival() checks whether the initialisation of an element + of a fundamental type is legal and, if so, performs the initialisation + by directly generating the necessary code. + No further comment is needed to explain the internal structure + of this straightforward function. + */ + void check_ival(struct expr** expp, struct type* tp) + { + /* The philosophy here is that ch3cast puts an explicit + conversion node in front of the expression if the types + are not compatible. In this case, the initialisation + expression is no longer a constant. + */ + struct expr* expr = *expp; + + switch (tp->tp_fund) + { + case CHAR: + case SHORT: + case INT: + case LONG: + case LNGLNG: + case ENUM: + case POINTER: + ch3cast(expp, '=', tp); + expr = *expp; + #ifdef DEBUG + print_expr("init-expr after cast", expr); + #endif /* DEBUG */ + if (!is_ld_cst(expr)) + illegal_init_cst(expr); + else if (expr->VL_CLASS == Const) + con_int(expr); + else if (expr->VL_CLASS == Name) + { + struct idf* idf = expr->VL_IDF; + + if (idf->id_def->df_level >= L_LOCAL && idf->id_def->df_sc != GLOBAL + && idf->id_def->df_sc != EXTERN) + { + illegal_init_cst(expr); + } + else /* e.g., int f(); int p = f; */ + if (idf->id_def->df_type->tp_fund == FUNCTION) + C_con_pnam(idf->id_text); + else /* e.g., int a; int *p = &a; */ + C_con_dnam(idf->id_text, (arith)expr->VL_VALUE); + } + else + { + assert(expr->VL_CLASS == Label); + C_con_dlb(expr->VL_LBL, (arith)expr->VL_VALUE); + } + break; + case FLOAT: + case DOUBLE: + case LNGDBL: + ch3cast(expp, '=', tp); + expr = *expp; + #ifdef DEBUG + print_expr("init-expr after cast", expr); + #endif /* DEBUG */ + if (expr->ex_class == Float) + { + char buf[FLT_STRLEN]; + + flt_flt2str(&(expr->FL_ARITH), buf, FLT_STRLEN); + C_con_fcon(buf, expr->ex_type->tp_size); + } + #ifdef NOTDEF + + Coercion from int to float is now always done compile time.This, + to accept declarations like double x = -(double)1; and also to prevent runtime coercions for compile-time constants. else - if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) { - /* float f = 1; */ - expr = expr->OP_RIGHT; - if (is_cp_cst(expr)) - C_con_fcon(long2str((long)expr->VL_VALUE, 10), - tp->tp_size); - else - illegal_init_cst(expr); - } -#endif /* NOTDEF */ - else - illegal_init_cst(expr); - break; - -#ifndef NOBITFIELD - case FIELD: - ch3cast(expp, '=', tp->tp_up); - expr = *expp; -#ifdef DEBUG - print_expr("init-expr after cast", expr); -#endif /* DEBUG */ - if (is_cp_cst(expr)) - put_bf(tp, (arith)expr->VL_VALUE); - else - illegal_init_cst(expr); - break; -#endif /* NOBITFIELD */ - - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - /* fall through */ - case VOID: - break; - default: - crash("check_ival"); - /*NOTREACHED*/ - } -} - -/* ch_array() initialises an array of characters when given - a string constant. - Alignment is taken care of. -*/ -void ch_array(struct type **tpp, /* type tp = array of characters */ - struct expr *ex) -{ - struct type *tp = *tpp; - int length = ex->SG_LEN, i; - char *to, *from, *s; - - assert(ex->ex_class == String); - if (tp->tp_size == (arith)-1) { - /* set the dimension */ - tp = *tpp = construct_type(ARRAY, tp->tp_up, 0, (arith)length, NO_PROTO); - } - else { - arith dim = tp->tp_size / tp->tp_up->tp_size; - -#ifdef LINT - if (length == dim + 1) { - expr_warning(ex, "array is not null-terminated"); - } else -#endif - if (length > dim + 1) { - expr_strict(ex, "too many initializers"); - } - length = dim; - } - /* throw out the characters of the already prepared string */ - s = calloc((unsigned) (length), 1); - i = length <= ex->SG_LEN ? length : ex->SG_LEN; - to = s; from = ex->SG_VALUE; - while(--i >= 0) { - *to++ = *from++; - } - free(ex->SG_VALUE); - str_cst(s, length, 0); /* a string, but not in rom */ - free(s); -} - -/* As long as some parts of the pipeline cannot handle very long string - constants, string constants are written out in chunks -*/ -void str_cst(char *str, int len, int inrom) -{ - int chunksize = ((127 + (int) word_size) / (int) word_size) * (int) word_size; - - while (len > chunksize) { - if (inrom) - C_rom_scon(str, (arith) chunksize); - else C_con_scon(str, (arith) chunksize); - len -= chunksize; - str += chunksize; - } - if (inrom) - C_rom_scon(str, (arith) len); - else C_con_scon(str, (arith) len); -} - -#ifndef NOBITFIELD -/* put_bf() takes care of the initialisation of (bit-)field - selectors of a struct: each time such an initialisation takes place, - put_bf() is called instead of the normal code generating routines. - Put_bf() stores the given integral value into "field" and - "throws" the result of "field" out if the current selector - is the last of this number of fields stored at the same address. -*/ -void put_bf(struct type *tp, arith val) -{ - static long field = (arith)0; - static arith offset = (arith)-1; - struct field *fd = tp->tp_field; - struct sdef *sd = fd->fd_sdef; - static struct expr exp; - - assert(sd); - if (offset == (arith)-1) { - /* first bitfield in this field */ - offset = sd->sd_offset; - exp.ex_type = tp->tp_up; - exp.ex_class = Value; - exp.VL_CLASS = Const; - } - if (val != 0) /* insert the value into "field" */ - field |= (val & fd->fd_mask) << fd->fd_shift; - if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) { - /* the selector was the last stored at this address */ - exp.VL_VALUE = (writh)field; - con_int(&exp); - field = (arith)0; - offset = (arith)-1; - } -} -#endif /* NOBITFIELD */ - -int zero_bytes(struct sdef *sd) -{ - /* fills the space between a selector of a struct - and the next selector of that struct with zero-bytes. - */ - int n = sd->sd_sdef->sd_offset - sd->sd_offset - - size_of_type(sd->sd_type, "struct member"); - int count = n; - - while (n-- > 0) - con_nullbyte(); - return count; -} - -int valid_type(struct type *tp, char *str) -{ - assert(tp!=(struct type *)0); - if (tp->tp_size < 0) { - error("size of %s unknown", str); - return 0; - } - return 1; -} - -void con_int(struct expr *ex) -{ - struct type *tp = ex->ex_type; - - assert(is_cp_cst(ex)); - if (tp->tp_unsigned) - C_con_ucon(writh2str(ex->VL_VALUE, 1), tp->tp_size); - else if (tp->tp_size == word_size) - C_con_cst((arith)ex->VL_VALUE); - else - C_con_icon(writh2str(ex->VL_VALUE, 0), tp->tp_size); -} - -void illegal_init_cst(struct expr *ex) -{ - expr_error(ex, "illegal initialization constant"); - gen_error = pack_level; -} - -void too_many_initialisers(void) + if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) { - error("too many initializers"); - gen_error = pack_level; + /* float f = 1; */ + expr = expr->OP_RIGHT; + if (is_cp_cst(expr)) + C_con_fcon(long2str((long)expr->VL_VALUE, 10), tp->tp_size); + else + illegal_init_cst(expr); } + #endif /* NOTDEF */ +else illegal_init_cst(expr); +break; + + #ifndef NOBITFIELD + case FIELD: + ch3cast(expp, '=', tp->tp_up); + expr = *expp; + #ifdef DEBUG + print_expr("init-expr after cast", expr); + #endif /* DEBUG */ + if (is_cp_cst(expr)) + put_bf(tp, (arith)expr->VL_VALUE); + else + illegal_init_cst(expr); + break; + #endif /* NOBITFIELD */ + + case ERRONEOUS: + if (!gen_error) + gen_error = pack_level; + /* fall through */ + case VOID: + break; + default: + crash("check_ival"); + /*NOTREACHED*/ + } + } + + /* ch_array() initialises an array of characters when given + a string constant. + Alignment is taken care of. + */ + void ch_array(struct type** tpp, /* type tp = array of characters */ + struct expr* ex) + { + struct type* tp = *tpp; + int length = ex->SG_LEN, i; + char *to, *from, *s; + + assert(ex->ex_class == String); + if (tp->tp_size == (arith)-1) + { + /* set the dimension */ + tp = *tpp = construct_type(ARRAY, tp->tp_up, 0, (arith)length, NO_PROTO); + } + else + { + arith dim = tp->tp_size / tp->tp_up->tp_size; + + #ifdef LINT + if (length == dim + 1) + { + expr_warning(ex, "array is not null-terminated"); + } + else + #endif + if (length > dim + 1) + { + expr_strict(ex, "too many initializers"); + } + length = dim; + } + /* throw out the characters of the already prepared string */ + s = calloc((unsigned)(length), 1); + i = length <= ex->SG_LEN ? length : ex->SG_LEN; + to = s; + from = ex->SG_VALUE; + while (--i >= 0) + { + *to++ = *from++; + } + free(ex->SG_VALUE); + str_cst(s, length, 0); /* a string, but not in rom */ + free(s); + } + + /* As long as some parts of the pipeline cannot handle very long string + constants, string constants are written out in chunks + */ + void str_cst(char* str, int len, int inrom) + { + int chunksize = ((127 + (int)word_size) / (int)word_size) * (int)word_size; + + while (len > chunksize) + { + if (inrom) + C_rom_scon(str, (arith)chunksize); + else + C_con_scon(str, (arith)chunksize); + len -= chunksize; + str += chunksize; + } + if (inrom) + C_rom_scon(str, (arith)len); + else + C_con_scon(str, (arith)len); + } + + #ifndef NOBITFIELD + /* put_bf() takes care of the initialisation of (bit-)field + selectors of a struct: each time such an initialisation takes place, + put_bf() is called instead of the normal code generating routines. + Put_bf() stores the given integral value into "field" and + "throws" the result of "field" out if the current selector + is the last of this number of fields stored at the same address. + */ + void put_bf(struct type* tp, arith val) + { + static long field = (arith)0; + static arith offset = (arith)-1; + struct field* fd = tp->tp_field; + struct sdef* sd = fd->fd_sdef; + static struct expr exp; + + assert(sd); + if (offset == (arith)-1) + { + /* first bitfield in this field */ + offset = sd->sd_offset; + exp.ex_type = tp->tp_up; + exp.ex_class = Value; + exp.VL_CLASS = Const; + } + if (val != 0) /* insert the value into "field" */ + field |= (val & fd->fd_mask) << fd->fd_shift; + if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) + { + /* the selector was the last stored at this address */ + exp.VL_VALUE = (writh)field; + con_int(&exp); + field = (arith)0; + offset = (arith)-1; + } + } + #endif /* NOBITFIELD */ + + int zero_bytes(struct sdef* sd) + { + /* fills the space between a selector of a struct + and the next selector of that struct with zero-bytes. + */ + int n = sd->sd_sdef->sd_offset - sd->sd_offset - size_of_type(sd->sd_type, "struct member"); + int count = n; + + while (n-- > 0) + con_nullbyte(); + return count; + } + + int valid_type(struct type* tp, char* str) + { + assert(tp != (struct type*)0); + if (tp->tp_size < 0) + { + error("size of %s unknown", str); + return 0; + } + return 1; + } + + void con_int(struct expr* ex) + { + struct type* tp = ex->ex_type; + + assert(is_cp_cst(ex)); + if (tp->tp_unsigned) + C_con_ucon(writh2str(ex->VL_VALUE, 1), tp->tp_size); + else if (tp->tp_size == word_size) + C_con_cst((arith)ex->VL_VALUE); + else + C_con_icon(writh2str(ex->VL_VALUE, 0), tp->tp_size); + } + + void illegal_init_cst(struct expr* ex) + { + expr_error(ex, "illegal initialization constant"); + gen_error = pack_level; + } + + void too_many_initialisers(void) + { + error("too many initializers"); + gen_error = pack_level; + } } diff --git a/lang/cem/cemcom.ansi/program.g b/lang/cem/cemcom.ansi/program.g index 07f1df549..ac0925296 100644 --- a/lang/cem/cemcom.ansi/program.g +++ b/lang/cem/cemcom.ansi/program.g @@ -2,228 +2,241 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cemcom.ansi/program.g + */ /* $Id$ */ /* PROGRAM PARSER */ /* The presence of typedef declarations renders it impossible to - make a context-free grammar of C. Consequently we need - context-sensitive parsing techniques, the simplest one being - a subtle cooperation between the parser and the lexical scanner. - The lexical scanner has to know whether to return IDENTIFIER - or TYPE_IDENTIFIER for a given tag, and it obtains this information - from the definition list, as constructed by the parser. - The present grammar is essentially LL(2), and is processed by - a parser generator which accepts LL(1) with tie breaking rules - in C, of the form %if(cond) and %while(cond). To solve the LL(1) - ambiguities, the lexical scanner does a one symbol look-ahead. - This symbol, however, cannot always be correctly assessed, since - the present symbol may cause a change in the definition list - which causes the identification of the look-ahead symbol to be - invalidated. - The lexical scanner relies on the parser (or its routines) to - detect this situation and then update the look-ahead symbol. - An alternative approach would be to reassess the look-ahead symbol - in the lexical scanner when it is promoted to dot symbol. This - would be more beautiful but less correct, since then for a short - while there would be a discrepancy between the look-ahead symbol - and the definition list; I think it would nevertheless work in - correct programs. - A third solution would be to enter the identifier as soon as it - is found; its storage class is then known, although its full type - isn't. We would have to fill that in afterwards. +make a context-free grammar of C. Consequently we need +context-sensitive parsing techniques, the simplest one being +a subtle cooperation between the parser and the lexical scanner. +The lexical scanner has to know whether to return IDENTIFIER +or TYPE_IDENTIFIER for a given tag, and it obtains this information +from the definition list, as constructed by the parser. +The present grammar is essentially LL(2), and is processed by +a parser generator which accepts LL(1) with tie breaking rules +in C, of the form %if(cond) and %while(cond). To solve the LL(1) +ambiguities, the lexical scanner does a one symbol look-ahead. +This symbol, however, cannot always be correctly assessed, since +the present symbol may cause a change in the definition list +which causes the identification of the look-ahead symbol to be +invalidated. +The lexical scanner relies on the parser (or its routines) to +detect this situation and then update the look-ahead symbol. +An alternative approach would be to reassess the look-ahead symbol +in the lexical scanner when it is promoted to dot symbol. This +would be more beautiful but less correct, since then for a short +while there would be a discrepancy between the look-ahead symbol +and the definition list; I think it would nevertheless work in +correct programs. +A third solution would be to enter the identifier as soon as it +is found; its storage class is then known, although its full type +isn't. We would have to fill that in afterwards. - At block exit the situation is even worse. Upon reading the - closing brace, the names declared inside the function are cleared - from the name list. This action may expose a type identifier that - is the same as the identifier in the look-ahead symbol. This - situation certainly invalidates the third solution, and casts - doubts upon the second. +At block exit the situation is even worse. Upon reading the +closing brace, the names declared inside the function are cleared +from the name list. This action may expose a type identifier that +is the same as the identifier in the look-ahead symbol. This +situation certainly invalidates the third solution, and casts +doubts upon the second. */ -%lexical LLlex; -%start C_program, program; -%start If_expr, control_if_expression; +%lexical LLlex; +%start C_program, program; +%start If_expr, control_if_expression; { -#include -#include -#include "parameters.h" -#include -#include "arith.h" -#include "LLlex.h" -#include "label.h" -#include "type.h" -#include "declar.h" -#include "decspecs.h" -#include "code.h" -#include "expr.h" -#include "def.h" -#include "idf.h" -#include "declarator.h" -#include "stack.h" -#include "proto.h" -#include "error.h" -#ifdef LINT -#include "l_lint.h" -#endif /* LINT */ - + #include + #include + #include "parameters.h" + #include + #include "arith.h" + #include "LLlex.h" + #include "label.h" + #include "type.h" + #include "declar.h" + #include "decspecs.h" + #include "code.h" + #include "expr.h" + #include "def.h" + #include "idf.h" + #include "declarator.h" + #include "stack.h" + #include "proto.h" + #include "error.h" + #ifdef LINT + #include "l_lint.h" + #endif /* LINT */ } control_if_expression - { - struct expr *exprX; - } -: - constant_expression(&exprX) - { - } -; + { + struct expr* exprX; + } + : constant_expression(&exprX) + {} + ; /* 3.7 */ -program: - [%persistent external_definition]* - { unstack_world(); } -; +program + : [ + %persistent + external_definition + ]* + { unstack_world(); } + ; /* A C identifier definition is remarkable in that it formulates - the declaration in a way different from most other languages: - e.g., rather than defining x as a pointer-to-integer, it defines - *x as an integer and lets the compiler deduce that x is actually - pointer-to-integer. This has profound consequences, both for the - structure of an identifier definition and for the compiler. - - A definition starts with a decl_specifiers, which contains things - like - typedef int - which is implicitly repeated for every definition in the list, and - then for each identifier a declarator is given, of the form - *a() - or so. The decl_specifiers is kept in a struct decspecs, to be - used again and again, while the declarator is stored in a struct - declarator, only to be passed to declare_idf together with the - struct decspecs. +the declaration in a way different from most other languages: +e.g., rather than defining x as a pointer-to-integer, it defines +*x as an integer and lets the compiler deduce that x is actually +pointer-to-integer. This has profound consequences, both for the +structure of an identifier definition and for the compiler. + +A definition starts with a decl_specifiers, which contains things +like +typedef int +which is implicitly repeated for every definition in the list, and +then for each identifier a declarator is given, of the form +*a() +or so. The decl_specifiers is kept in a struct decspecs, to be +used again and again, while the declarator is stored in a struct +declarator, only to be passed to declare_idf together with the +struct decspecs. - With the introduction of prototypes, extra problems for the scope - administration were introduced as well. We can have, for example, - int x(double x); - and - int x(double x) { ... use(x) ... } - In the first case, the parameter name can be forgotten, whereas in - the second case, the parameter should have a block scope. The - problem lies in the fact that the parameter's type is known before - the type of the function, which causes the def structure to be on - the end of the list. Our solution is as follows: - 1- In case of a declaration, throw the parameter identifier away - before the declaration of the outer x. - 2- In case of a definition, the function begin_proc() changes the - def list for the identifier. This means that declare_idf() - contains an extra test in case we already saw a declaration of - such a function, because this function is called before - begin_proc(). +With the introduction of prototypes, extra problems for the scope +administration were introduced as well. We can have, for example, +int x(double x); +and +int x(double x) { ... use(x) ... } +In the first case, the parameter name can be forgotten, whereas in +the second case, the parameter should have a block scope. The +problem lies in the fact that the parameter's type is known before +the type of the function, which causes the def structure to be on +the end of the list. Our solution is as follows: +1- In case of a declaration, throw the parameter identifier away +before the declaration of the outer x. +2- In case of a definition, the function begin_proc() changes the +def list for the identifier. This means that declare_idf() +contains an extra test in case we already saw a declaration of +such a function, because this function is called before +begin_proc(). */ external_definition - { struct decspecs Ds; - struct declarator Dc; - } -: - { Ds = null_decspecs; - Dc = null_declarator; - } - [ %if (DOT != IDENTIFIER || AHEAD == IDENTIFIER) - decl_specifiers(&Ds) - | - {do_decspecs(&Ds);} - ] - [ - declarator(&Dc) - { - declare_idf(&Ds, &Dc, level); -#ifdef LINT - lint_ext_def(Dc.dc_idf, Ds.ds_sc); -#endif /* LINT */ - } - [ - function(&Ds, &Dc) - | - { if (! Ds.ds_sc_given && ! Ds.ds_typequal && - Ds.ds_notypegiven) { - strict("declaration specifiers missing"); - } - } - non_function(&Ds, &Dc) - ] - | - { if (! Ds.ds_sc_given && ! Ds.ds_typequal && - Ds.ds_notypegiven) { - strict("declaration missing"); - } - } - ';' - ] - {remove_declarator(&Dc); flush_strings(); } -; + { + struct decspecs Ds; + struct declarator Dc; + } + : + { + Ds = null_decspecs; + Dc = null_declarator; + } + [ + %if (DOT != IDENTIFIER || AHEAD == IDENTIFIER) + decl_specifiers(&Ds) + | + { do_decspecs(&Ds); } + ] + [ + declarator(&Dc) + { + declare_idf(&Ds, &Dc, level); + #ifdef LINT + lint_ext_def(Dc.dc_idf, Ds.ds_sc); + #endif /* LINT */ + } + [ + function(&Ds, &Dc) + | + { + if (!Ds.ds_sc_given && !Ds.ds_typequal && Ds.ds_notypegiven) + { + strict("declaration specifiers missing"); + } + } + non_function(&Ds, &Dc) + ] + | + { + if (!Ds.ds_sc_given && !Ds.ds_typequal && Ds.ds_notypegiven) + { + strict("declaration missing"); + } + } + ';' + ] + { + remove_declarator(&Dc); + flush_strings(); + } + ; -non_function(struct decspecs *ds; struct declarator *dc;) -: - { reject_params(dc); - } - [ - initializer(dc->dc_idf, ds->ds_sc) - | - { code_declaration(dc->dc_idf, (struct expr *) 0, level, ds->ds_sc); } - ] - { -#ifdef LINT - lint_non_function_decl(ds, dc); -#endif /* LINT */ - } - [ - ',' - init_declarator(ds) - ]* - ';' -; +non_function(struct decspecs* ds; struct declarator* dc;) + : + { reject_params(dc); } + [ + initializer(dc->dc_idf, ds->ds_sc) + | + { code_declaration(dc->dc_idf, (struct expr*)0, level, ds->ds_sc); } + ] + { + #ifdef LINT + lint_non_function_decl(ds, dc); + #endif /* LINT */ + } + [ + ',' + init_declarator(ds) + ]* + ';' + ; /* 3.7.1 */ -function(struct decspecs *ds; struct declarator *dc;) - { - arith fbytes; - struct idf *idf = dc->dc_idf; - } -: - { -#ifdef LINT - lint_start_function(); -#endif /* LINT */ - idf_initialized(idf); - stack_level(); /* L_FORMAL1 declarations */ - declare_params(dc); - begin_proc(ds, idf); /* sets global function info */ - stack_level(); /* L_FORMAL2 declarations */ - declare_protos(dc); - } - declaration* - { - check_formals(idf, dc); /* check style-mixtures */ - declare_formals(idf, &fbytes); -#ifdef LINT - lint_formals(); -#endif /* LINT */ - } - compound_statement - { - end_proc(fbytes); -#ifdef LINT - lint_implicit_return(); -#endif /* LINT */ - unstack_level(); /* L_FORMAL2 declarations */ -#ifdef LINT - lint_end_formals(); -#endif /* LINT */ - unstack_level(); /* L_FORMAL1 declarations */ -#ifdef LINT - lint_end_function(); -#endif /* LINT */ - } -; +function(struct decspecs* ds; struct declarator* dc;) + { + arith fbytes; + struct idf* idf = dc->dc_idf; + } + : + { + #ifdef LINT + lint_start_function(); + #endif /* LINT */ + idf_initialized(idf); + stack_level(); /* L_FORMAL1 declarations */ + declare_params(dc); + begin_proc(ds, idf); /* sets global function info */ + stack_level(); /* L_FORMAL2 declarations */ + declare_protos(dc); + } + declaration* + { + check_formals(idf, dc); /* check style-mixtures */ + declare_formals(idf, &fbytes); + #ifdef LINT + lint_formals(); + #endif /* LINT */ + } + compound_statement + { + end_proc(fbytes); + #ifdef LINT + lint_implicit_return(); + #endif /* LINT */ + unstack_level(); /* L_FORMAL2 declarations */ + #ifdef LINT + lint_end_formals(); + #endif /* LINT */ + unstack_level(); /* L_FORMAL1 declarations */ + #ifdef LINT + lint_end_function(); + #endif /* LINT */ + } + ; diff --git a/lang/cem/cemcom.ansi/statement.g b/lang/cem/cemcom.ansi/statement.g index 83c741d61..9ae2a848f 100644 --- a/lang/cem/cemcom.ansi/statement.g +++ b/lang/cem/cemcom.ansi/statement.g @@ -2,35 +2,41 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cemcom.ansi/statement.g + */ /* $Id$ */ /* STATEMENT SYNTAX PARSER */ { -#include "parameters.h" -#ifndef LINT -#include -#else -#include "l_em.h" -#include "l_lint.h" -#endif /* LINT */ + #include "parameters.h" + #ifndef LINT + #include + #else + #include "l_em.h" + #include "l_lint.h" + #endif /* LINT */ -#include -#include "idf.h" -#include "arith.h" -#include "LLlex.h" -#include "type.h" -#include "label.h" -#include "expr.h" -#include "code.h" -#include "stack.h" -#include "def.h" -#include "switch.h" -#ifdef DBSYMTAB -#include -#endif /* DBSYMTAB */ + #include + #include "idf.h" + #include "arith.h" + #include "LLlex.h" + #include "type.h" + #include "label.h" + #include "expr.h" + #include "code.h" + #include "stack.h" + #include "def.h" + #include "switch.h" + #ifdef DBSYMTAB + #include + #endif /* DBSYMTAB */ -extern int level; -extern char options[]; + extern int level; + extern char options[]; } /* Each statement construction is stacked in order to trace a @@ -40,467 +46,447 @@ extern char options[]; /* 3.6 */ statement - { -#ifdef LINT - lint_statement(); -#endif /* LINT */ - } -: -%if (AHEAD != ':') - expression_statement -| - label ':' statement -| - compound_statement -| - if_statement -| - while_statement -| - do_statement -| - for_statement -| - switch_statement -| - case_statement -| - default_statement -| - BREAK - { - code_break(); -#ifdef LINT - lint_break_stmt(); -#endif /* LINT */ - } - ';' -| - CONTINUE - { - code_continue(); -#ifdef LINT - lint_continue_stmt(); -#endif /* LINT */ - } - ';' -| - return_statement -| - jump -| - ';' -; - + { + #ifdef LINT + lint_statement(); + #endif /* LINT */ + } + : %if (AHEAD != ':') + expression_statement + | label ':' statement + | compound_statement + | if_statement + | while_statement + | do_statement + | for_statement + | switch_statement + | case_statement + | default_statement + | BREAK + { + code_break(); + #ifdef LINT + lint_break_stmt(); + #endif /* LINT */ + } + ';' + | CONTINUE + { + code_continue(); + #ifdef LINT + lint_continue_stmt(); + #endif /* LINT */ + } + ';' + | return_statement + | jump + | ';' + ; expression_statement - { struct expr *expr; - } -: - expression(&expr) - ';' - { -#ifdef DEBUG - print_expr("expression_statement", expr); -#endif /* DEBUG */ - code_expr(expr, RVAL, FALSE, NO_LABEL, NO_LABEL); - free_expression(expr); - } -; + { + struct expr* expr; + } + : expression(&expr) + ';' + { + #ifdef DEBUG + print_expr("expression_statement", expr); + #endif /* DEBUG */ + code_expr(expr, RVAL, FALSE, NO_LABEL, NO_LABEL); + free_expression(expr); + } + ; /* 3.6.1 (partially) */ label - { struct idf *idf; } -: - identifier(&idf) - { - /* This allows the following absurd case: + { + struct idf* idf; + } + : identifier(&idf) + { + /* This allows the following absurd case: - typedef int grz; - main() { - grz: printf("A labelled statement\n"); - } - */ -#ifdef LINT - lint_label(); -#endif /* LINT */ - define_label(idf); - C_df_ilb((label)idf->id_label->df_address); - } -; + typedef int grz; + main() { + grz: printf("A labelled statement\n"); + } + */ + #ifdef LINT + lint_label(); + #endif /* LINT */ + define_label(idf); + C_df_ilb((label)idf->id_label->df_address); + } + ; /* 3.6.4.1 */ if_statement - { - struct expr *expr; - label l_true = text_label(); - label l_false = text_label(); - label l_end = text_label(); - } -: - IF - '(' - expression(&expr) - { - opnd2test(&expr, IF); - if (is_cp_cst(expr)) { - /* The comparison has been optimized - to a 0 or 1. - */ - if (expr->VL_VALUE == 0) { - C_bra(l_false); - } - /* else fall through */ -#ifdef LINT - start_if_part(1); -#endif /* LINT */ - } - else { - code_expr(expr, RVAL, TRUE, l_true, l_false); - C_df_ilb(l_true); -#ifdef LINT - start_if_part(0); -#endif /* LINT */ - } - free_expression(expr); - } - ')' - statement - [%prefer - ELSE - { -#ifdef LINT - start_else_part(); -#endif /* LINT */ - C_bra(l_end); - C_df_ilb(l_false); - } - statement - { C_df_ilb(l_end); -#ifdef LINT - end_if_else_stmt(); -#endif /* LINT */ - } - | - empty - { C_df_ilb(l_false); -#ifdef LINT - end_if_stmt(); -#endif /* LINT */ - } - ] -; + { + struct expr* expr; + label l_true = text_label(); + label l_false = text_label(); + label l_end = text_label(); + } + : IF '(' + expression(&expr) + { + opnd2test(&expr, IF); + if (is_cp_cst(expr)) + { + /* The comparison has been optimized + to a 0 or 1. + */ + if (expr->VL_VALUE == 0) + { + C_bra(l_false); + } + /* else fall through */ + #ifdef LINT + start_if_part(1); + #endif /* LINT */ + } + else + { + code_expr(expr, RVAL, TRUE, l_true, l_false); + C_df_ilb(l_true); + #ifdef LINT + start_if_part(0); + #endif /* LINT */ + } + free_expression(expr); + } + ')' statement + [ + %prefer + ELSE + { + #ifdef LINT + start_else_part(); + #endif /* LINT */ + C_bra(l_end); + C_df_ilb(l_false); + } + statement + { + C_df_ilb(l_end); + #ifdef LINT + end_if_else_stmt(); + #endif /* LINT */ + } + | empty + { + C_df_ilb(l_false); + #ifdef LINT + end_if_stmt(); + #endif /* LINT */ + } + ] + ; /* 3.6.5.3 */ while_statement - { - struct expr *expr; - label l_break = text_label(); - label l_continue = text_label(); - label l_body = text_label(); - } -: - WHILE - { - stack_stmt(l_break, l_continue); - C_df_ilb(l_continue); - } - '(' - expression(&expr) - { - opnd2test(&expr, WHILE); - if (is_cp_cst(expr)) { - if (expr->VL_VALUE == 0) { - C_bra(l_break); - } - } - else { - code_expr(expr, RVAL, TRUE, l_body, l_break); - C_df_ilb(l_body); - } -#ifdef LINT - start_while_stmt(expr); -#endif /* LINT */ - } - ')' - statement - { - C_bra(l_continue); - C_df_ilb(l_break); - unstack_stmt(); - free_expression(expr); -#ifdef LINT - end_loop_body(); - end_loop_stmt(); -#endif /* LINT */ - } -; + { + struct expr* expr; + label l_break = text_label(); + label l_continue = text_label(); + label l_body = text_label(); + } + : WHILE + { + stack_stmt(l_break, l_continue); + C_df_ilb(l_continue); + } + '(' + expression(&expr) + { + opnd2test(&expr, WHILE); + if (is_cp_cst(expr)) + { + if (expr->VL_VALUE == 0) + { + C_bra(l_break); + } + } + else + { + code_expr(expr, RVAL, TRUE, l_body, l_break); + C_df_ilb(l_body); + } + #ifdef LINT + start_while_stmt(expr); + #endif /* LINT */ + } + ')' statement + { + C_bra(l_continue); + C_df_ilb(l_break); + unstack_stmt(); + free_expression(expr); + #ifdef LINT + end_loop_body(); + end_loop_stmt(); + #endif /* LINT */ + } + ; /* 3.6.5.2 */ do_statement - { struct expr *expr; - label l_break = text_label(); - label l_continue = text_label(); - label l_body = text_label(); - } -: - DO - { C_df_ilb(l_body); - stack_stmt(l_break, l_continue); -#ifdef LINT - start_do_stmt(); -#endif /* LINT */ - } - statement - WHILE - '(' - { -#ifdef LINT - end_loop_body(); -#endif /* LINT */ - C_df_ilb(l_continue); - } - expression(&expr) - { - opnd2test(&expr, WHILE); - if (is_cp_cst(expr)) { - if (expr->VL_VALUE == 1) { - C_bra(l_body); - } -#ifdef LINT - end_do_stmt(1, expr->VL_VALUE != 0); -#endif /* LINT */ - } - else { - code_expr(expr, RVAL, TRUE, l_body, l_break); -#ifdef LINT - end_do_stmt(0, 0); -#endif /* LINT */ - } - C_df_ilb(l_break); - } - ')' - ';' - { - unstack_stmt(); - free_expression(expr); - } -; + { + struct expr* expr; + label l_break = text_label(); + label l_continue = text_label(); + label l_body = text_label(); + } + : DO + { + C_df_ilb(l_body); + stack_stmt(l_break, l_continue); + #ifdef LINT + start_do_stmt(); + #endif /* LINT */ + } + statement WHILE '(' + { + #ifdef LINT + end_loop_body(); + #endif /* LINT */ + C_df_ilb(l_continue); + } + expression(&expr) + { + opnd2test(&expr, WHILE); + if (is_cp_cst(expr)) + { + if (expr->VL_VALUE == 1) + { + C_bra(l_body); + } + #ifdef LINT + end_do_stmt(1, expr->VL_VALUE != 0); + #endif /* LINT */ + } + else + { + code_expr(expr, RVAL, TRUE, l_body, l_break); + #ifdef LINT + end_do_stmt(0, 0); + #endif /* LINT */ + } + C_df_ilb(l_break); + } + ')' ';' + { + unstack_stmt(); + free_expression(expr); + } + ; /* 3.6.5.3 */ for_statement - { struct expr *e_init = 0, *e_test = 0, *e_incr = 0; - label l_break = text_label(); - label l_continue = text_label(); - label l_body = text_label(); - label l_test = text_label(); - } -: - FOR - { stack_stmt(l_break, l_continue); - } - '(' - [ - expression(&e_init) - { code_expr(e_init, RVAL, FALSE, NO_LABEL, NO_LABEL); - } - ]? - ';' - { C_df_ilb(l_test); - } - [ - expression(&e_test) - { - opnd2test(&e_test, FOR); - if (is_cp_cst(e_test)) { - if (e_test->VL_VALUE == 0) { - C_bra(l_break); - } - } - else { - code_expr(e_test, RVAL, TRUE, l_body, l_break); - C_df_ilb(l_body); - } - } - ]? - ';' - expression(&e_incr)? - ')' - { -#ifdef LINT - start_for_stmt(e_test); -#endif /* LINT */ - } - statement - { -#ifdef LINT - end_loop_body(); -#endif /* LINT */ - C_df_ilb(l_continue); - if (e_incr) - code_expr(e_incr, RVAL, FALSE, - NO_LABEL, NO_LABEL); - C_bra(l_test); - C_df_ilb(l_break); - unstack_stmt(); - free_expression(e_init); - free_expression(e_test); - free_expression(e_incr); -#ifdef LINT - end_loop_stmt(); -#endif /* LINT */ - } -; + { + struct expr *e_init = 0, *e_test = 0, *e_incr = 0; + label l_break = text_label(); + label l_continue = text_label(); + label l_body = text_label(); + label l_test = text_label(); + } + : FOR + { stack_stmt(l_break, l_continue); } + '(' + [ + expression(&e_init) + { code_expr(e_init, RVAL, FALSE, NO_LABEL, NO_LABEL); } + ]? + ';' + { C_df_ilb(l_test); } + [ + expression(&e_test) + { + opnd2test(&e_test, FOR); + if (is_cp_cst(e_test)) + { + if (e_test->VL_VALUE == 0) + { + C_bra(l_break); + } + } + else + { + code_expr(e_test, RVAL, TRUE, l_body, l_break); + C_df_ilb(l_body); + } + } + ]? + ';' + expression(&e_incr)? + ')' + { + #ifdef LINT + start_for_stmt(e_test); + #endif /* LINT */ + } + statement + { + #ifdef LINT + end_loop_body(); + #endif /* LINT */ + C_df_ilb(l_continue); + if (e_incr) + code_expr(e_incr, RVAL, FALSE, NO_LABEL, NO_LABEL); + C_bra(l_test); + C_df_ilb(l_break); + unstack_stmt(); + free_expression(e_init); + free_expression(e_test); + free_expression(e_incr); + #ifdef LINT + end_loop_stmt(); + #endif /* LINT */ + } + ; /* 3.6.4.2 */ switch_statement - { - struct expr *expr; - } -: - SWITCH - '(' - expression(&expr) - { - code_startswitch(&expr); -#ifdef LINT - start_switch_part(is_cp_cst(expr)); -#endif /* LINT */ - } - ')' - statement - { -#ifdef LINT - end_switch_stmt(); -#endif /* LINT */ - code_endswitch(); - free_expression(expr); - } -; + { + struct expr* expr; + } + : SWITCH '(' + expression(&expr) + { + code_startswitch(&expr); + #ifdef LINT + start_switch_part(is_cp_cst(expr)); + #endif /* LINT */ + } + ')' statement + { + #ifdef LINT + end_switch_stmt(); + #endif /* LINT */ + code_endswitch(); + free_expression(expr); + } + ; /* 3.6.1 (partially) */ case_statement - { - struct expr *expr; - } -: - CASE - constant_expression(&expr) - { -#ifdef LINT - lint_case_stmt(0); -#endif /* LINT */ - code_case(expr); - free_expression(expr); - } - ':' - statement -; + { + struct expr* expr; + } + : CASE + constant_expression(&expr) + { + #ifdef LINT + lint_case_stmt(0); + #endif /* LINT */ + code_case(expr); + free_expression(expr); + } + ':' statement + ; /* 3.6.1 (partially) */ default_statement -: - DEFAULT - { -#ifdef LINT - lint_case_stmt(1); -#endif /* LINT */ - code_default(); - } - ':' - statement -; + : DEFAULT + { + #ifdef LINT + lint_case_stmt(1); + #endif /* LINT */ + code_default(); + } + ':' statement + ; /* 3.6.6.4 */ return_statement - { struct expr *expr = 0; - } -: - RETURN - [ - expression(&expr) - { -#ifdef LINT - lint_ret_conv(expr); -#endif /* LINT */ + { + struct expr* expr = 0; + } + : RETURN + [ + expression(&expr) + { + #ifdef LINT + lint_ret_conv(expr); + #endif /* LINT */ - do_return_expr(expr); - free_expression(expr); -#ifdef LINT - lint_return_stmt(VALRETURNED); -#endif /* LINT */ - } - | - empty - { - do_return(); -#ifdef LINT - lint_return_stmt(NOVALRETURNED); -#endif /* LINT */ - } - ] - ';' -; + do_return_expr(expr); + free_expression(expr); + #ifdef LINT + lint_return_stmt(VALRETURNED); + #endif /* LINT */ + } + | empty + { + do_return(); + #ifdef LINT + lint_return_stmt(NOVALRETURNED); + #endif /* LINT */ + } + ] + ';' + ; /* 3.6.6.1 (partially) */ jump - { struct idf *idf; - } -: - GOTO - identifier(&idf) - ';' - { - apply_label(idf); - C_bra((label)idf->id_label->df_address); -#ifdef LINT - lint_jump_stmt(idf); -#endif /* LINT */ - } -; + { + struct idf* idf; + } + : GOTO + identifier(&idf) + ';' + { + apply_label(idf); + C_bra((label)idf->id_label->df_address); + #ifdef LINT + lint_jump_stmt(idf); + #endif /* LINT */ + } + ; /* 3.6.2 */ compound_statement - { -#ifdef DBSYMTAB - static int brc_level = 1; - int decl_seen = brc_level == 1; -#endif /* DBSYMTAB */ - } -: - '{' - { - stack_level(); - } - [%while ((DOT != IDENTIFIER && AHEAD != ':') || - (DOT == IDENTIFIER && AHEAD == IDENTIFIER)) - /* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */ - declaration - { -#ifdef DBSYMTAB - decl_seen++; -#endif /* DBSYMTAB */ - } - ]* - { -#ifdef DBSYMTAB - ++brc_level; - if (options['g'] && decl_seen) { - C_ms_std((char *) 0, N_LBRAC, brc_level); - } -#endif /* DBSYMTAB */ - } - [%persistent - statement - ]* - '}' - { - unstack_level(); -#ifdef DBSYMTAB - if (options['g'] && decl_seen) { - C_ms_std((char *) 0, N_RBRAC, brc_level); - } - brc_level--; -#endif /* DBSYMTAB */ - } -; + { + #ifdef DBSYMTAB + static int brc_level = 1; + int decl_seen = brc_level == 1; + #endif /* DBSYMTAB */ + } + : '{' + { stack_level(); } + [ + %while ((DOT != IDENTIFIER && AHEAD != ':') || (DOT == IDENTIFIER && AHEAD == IDENTIFIER)) + /* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */ + declaration + { + #ifdef DBSYMTAB + decl_seen++; + #endif /* DBSYMTAB */ + } + ]* + { + #ifdef DBSYMTAB + ++brc_level; + if (options['g'] && decl_seen) + { + C_ms_std((char*)0, N_LBRAC, brc_level); + } + #endif /* DBSYMTAB */ + } + [ + %persistent + statement + ]* + '}' + { + unstack_level(); + #ifdef DBSYMTAB + if (options['g'] && decl_seen) + { + C_ms_std((char*)0, N_RBRAC, brc_level); + } + brc_level--; + #endif /* DBSYMTAB */ + } + ; diff --git a/lang/cem/cemcom/declar.g b/lang/cem/cemcom/declar.g index 295c7412c..a0647a060 100644 --- a/lang/cem/cemcom/declar.g +++ b/lang/cem/cemcom/declar.g @@ -2,539 +2,580 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cemcom/declar.g + */ /* $Id$ */ /* DECLARATION SYNTAX PARSER */ { -#include "lint.h" -#include "dbsymtab.h" -#include -#include "nobitfield.h" -#include "debug.h" -#include "arith.h" -#include "LLlex.h" -#include "label.h" -#include "code.h" -#include "idf.h" -#include "type.h" -#include "struct.h" -#include "field.h" -#include "decspecs.h" -#include "def.h" -#include "declar.h" -#include "label.h" -#include "expr.h" -#include "sizes.h" -#include "level.h" -#ifdef LINT -#include "l_lint.h" -#endif /* LINT */ - -extern char options[]; + #include "lint.h" + #include "dbsymtab.h" + #include + #include "nobitfield.h" + #include "debug.h" + #include "arith.h" + #include "LLlex.h" + #include "label.h" + #include "code.h" + #include "idf.h" + #include "type.h" + #include "struct.h" + #include "field.h" + #include "decspecs.h" + #include "def.h" + #include "declar.h" + #include "label.h" + #include "expr.h" + #include "sizes.h" + #include "level.h" + #ifdef LINT + #include "l_lint.h" + #endif /* LINT */ + + extern char options[]; } /* 8 */ declaration - {struct decspecs Ds;} -: - {Ds = null_decspecs;} - decl_specifiers(&Ds) - [%default /* missing identifier derailed parser */ - init_declarator_list(&Ds) - | - empty - ] - ';' -; + { + struct decspecs Ds; + } + : + { Ds = null_decspecs; } + decl_specifiers(&Ds) + [ + %default + /* missing identifier derailed parser */ + init_declarator_list(&Ds) + | empty + ] + ';' + ; /* A `decl_specifiers' describes a sequence of a storage_class_specifier, - an unsigned_specifier, a size_specifier and a simple type_specifier, - which may occur in arbitrary order and each of which may be absent; - at least one of them must be present, however, since the totally - empty case has already be dealt with in `external_definition'. - This means that something like: - unsigned extern int short xx; - is perfectly good C. - - On top of that, multiple occurrences of storage_class_specifiers, - unsigned_specifiers and size_specifiers are errors, but a second - type_specifier should end the decl_specifiers and be treated as - the name to be declared (see the thin ice in RM11.1). - Such a language is not easily expressed in a grammar; enumeration - of the permutations is unattractive. We solve the problem by - having a regular grammar for the "soft" items, handling the single - occurrence of the type_specifier in the grammar (we have no choice), - collecting all data in a `struct decspecs' and turning that data - structure into what we want. - - The existence of declarations like - short typedef yepp; - makes all hope of writing a specific grammar for typedefs illusory. +an unsigned_specifier, a size_specifier and a simple type_specifier, +which may occur in arbitrary order and each of which may be absent; +at least one of them must be present, however, since the totally +empty case has already be dealt with in `external_definition'. +This means that something like: +unsigned extern int short xx; +is perfectly good C. + +On top of that, multiple occurrences of storage_class_specifiers, +unsigned_specifiers and size_specifiers are errors, but a second +type_specifier should end the decl_specifiers and be treated as +the name to be declared (see the thin ice in RM11.1). +Such a language is not easily expressed in a grammar; enumeration +of the permutations is unattractive. We solve the problem by +having a regular grammar for the "soft" items, handling the single +occurrence of the type_specifier in the grammar (we have no choice), +collecting all data in a `struct decspecs' and turning that data +structure into what we want. + +The existence of declarations like +short typedef yepp; +makes all hope of writing a specific grammar for typedefs illusory. */ -decl_specifiers /* non-empty */ (struct decspecs *ds;) - /* Reads a non-empty decl_specifiers and fills the struct - decspecs *ds. - */ -: -[ - other_specifier(ds)+ - [%if (DOT != IDENTIFIER || AHEAD == IDENTIFIER) - /* the thin ice in R.M. 11.1 */ - single_type_specifier(ds) other_specifier(ds)* - | - empty - ] -| - single_type_specifier(ds) other_specifier(ds)* -] - {do_decspecs(ds);} -; +decl_specifiers + /* non-empty */ +(struct decspecs* ds;) + /* Reads a non-empty decl_specifiers and fills the struct + decspecs *ds. + */ + : [ + other_specifier(ds)+ + [ + %if (DOT != IDENTIFIER || AHEAD == IDENTIFIER) + /* the thin ice in R.M. 11.1 */ + single_type_specifier(ds) + other_specifier(ds)* + | empty + ] + | single_type_specifier(ds) + other_specifier(ds)* + ] + { do_decspecs(ds); } + ; /* 8.1 */ -other_specifier(struct decspecs *ds;): - [ AUTO | STATIC | EXTERN | TYPEDEF | REGISTER ] - { if (ds->ds_sc_given) - error("repeated storage class specifier"); - ds->ds_sc_given = 1; - ds->ds_sc = DOT; - } -| - [ SHORT | LONG ] - { if (ds->ds_size) - error("repeated size specifier"); - ds->ds_size = DOT; - } -| - UNSIGNED - { if (ds->ds_unsigned) - error("unsigned specified twice"); - ds->ds_unsigned = 1; - } -; +other_specifier(struct decspecs* ds;) + : [ + AUTO + | STATIC + | EXTERN + | TYPEDEF + | REGISTER + ] + { + if (ds->ds_sc_given) + error("repeated storage class specifier"); + ds->ds_sc_given = 1; + ds->ds_sc = DOT; + } + | [ + SHORT + | LONG + ] + { + if (ds->ds_size) + error("repeated size specifier"); + ds->ds_size = DOT; + } + | UNSIGNED + { + if (ds->ds_unsigned) + error("unsigned specified twice"); + ds->ds_unsigned = 1; + } + ; /* 8.2 */ -type_specifier(struct type **tpp;) - /* Used in struct/union declarations and in casts; only the - type is relevant. - */ - {struct decspecs Ds; Ds = null_decspecs;} -: - decl_specifiers(&Ds) - { - if (Ds.ds_sc_given) - error("storage class ignored"); - if (Ds.ds_sc == REGISTER) - error("register ignored"); - } - {*tpp = Ds.ds_type;} -; - -single_type_specifier(struct decspecs *ds;): - %default TYPE_IDENTIFIER /* this includes INT, CHAR, etc. */ - {idf2type(dot.tk_idf, &ds->ds_type);} -| - %erroneous - IDENTIFIER - { - error("%s is not a type identifier", dot.tk_idf->id_text); - ds->ds_type = error_type; - if (dot.tk_idf->id_def) { - dot.tk_idf->id_def->df_type = error_type; - dot.tk_idf->id_def->df_sc = TYPEDEF; - } - } -| - %illegal - IDENTIFIER -| - struct_or_union_specifier(&ds->ds_type) -| - enum_specifier(&ds->ds_type) -; +type_specifier(struct type** tpp;) + /* Used in struct/union declarations and in casts; only the + type is relevant. + */ + { + struct decspecs Ds; + Ds = null_decspecs; + } + : decl_specifiers(&Ds) + { + if (Ds.ds_sc_given) + error("storage class ignored"); + if (Ds.ds_sc == REGISTER) + error("register ignored"); + } + { *tpp = Ds.ds_type; } + ; + +single_type_specifier(struct decspecs* ds;) + : %default + TYPE_IDENTIFIER + /* this includes INT, CHAR, etc. */ + { idf2type(dot.tk_idf, &ds->ds_type); } + | %erroneous IDENTIFIER + { + error("%s is not a type identifier", dot.tk_idf->id_text); + ds->ds_type = error_type; + if (dot.tk_idf->id_def) + { + dot.tk_idf->id_def->df_type = error_type; + dot.tk_idf->id_def->df_sc = TYPEDEF; + } + } + | %illegal + IDENTIFIER + | struct_or_union_specifier(&ds->ds_type) + | enum_specifier(&ds->ds_type) + ; /* 8.3 */ -init_declarator_list(struct decspecs *ds;): - init_declarator(ds) - [ ',' init_declarator(ds) ]* -; - -init_declarator(struct decspecs *ds;) - { - struct declarator Dc; - } -: - { - Dc = null_declarator; - } -[ - declarator(&Dc) - { - reject_params(&Dc); - declare_idf(ds, &Dc, level); -#ifdef LINT - lint_declare_idf(Dc.dc_idf, ds->ds_sc); -#endif /* LINT */ - } - [ - initializer(Dc.dc_idf, ds->ds_sc) - | - { code_declaration(Dc.dc_idf, (struct expr *) 0, level, ds->ds_sc); } - ] -] - { -#ifdef LINT - add_auto(Dc.dc_idf); -#endif /* LINT */ - remove_declarator(&Dc); - } -; +init_declarator_list(struct decspecs* ds;) + : init_declarator(ds) + [ + ',' + init_declarator(ds) + ]* + ; + +init_declarator(struct decspecs* ds;) + { + struct declarator Dc; + } + : + { Dc = null_declarator; } + [ + declarator(&Dc) + { + reject_params(&Dc); + declare_idf(ds, &Dc, level); + #ifdef LINT + lint_declare_idf(Dc.dc_idf, ds->ds_sc); + #endif /* LINT */ + } + [ + initializer(Dc.dc_idf, ds->ds_sc) + | + { code_declaration(Dc.dc_idf, (struct expr*)0, level, ds->ds_sc); } + ] + ] + { + #ifdef LINT + add_auto(Dc.dc_idf); + #endif /* LINT */ + remove_declarator(&Dc); + } + ; /* 8.6: initializer */ -initializer(struct idf *idf; int sc;) - { - struct expr *expr = (struct expr *) 0; - int globalflag = level == L_GLOBAL || - (level >= L_LOCAL && sc == STATIC); - } -: - { if (idf->id_def->df_type->tp_fund == FUNCTION) { - error("illegal initialization of function"); - idf->id_def->df_type->tp_fund = ERRONEOUS; - } - if (level == L_FORMAL2) - warning("illegal initialization of formal parameter (ignored)"); - } - '=' /* used to be optional because of V6 */ - { -#ifdef LINT - lint_statement(); -#endif /* LINT */ - if (globalflag) { - struct expr ex; - code_declaration(idf, &ex, level, sc); - } - } - initial_value(globalflag ? &(idf->id_def->df_type) : (struct type **)0, - &expr) - { if (! globalflag) { - if (idf->id_def->df_type->tp_fund == FUNCTION) { - free_expression(expr); - expr = 0; - } -#ifdef DEBUG - print_expr("initializer-expression", expr); -#endif /* DEBUG */ -#ifdef LINT - change_state(idf, SET); -#endif /* LINT */ -#ifdef DBSYMTAB - if (options['g'] && level >= L_LOCAL && expr) { - db_line(expr->ex_file, (unsigned) expr->ex_line) -; - } -#endif /* DBSYMTAB */ - code_declaration(idf, expr, level, sc); - } -#ifdef DBSYMTAB - if (options['g'] && globalflag) { - stb_string(idf->id_def, sc, idf->id_text); - } -#endif /* DBSYMTAB */ - init_idf(idf); - } -; +initializer(struct idf* idf; int sc;) + { + struct expr* expr = (struct expr*)0; + int globalflag = level == L_GLOBAL || (level >= L_LOCAL && sc == STATIC); + } + : + { + if (idf->id_def->df_type->tp_fund == FUNCTION) + { + error("illegal initialization of function"); + idf->id_def->df_type->tp_fund = ERRONEOUS; + } + if (level == L_FORMAL2) + warning("illegal initialization of formal parameter (ignored)"); + } + '=' + /* used to be optional because of V6 */ + { + #ifdef LINT + lint_statement(); + #endif /* LINT */ + if (globalflag) + { + struct expr ex; + code_declaration(idf, &ex, level, sc); + } + } + initial_value(globalflag ? &(idf->id_def->df_type) : (struct type**)0, &expr) + { + if (!globalflag) + { + if (idf->id_def->df_type->tp_fund == FUNCTION) + { + free_expression(expr); + expr = 0; + } + #ifdef DEBUG + print_expr("initializer-expression", expr); + #endif /* DEBUG */ + #ifdef LINT + change_state(idf, SET); + #endif /* LINT */ + #ifdef DBSYMTAB + if (options['g'] && level >= L_LOCAL && expr) + { + db_line(expr->ex_file, (unsigned)expr->ex_line); + } + #endif /* DBSYMTAB */ + code_declaration(idf, expr, level, sc); + } + #ifdef DBSYMTAB + if (options['g'] && globalflag) + { + stb_string(idf->id_def, sc, idf->id_text); + } + #endif /* DBSYMTAB */ + init_idf(idf); + } + ; /* - Functions yielding pointers to functions must be declared as, e.g., - int (*hehe(par1, par2))() char *par1, *par2; {} - Since the function heading is read as a normal declarator, - we just include the (formal) parameter list in the declarator - description list dc. +Functions yielding pointers to functions must be declared as, e.g., +int (*hehe(par1, par2))() char *par1, *par2; {} +Since the function heading is read as a normal declarator, +we just include the (formal) parameter list in the declarator +description list dc. */ -declarator(struct declarator *dc;) - { - arith count; - struct formal *fm = 0; - } -: - primary_declarator(dc) - [ - '(' - formal_list(&fm) ? /* semantic check later... */ - ')' - { - add_decl_unary(dc, FUNCTION, (arith)0, fm); - fm = 0; - } - | - arrayer(&count) - {add_decl_unary(dc, ARRAY, count, NO_PARAMS);} - ]* -| - '*' declarator(dc) - {add_decl_unary(dc, POINTER, (arith)0, NO_PARAMS);} -; - -primary_declarator(struct declarator *dc;) : - identifier(&dc->dc_idf) -| - '(' declarator(dc) ')' -; - -arrayer(arith *sizep;) - { struct expr *expr; } -: - '[' - [ - constant_expression(&expr) - { - check_array_subscript(expr); - *sizep = expr->VL_VALUE; - free_expression(expr); - } - | - empty - { *sizep = (arith)-1; } - ] - ']' -; - -formal_list (struct formal **fmp;) -: - formal(fmp) [ %persistent ',' formal(fmp) ]* -; - -formal(struct formal **fmp;) - {struct idf *idf; } -: - identifier(&idf) - { - struct formal *new = new_formal(); - - new->fm_idf = idf; - new->next = *fmp; - *fmp = new; - } -; +declarator(struct declarator* dc;) + { + arith count; + struct formal* fm = 0; + } + : primary_declarator(dc) + [ + '(' + formal_list(&fm)? + /* semantic check later... */ + ')' + { + add_decl_unary(dc, FUNCTION, (arith)0, fm); + fm = 0; + } + | arrayer(&count) + { add_decl_unary(dc, ARRAY, count, NO_PARAMS); } + ]* + | '*' + declarator(dc) + { add_decl_unary(dc, POINTER, (arith)0, NO_PARAMS); } + ; + +primary_declarator(struct declarator* dc;) + : identifier(&dc->dc_idf) + | '(' + declarator(dc) + ')' + ; + +arrayer(arith* sizep;) + { + struct expr* expr; + } + : '[' + [ + constant_expression(&expr) + { + check_array_subscript(expr); + *sizep = expr->VL_VALUE; + free_expression(expr); + } + | empty + { *sizep = (arith)-1; } + ] + ']' + ; + +formal_list(struct formal** fmp;) + : formal(fmp) + [ + %persistent + ',' + formal(fmp) + ]* + ; + +formal(struct formal** fmp;) + { + struct idf* idf; + } + : identifier(&idf) + { + struct formal* new = new_formal(); + + new->fm_idf = idf; + new->next = *fmp; + *fmp = new; + } + ; /* Change 2 */ -enum_specifier(struct type **tpp;) - { - struct idf *idf; - arith l = (arith)0; - } -: - ENUM - [ - {declare_struct(ENUM, (struct idf *) 0, tpp);} - enumerator_pack(*tpp, &l) - | - identifier(&idf) - [ - {declare_struct(ENUM, idf, tpp);} - enumerator_pack(*tpp, &l) - { -#ifdef DBSYMTAB - if (options['g']) { - stb_tag(idf->id_enum, idf->id_text); - } -#endif /*DBSYMTAB */ - } - | - {apply_struct(ENUM, idf, tpp);} - empty - ] - ] -; - -enumerator_pack(struct type *tp; arith *lp;) : - '{' - enumerator(tp, lp) - [%while(AHEAD != '}') /* >>> conflict on ',' */ - ',' - enumerator(tp, lp) - ]* - ','? /* optional trailing comma */ - '}' - {tp->tp_size = int_size;} - /* fancy implementations that put small enums in 1 byte - or so should start here. - */ -; - -enumerator(struct type *tp; arith *lp;) - { - struct idf *idf; - struct expr *expr; - } -: - identifier(&idf) - [ - '=' - constant_expression(&expr) - { - *lp = expr->VL_VALUE; - free_expression(expr); - } - ]? - {declare_enum(tp, idf, (*lp)++);} -; +enum_specifier(struct type** tpp;) + { + struct idf* idf; + arith l = (arith)0; + } + : ENUM + [ + { declare_struct(ENUM, (struct idf*)0, tpp); } + enumerator_pack(*tpp, &l) + | identifier(&idf) + [ + { declare_struct(ENUM, idf, tpp); } + enumerator_pack(*tpp, &l) + { + #ifdef DBSYMTAB + if (options['g']) + { + stb_tag(idf->id_enum, idf->id_text); + } + #endif /*DBSYMTAB */ + } + | + { apply_struct(ENUM, idf, tpp); } + empty + ] + ] + ; + +enumerator_pack(struct type* tp; arith* lp;) + : '{' + enumerator(tp, lp) + [ + %while (AHEAD != '}') + /* >>> conflict on ',' */ + ',' + enumerator(tp, lp) + ]* + ','? + /* optional trailing comma */ + '}' + { tp->tp_size = int_size; } + /* fancy implementations that put small enums in 1 byte + or so should start here. + */ + ; + +enumerator(struct type* tp; arith* lp;) + { + struct idf* idf; + struct expr* expr; + } + : identifier(&idf) + [ + '=' + constant_expression(&expr) + { + *lp = expr->VL_VALUE; + free_expression(expr); + } + ]? + { declare_enum(tp, idf, (*lp)++); } + ; /* 8.5 */ -struct_or_union_specifier(struct type **tpp;) - { - int fund; - struct idf *idfX; - struct idf *idf; - } -: - [ STRUCT | UNION ] - {fund = DOT;} - [ - { - declare_struct(fund, (struct idf *)0, tpp); - } - struct_declaration_pack(*tpp) - | - identifier(&idfX) { idf = idfX; } - [ - { - declare_struct(fund, idf, tpp); - (idf->id_struct->tg_busy)++; - } - struct_declaration_pack(*tpp) - { - (idf->id_struct->tg_busy)--; -#ifdef DBSYMTAB - if (options['g']) { - stb_tag(idf->id_struct, idf->id_text); - } -#endif /*DBSYMTAB */ - } - | - {apply_struct(fund, idf, tpp);} - empty - ] - ] -; - -struct_declaration_pack(struct type *stp;) - { - struct sdef **sdefp = &stp->tp_sdef; - arith size = (arith)0; - } -: - /* The size is only filled in after the whole struct has - been read, to prevent recursive definitions. - */ - '{' - struct_declaration(stp, &sdefp, &size)+ - '}' - {stp->tp_size = align(size, stp->tp_align);} -; - -struct_declaration(struct type *stp; struct sdef ***sdefpp; arith *szp;) - {struct type *tp;} -: - type_specifier(&tp) - struct_declarator_list(tp, stp, sdefpp, szp) - [ /* in some standard UNIX compilers the semicolon - is optional, would you believe! - */ - ';' - | - empty - {warning("no semicolon after declarator");} - ] -; - -struct_declarator_list(struct type *tp; struct type *stp; - struct sdef ***sdefpp; arith *szp;) -: - struct_declarator(tp, stp, sdefpp, szp) - [ ',' struct_declarator(tp, stp, sdefpp, szp) ]* -; - -struct_declarator(struct type *tp; struct type *stp; - struct sdef ***sdefpp; arith *szp;) - { - struct declarator Dc; - struct field *fd = 0; - } -: - { - Dc = null_declarator; - } -[ - declarator(&Dc) - {reject_params(&Dc);} - bit_expression(&fd)? -| - {Dc.dc_idf = gen_idf();} - bit_expression(&fd) -] - {add_sel(stp, declare_type(tp, &Dc), Dc.dc_idf, sdefpp, szp, fd);} - {remove_declarator(&Dc);} -; - -bit_expression(struct field **fd;) - { struct expr *expr; } -: - { - *fd = new_field(); - } - ':' - constant_expression(&expr) - { - (*fd)->fd_width = expr->VL_VALUE; - free_expression(expr); -#ifdef NOBITFIELD - error("bitfields are not implemented"); -#endif /* NOBITFIELD */ - } -; +struct_or_union_specifier(struct type** tpp;) + { + int fund; + struct idf* idfX; + struct idf* idf; + } + : [ + STRUCT + | UNION + ] + { fund = DOT; } + [ + { declare_struct(fund, (struct idf*)0, tpp); } + struct_declaration_pack(*tpp) + | identifier(&idfX) + { idf = idfX; } + [ + { + declare_struct(fund, idf, tpp); + (idf->id_struct->tg_busy)++; + } + struct_declaration_pack(*tpp) + { + (idf->id_struct->tg_busy)--; + #ifdef DBSYMTAB + if (options['g']) + { + stb_tag(idf->id_struct, idf->id_text); + } + #endif /*DBSYMTAB */ + } + | + { apply_struct(fund, idf, tpp); } + empty + ] + ] + ; + +struct_declaration_pack(struct type* stp;) + { + struct sdef** sdefp = &stp->tp_sdef; + arith size = (arith)0; + } + : + /* The size is only filled in after the whole struct has + been read, to prevent recursive definitions. + */ + '{' + struct_declaration(stp, &sdefp, &size)+ + '}' + { stp->tp_size = align(size, stp->tp_align); } + ; + +struct_declaration(struct type* stp; struct sdef*** sdefpp; arith* szp;) + { + struct type* tp; + } + : type_specifier(&tp) + struct_declarator_list(tp, stp, sdefpp, szp) + [ + /* in some standard UNIX compilers the semicolon + is optional, would you believe! + */ + ';' + | empty + { warning("no semicolon after declarator"); } + ] + ; + +struct_declarator_list(struct type* tp; struct type* stp; struct sdef*** sdefpp; arith* szp;) + : struct_declarator(tp, stp, sdefpp, szp) + [ + ',' + struct_declarator(tp, stp, sdefpp, szp) + ]* + ; + +struct_declarator(struct type* tp; struct type* stp; struct sdef*** sdefpp; arith* szp;) + { + struct declarator Dc; + struct field* fd = 0; + } + : + { Dc = null_declarator; } + [ + declarator(&Dc) + { reject_params(&Dc); } + bit_expression(&fd)? + | + { Dc.dc_idf = gen_idf(); } + bit_expression(&fd) + ] + { add_sel(stp, declare_type(tp, &Dc), Dc.dc_idf, sdefpp, szp, fd); } + { remove_declarator(&Dc); } + ; + +bit_expression(struct field** fd;) + { + struct expr* expr; + } + : + { *fd = new_field(); } + ':' + constant_expression(&expr) + { + (*fd)->fd_width = expr->VL_VALUE; + free_expression(expr); + #ifdef NOBITFIELD + error("bitfields are not implemented"); + #endif /* NOBITFIELD */ + } + ; /* 8.7 */ -cast(struct type **tpp;) {struct declarator Dc;} : - {Dc = null_declarator;} - '(' - type_specifier(tpp) - abstract_declarator(&Dc) - ')' - {*tpp = declare_type(*tpp, &Dc);} - {remove_declarator(&Dc);} -; +cast(struct type** tpp;) + { + struct declarator Dc; + } + : + { Dc = null_declarator; } + '(' + type_specifier(tpp) + abstract_declarator(&Dc) + ')' + { *tpp = declare_type(*tpp, &Dc); } + { remove_declarator(&Dc); } + ; /* This code is an abject copy of that of 'declarator', for lack of - a two-level grammar. +a two-level grammar. */ -abstract_declarator(struct declarator *dc;) - {arith count;} -: - primary_abstract_declarator(dc) - [ - '(' ')' - {add_decl_unary(dc, FUNCTION, (arith)0, NO_PARAMS);} - | - arrayer(&count) - {add_decl_unary(dc, ARRAY, count, NO_PARAMS);} - ]* -| - '*' abstract_declarator(dc) - {add_decl_unary(dc, POINTER, (arith)0, NO_PARAMS);} -; - -primary_abstract_declarator(struct declarator *dc;) : -[%if (AHEAD == ')') - empty -| - '(' abstract_declarator(dc) ')' -] -; - -empty: -; +abstract_declarator(struct declarator* dc;) + { + arith count; + } + : primary_abstract_declarator(dc) + [ + '(' ')' + { add_decl_unary(dc, FUNCTION, (arith)0, NO_PARAMS); } + | arrayer(&count) + { add_decl_unary(dc, ARRAY, count, NO_PARAMS); } + ]* + | '*' + abstract_declarator(dc) + { add_decl_unary(dc, POINTER, (arith)0, NO_PARAMS); } + ; + +primary_abstract_declarator(struct declarator* dc;) + : [ + %if (AHEAD == ')') + empty + | '(' + abstract_declarator(dc) + ')' + ] + ; + +empty + : + ; /* 8.8 */ /* included in the IDENTIFIER/TYPE_IDENTIFIER mechanism */ diff --git a/lang/cem/cemcom/expression.g b/lang/cem/cemcom/expression.g index 73ab9e837..d93dc51c4 100644 --- a/lang/cem/cemcom/expression.g +++ b/lang/cem/cemcom/expression.g @@ -2,336 +2,384 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cemcom/expression.g + */ /* $Id$ */ /* EXPRESSION SYNTAX PARSER */ { -#include "arith.h" -#include "LLlex.h" -#include "type.h" -#include "idf.h" -#include "label.h" -#include "expr.h" -#include "code.h" -#include "noRoption.h" - -extern char options[]; -extern struct expr *intexpr(); + #include "arith.h" + #include "LLlex.h" + #include "type.h" + #include "idf.h" + #include "label.h" + #include "expr.h" + #include "code.h" + #include "noRoption.h" + + extern char options[]; + extern struct expr* intexpr(); } /* 7.1 */ -primary(struct expr **expp;) : - IDENTIFIER - {dot2expr(expp);} -| - %illegal TYPE_IDENTIFIER -| - constant(expp) -| - STRING - {dot2expr(expp);} -| - '(' expression(expp) ')' - {(*expp)->ex_flags |= EX_PARENS;} -; +primary(struct expr** expp;) + : IDENTIFIER + { dot2expr(expp); } + | %illegal + TYPE_IDENTIFIER + | constant(expp) + | STRING + { dot2expr(expp); } + | '(' + expression(expp) + ')' + { (*expp)->ex_flags |= EX_PARENS; } + ; -secundary(struct expr **expp;) : - primary(expp) - [ - index_pack(expp) - | - parameter_pack(expp) - | - selection(expp) - ]* -; +secundary(struct expr** expp;) + : primary(expp) + [ + index_pack(expp) + | parameter_pack(expp) + | selection(expp) + ]* + ; -index_pack(struct expr **expp;) - {struct expr *e1;} -: - '[' expression(&e1) ']' - {ch7bin(expp, '[', e1);} -; +index_pack(struct expr** expp;) + { + struct expr* e1; + } + : '[' + expression(&e1) + ']' + { ch7bin(expp, '[', e1); } + ; -parameter_pack(struct expr **expp;) - {struct expr *e1 = 0;} -: - '(' parameter_list(&e1)? ')' - {ch7bin(expp, '(', e1);} -; +parameter_pack(struct expr** expp;) + { + struct expr* e1 = 0; + } + : '(' + parameter_list(&e1)? + ')' + { ch7bin(expp, '(', e1); } + ; -selection(struct expr **expp;) - {int oper; struct idf *idf;} -: - [ '.' | ARROW ] - {oper = DOT;} - identifier(&idf) - {ch7sel(expp, oper, idf);} -; +selection(struct expr** expp;) + { + int oper; + struct idf* idf; + } + : [ + '.' + | ARROW + ] + { oper = DOT; } + identifier(&idf) + { ch7sel(expp, oper, idf); } + ; -parameter_list(struct expr **expp;) - {struct expr *e1 = 0;} -: - assignment_expression(expp) - {any2opnd(expp, PARCOMMA);} - [ %persistent - ',' - assignment_expression(&e1) - {any2opnd(&e1, PARCOMMA);} - {ch7bin(expp, PARCOMMA, e1);} - ]* -; +parameter_list(struct expr** expp;) + { + struct expr* e1 = 0; + } + : assignment_expression(expp) + { any2opnd(expp, PARCOMMA); } + [ + %persistent + ',' + assignment_expression(&e1) + { any2opnd(&e1, PARCOMMA); } + { ch7bin(expp, PARCOMMA, e1); } + ]* + ; /* 7.2 */ -postfixed(struct expr **expp;) - {int oper;} -: - secundary(expp) - [ - postop(&oper) - {ch7incr(expp, oper);} - | - empty - ] -; +postfixed(struct expr** expp;) + { + int oper; + } + : secundary(expp) + [ + postop(&oper) + { ch7incr(expp, oper); } + | empty + ] + ; -%first first_of_type_specifier, type_specifier; +%first first_of_type_specifier, type_specifier; -unary(struct expr **expp;) - {struct type *tp; int oper;} -: -%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) - cast(&tp) unary(expp) - { ch7cast(expp, CAST, tp); - (*expp)->ex_flags |= EX_CAST; - } -| - postfixed(expp) -| - unop(&oper) unary(expp) - {ch7mon(oper, expp);} -| - size_of(expp) -; +unary(struct expr** expp;) + { + struct type* tp; + int oper; + } + : %if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) + cast(&tp) + unary(expp) + { + ch7cast(expp, CAST, tp); + (*expp)->ex_flags |= EX_CAST; + } + | postfixed(expp) + | unop(&oper) + unary(expp) + { ch7mon(oper, expp); } + | size_of(expp) + ; -size_of(struct expr **expp;) - {struct type *tp;} -: - SIZEOF - [%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) - cast(&tp) - { - *expp = intexpr(size_of_type(tp, "type"), INT); - (*expp)->ex_flags |= EX_SIZEOF; - } - | - unary(expp) - {ch7mon(SIZEOF, expp);} - ] -; +size_of(struct expr** expp;) + { + struct type* tp; + } + : SIZEOF + [ + %if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) + cast(&tp) + { + *expp = intexpr(size_of_type(tp, "type"), INT); + (*expp)->ex_flags |= EX_SIZEOF; + } + | unary(expp) + { ch7mon(SIZEOF, expp); } + ] + ; /* 7.3-7.12 */ /* The set of operators in C is stratified in 15 levels, with level - N being treated in RM 7.N. In principle each operator is - assigned a rank, ranging from 1 to 15. Such an expression can - be parsed by a construct like: - binary_expression(int maxrank;) - {int oper;} - : - binary_expression(maxrank - 1) - [%if (rank_of(DOT) <= maxrank) - binop(&oper) - binary_expression(rank_of(oper)-1) - ]? - ; - except that some call of 'unary' is necessary, depending on the - grammar. - - This simple view is marred by three complications: - 1. Level 15 (comma operator) is not allowed in many - contexts and is different. - 2. Level 13 (conditional operator) is a ternary operator, - which does not fit this scheme at all. - 3. Level 14 (assignment operators) group right-to-left, as - opposed to 2-12, which group left-to-right (or are - immaterial). - 4. The operators in level 14 start with operators in levels - 2-13 (RM 7.14: The two parts of a compound assignment - operator are separate tokens.) This causes LL1 problems. - This forces us to have four rules: - binary_expression for level 2-12 - conditional_expression for level 13 - assignment_expression for level 14 and - expression for the most general expression -*/ - -binary_expression(int maxrank; struct expr **expp;) - {int oper; struct expr *e1;} +N being treated in RM 7.N. In principle each operator is +assigned a rank, ranging from 1 to 15. Such an expression can +be parsed by a construct like: +binary_expression(int maxrank;) +{int oper;} : - unary(expp) - [%while (rank_of(DOT) <= maxrank && AHEAD != '=') - /* '?', '=', and ',' are no binops, and the test - for AHEAD != '=' keeps the other assignment - operators out - */ - binop(&oper) - binary_expression(rank_of(oper)-1, &e1) - { - ch7bin(expp, oper, e1); - } - ]* +binary_expression(maxrank - 1) +[%if (rank_of(DOT) <= maxrank) +binop(&oper) +binary_expression(rank_of(oper)-1) +]? ; +except that some call of 'unary' is necessary, depending on the +grammar. -/* 7.13 */ -conditional_expression(struct expr **expp;) -/* There is some unfortunate disagreement about what is allowed - between the '?' and the ':' of a conditional_expression. - Although the Ritchie compiler does not even allow - conditional_expressions there, some other compilers (e.g., VAX) - accept a full assignment_expression there, and programs - (like, e.g., emacs) rely on it. So we have little choice. +This simple view is marred by three complications: +1. Level 15 (comma operator) is not allowed in many +contexts and is different. +2. Level 13 (conditional operator) is a ternary operator, +which does not fit this scheme at all. +3. Level 14 (assignment operators) group right-to-left, as +opposed to 2-12, which group left-to-right (or are +immaterial). +4. The operators in level 14 start with operators in levels +2-13 (RM 7.14: The two parts of a compound assignment +operator are separate tokens.) This causes LL1 problems. +This forces us to have four rules: +binary_expression for level 2-12 +conditional_expression for level 13 +assignment_expression for level 14 and +expression for the most general expression */ - {struct expr *e1 = 0, *e2 = 0;} -: - /* allow all binary operators */ - binary_expression(rank_of('?') - 1, expp) - [ '?' - expression(&e1) - { -#ifndef NOROPTION - check_conditional(e1, '?', "between ? and :"); -#endif - } - ':' - assignment_expression(&e2) - { -#ifndef NOROPTION - check_conditional(e2, '=', "after :"); -#endif - ch7bin(&e1, ':', e2); - opnd2test(expp, '?'); - ch7bin(expp, '?', e1); - } - ]? -; + +binary_expression(int maxrank; struct expr** expp;) + { + int oper; + struct expr* e1; + } + : unary(expp) + [ + %while (rank_of(DOT) <= maxrank && AHEAD != '=') + /* '?', '=', and ',' are no binops, and the test + for AHEAD != '=' keeps the other assignment + operators out + */ + binop(&oper) + binary_expression(rank_of(oper) - 1, &e1) + { ch7bin(expp, oper, e1); } + ]* + ; + +/* 7.13 */ +conditional_expression(struct expr** expp;) + /* There is some unfortunate disagreement about what is allowed + between the '?' and the ':' of a conditional_expression. + Although the Ritchie compiler does not even allow + conditional_expressions there, some other compilers (e.g., VAX) + accept a full assignment_expression there, and programs + (like, e.g., emacs) rely on it. So we have little choice. + */ + { + struct expr *e1 = 0, *e2 = 0; + } + : + /* allow all binary operators */ + binary_expression(rank_of('?') - 1, expp) + [ + '?' + expression(&e1) + { + #ifndef NOROPTION + check_conditional(e1, '?', "between ? and :"); + #endif + } + ':' + assignment_expression(&e2) + { + #ifndef NOROPTION + check_conditional(e2, '=', "after :"); + #endif + ch7bin(&e1, ':', e2); + opnd2test(expp, '?'); + ch7bin(expp, '?', e1); + } + ]? + ; /* 7.14 */ -assignment_expression(struct expr **expp;) - { - int oper; - struct expr *e1 = 0; - } -: - conditional_expression(expp) - [%prefer /* (rank_of(DOT) <= maxrank) for any asgnop */ - asgnop(&oper) - assignment_expression(&e1) - {ch7asgn(expp, oper, e1);} - | - empty /* LLgen artefact ??? */ - ] -; +assignment_expression(struct expr** expp;) + { + int oper; + struct expr* e1 = 0; + } + : conditional_expression(expp) + [ + %prefer + /* (rank_of(DOT) <= maxrank) for any asgnop */ + asgnop(&oper) + assignment_expression(&e1) + { ch7asgn(expp, oper, e1); } + | empty + /* LLgen artefact ??? */ + ] + ; /* 7.15 */ -expression(struct expr **expp;) - {struct expr *e1;} -: - assignment_expression(expp) - [ ',' - assignment_expression(&e1) - { - ch7bin(expp, ',', e1); - } - ]* -; +expression(struct expr** expp;) + { + struct expr* e1; + } + : assignment_expression(expp) + [ + ',' + assignment_expression(&e1) + { ch7bin(expp, ',', e1); } + ]* + ; -unop(int *oper;) : - ['*' | '&' | '-' | '!' | '~' | PLUSPLUS | MINMIN] - {*oper = DOT;} -; +unop(int* oper;) + : [ + '*' + | '&' + | '-' + | '!' + | '~' + | PLUSPLUS + | MINMIN + ] + { *oper = DOT; } + ; -postop(int *oper;): - PLUSPLUS {*oper = POSTINCR;} -| - MINMIN {*oper = POSTDECR;} -; +postop(int* oper;) + : PLUSPLUS + { *oper = POSTINCR; } + | MINMIN + { *oper = POSTDECR; } + ; -multop: - '*' | '/' | '%' -; +multop + : '*' + | '/' + | '%' + ; -addop: - '+' | '-' -; +addop + : '+' + | '-' + ; -shiftop: - LEFT | RIGHT -; +shiftop + : LEFT + | RIGHT + ; -relop: - '<' | '>' | LESSEQ | GREATEREQ -; +relop + : '<' + | '>' + | LESSEQ + | GREATEREQ + ; -eqop: - EQUAL | NOTEQUAL -; +eqop + : EQUAL + | NOTEQUAL + ; -arithop: - multop | addop | shiftop -| - '&' | '^' | '|' -; +arithop + : multop + | addop + | shiftop + | '&' + | '^' + | '|' + ; -binop(int *oper;) : - [ arithop | relop | eqop | AND | OR ] - {*oper = DOT;} -; +binop(int* oper;) + : [ + arithop + | relop + | eqop + | AND + | OR + ] + { *oper = DOT; } + ; -asgnop(int *oper;): - '=' {*oper = DOT;} -| - '+' '=' {*oper = PLUSAB;} -| - '-' '=' {*oper = MINAB;} -| - '*' '=' {*oper = TIMESAB;} -| - '/' '=' {*oper = DIVAB;} -| - '%' '=' {*oper = MODAB;} -| - LEFT '=' {*oper = LEFTAB;} -| - RIGHT '=' {*oper = RIGHTAB;} -| - '&' '=' {*oper = ANDAB;} -| - '^' '=' {*oper = XORAB;} -| - '|' '=' {*oper = ORAB;} -; +asgnop(int* oper;) + : '=' + { *oper = DOT; } + | '+' '=' + { *oper = PLUSAB; } + | '-' '=' + { *oper = MINAB; } + | '*' '=' + { *oper = TIMESAB; } + | '/' '=' + { *oper = DIVAB; } + | '%' '=' + { *oper = MODAB; } + | LEFT '=' + { *oper = LEFTAB; } + | RIGHT '=' + { *oper = RIGHTAB; } + | '&' '=' + { *oper = ANDAB; } + | '^' '=' + { *oper = XORAB; } + | '|' '=' + { *oper = ORAB; } + ; -constant(struct expr **expp;) : -[ - INTEGER -| - FLOATING -] {dot2expr(expp);} -; +constant(struct expr** expp;) + : [ + INTEGER + | FLOATING + ] + { dot2expr(expp); } + ; /* 15 */ -constant_expression (struct expr **expp;) : - assignment_expression(expp) - {chk_cst_expr(expp);} -; +constant_expression(struct expr** expp;) + : assignment_expression(expp) + { chk_cst_expr(expp); } + ; -identifier(struct idf **idfp;) : -[ - IDENTIFIER -| - TYPE_IDENTIFIER -] - { - *idfp = dot.tk_idf; - } -; +identifier(struct idf** idfp;) + : [ + IDENTIFIER + | TYPE_IDENTIFIER + ] + { *idfp = dot.tk_idf; } + ; diff --git a/lang/cem/cemcom/ival.g b/lang/cem/cemcom/ival.g index e7ca7f6ce..7be7df200 100644 --- a/lang/cem/cemcom/ival.g +++ b/lang/cem/cemcom/ival.g @@ -2,709 +2,755 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cemcom/ival.g + */ /* $Id$ */ /* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */ { -#include "lint.h" -#include "nofloat.h" -#ifndef LINT -#include -#else -#include "l_em.h" -#include "l_lint.h" -#endif /* LINT */ -#include "debug.h" -#include -#include "nobitfield.h" -#include "arith.h" -#include "label.h" -#include "expr.h" -#include "type.h" -#include "struct.h" -#include "field.h" -#include "assert.h" -#include "Lpars.h" -#include "sizes.h" -#include "align.h" -#include "idf.h" -#include "level.h" -#include "def.h" -#include "LLlex.h" -#include "noRoption.h" -#include "estack.h" - -#define con_nullbyte() C_con_ucon("0", (arith)1) -#define aggregate_type(tp) ((tp)->tp_fund == ARRAY || (tp)->tp_fund == STRUCT) - -char *long2str(); -char *strncpy(); -extern char options[]; -static int gen_error; -static int pack_level; -struct type **gen_tphead(), **gen_tpmiddle(); -struct sdef *gen_align_to_next(); -struct e_stack *p_stack; + #include "lint.h" + #include "nofloat.h" + #ifndef LINT + #include + #else + #include "l_em.h" + #include "l_lint.h" + #endif /* LINT */ + #include "debug.h" + #include + #include "nobitfield.h" + #include "arith.h" + #include "label.h" + #include "expr.h" + #include "type.h" + #include "struct.h" + #include "field.h" + #include "assert.h" + #include "Lpars.h" + #include "sizes.h" + #include "align.h" + #include "idf.h" + #include "level.h" + #include "def.h" + #include "LLlex.h" + #include "noRoption.h" + #include "estack.h" + + #define con_nullbyte() C_con_ucon("0", (arith)1) + #define aggregate_type(tp) ((tp)->tp_fund == ARRAY || (tp)->tp_fund == STRUCT) + + char* long2str(); + char* strncpy(); + extern char options[]; + static int gen_error; + static int pack_level; + struct type **gen_tphead(), **gen_tpmiddle(); + struct sdef* gen_align_to_next(); + struct e_stack* p_stack; } /* initial_value recursively guides the initialisation expression. - Upto now, the initialisation of a union is not allowed! +Upto now, the initialisation of a union is not allowed! */ /* 7 */ -initial_value(struct type **tpp; struct expr **expp;) : - { if (tpp) gen_tpcheck(tpp, 0); } -[ - assignment_expression(expp) - { -#ifdef LINT - lint_expr(*expp, USED); -#endif /* LINT */ - if ((*expp)->ex_type->tp_fund == ARRAY) - array2pointer(*expp); - if (tpp) { - gen_simple_exp(tpp, expp); - free_expression(*expp); - *expp = 0; - } - } -| - initial_value_pack(tpp, expp) -] -; - -initial_value_pack(struct type **tpp; struct expr **expp;) -: - '{' - { if (pack_level == 0) gen_error = 0; pack_level++; } - initial_value_list(tpp, expp) - { pack_level--; - if (!pack_level) { - while (p_stack) { - struct e_stack *p = p_stack->next; - - free_e_stack(p_stack); - p_stack = p; - } - } - if (pack_level < gen_error) gen_error = 0; - } - '}' -; - -initial_value_list(struct type **tpp; struct expr **expp;) - { struct expr *e1; - struct type **tpp2 = 0; - int err_flag = gen_error; - } -: - { if (tpp) tpp2 = gen_tphead(tpp, 0); } - initial_value(tpp2, &e1) - { if (!tpp) init_expression(&expp, e1); } - [%while (AHEAD != '}') /* >>> conflict on ',' */ - ',' - { if (tpp) tpp2 = gen_tpmiddle(); } - initial_value(tpp2, &e1) - { if (!tpp) init_expression(&expp, e1); } - ]* - { if (tpp && ! err_flag) gen_tpend(); } - ','? /* optional trailing comma */ -; - -{ -gen_tpcheck(tpp, union_allowed) - struct type **tpp; -{ - struct type *tp; - - if (gen_error) return; - switch((tp = *tpp)->tp_fund) { - case ARRAY: - if (! valid_type(tp->tp_up, "array element")) - gen_error = pack_level; - break; - case STRUCT: - if (! valid_type(tp, "struct")) - gen_error = pack_level; - break; - case UNION: - if (! union_allowed) { - error("union initialization not allowed"); - gen_error = pack_level; - break; - } - if (! valid_type(tp, "union")) - gen_error = pack_level; - break; - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - break; - } -} - -gen_simple_exp(tpp, expp) - struct type **tpp; - struct expr **expp; -{ - struct type *tp; - - if (gen_error) return; - tp = *tpp; - switch(tp->tp_fund) { - case ARRAY: - if ((*expp)->ex_class == String && tp->tp_up->tp_fund == CHAR) { - ch_array(tpp,*expp); - break; - } - /* Fall through */ - case STRUCT: - check_and_pad(expp, tpp); - break; - case ERRONEOUS: - gen_error = pack_level; - break; - default: - check_ival(expp, tp); - break; - } -} - -struct type ** -arr_elem(tpp, p) - struct type **tpp; - struct e_stack *p; -{ - struct type *tp = *tpp; - - if (tp->tp_up->tp_fund == CHAR && AHEAD == STRING && p->elem_count == 1) { - p->nelem = 1; - return tpp; - } - if (AHEAD == '{' || ! aggregate_type(tp->tp_up)) - return &(tp->tp_up); - return gen_tphead(&(tp->tp_up), 1); -} - -struct sdef * -next_field(sd, p) - struct sdef *sd; - struct e_stack *p; -{ - if (sd->sd_sdef) - p->bytes_upto_here += zero_bytes(sd); - p->bytes_upto_here += - size_of_type(sd->sd_type, "selector"); - p->last_offset = sd->sd_offset; - return sd->sd_sdef; -} - -struct type ** -gen_tphead(tpp, nest) - struct type **tpp; -{ - struct type *tp = *tpp; - struct e_stack *p; - struct sdef *sd; - - if (tpp && *tpp == error_type) { - gen_error = pack_level; - return 0; - } - if (gen_error) return tpp; - p = new_e_stack(); - p->next = p_stack; - p_stack = p; - p->s_nested = nest; - p->s_tpp = tpp; - switch(tp->tp_fund) { - case ARRAY: - p->nelem = -1; - p->elem_count = 1; - if (tp->tp_size != (arith) -1) { - p->nelem = (tp->tp_size / tp->tp_up->tp_size); - } - return arr_elem(tpp, p); - case STRUCT: - p->s_def = sd = tp->tp_sdef; - p->bytes_upto_here = 0; - p->last_offset = -1; -#ifndef NOBITFIELD - while (sd && is_anon_idf(sd->sd_idf)) { - put_bf(sd->sd_type, (arith) 0); - sd = next_field(sd, p); - } -#endif - if (! sd) { - /* something wrong with this struct */ - gen_error = pack_level; - p_stack = p->next; - free_e_stack(p); - return 0; - } - p->s_def = sd; - if (AHEAD != '{' && aggregate_type(sd->sd_type)) { - return gen_tphead(&(sd->sd_type), 1); - } - return &(sd->sd_type); - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - /* fall through */ - default: - p->nelem = 1; - p->elem_count = 1; - return tpp; - } -} - -struct type ** -gen_tpmiddle() -{ - struct type *tp; - struct sdef *sd; - struct e_stack *p = p_stack; - - if (gen_error) { - if (p) return p->s_tpp; - return 0; - } -again: - tp = *(p->s_tpp); - switch(tp->tp_fund) { - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - return p->s_tpp; - default: - if (p->elem_count == p->nelem && p->s_nested) { - p = p->next; - free_e_stack(p_stack); - p_stack = p; - goto again; - } - p->elem_count++; - if (p->nelem >= 0 && p->elem_count > p->nelem) { - too_many_initialisers(); - return p->s_tpp; - } - if (tp->tp_fund == ARRAY) { - return arr_elem(p->s_tpp, p); - } - return p->s_tpp; - case STRUCT: - sd = gen_align_to_next(p); - if (! sd) { - while (p->bytes_upto_here++ < tp->tp_size) - con_nullbyte(); - if (p->s_nested) { - p = p->next; - free_e_stack(p_stack); - p_stack = p; - goto again; - } - too_many_initialisers(); - return p->s_tpp; - } - if (AHEAD != '{' && aggregate_type(sd->sd_type)) { - return gen_tphead(&(sd->sd_type), 1); - } - return &(sd->sd_type); - } -} +initial_value(struct type** tpp; struct expr** expp;) + : + { if (tpp) gen_tpcheck(tpp, 0); } + [ + assignment_expression(expp) + { + #ifdef LINT + lint_expr(*expp, USED); + #endif /* LINT */ + if ((*expp)->ex_type->tp_fund == ARRAY) + array2pointer(*expp); + if (tpp) + { + gen_simple_exp(tpp, expp); + free_expression(*expp); + *expp = 0; + } + } + | initial_value_pack(tpp, expp) + ] + ; + +initial_value_pack(struct type** tpp; struct expr** expp;) + : '{' + { + if (pack_level == 0) + gen_error = 0; + pack_level++; + } + initial_value_list(tpp, expp) + { + pack_level--; + if (!pack_level) + { + while (p_stack) + { + struct e_stack* p = p_stack->next; + + free_e_stack(p_stack); + p_stack = p; + } + } + if (pack_level < gen_error) + gen_error = 0; + } + '}' + ; + +initial_value_list(struct type** tpp; struct expr** expp;) + { + struct expr* e1; + struct type** tpp2 = 0; + int err_flag = gen_error; + } + : + { if (tpp) tpp2 = gen_tphead(tpp, 0); } + initial_value(tpp2, &e1) + { if (!tpp) init_expression(&expp, e1); } + [ + %while (AHEAD != '}') + /* >>> conflict on ',' */ + ',' + { if (tpp) tpp2 = gen_tpmiddle(); } + initial_value(tpp2, &e1) + { if (!tpp) init_expression(&expp, e1); } + ]* + { if (tpp && !err_flag) gen_tpend(); } + ','? + /* optional trailing comma */ + ; -struct sdef * -gen_align_to_next(p) - struct e_stack *p; { - struct sdef *sd = p->s_def; - - if (! sd) return sd; -#ifndef NOBITFIELD - do { - if (is_anon_idf(sd->sd_idf)) put_bf(sd->sd_type, (arith) 0); -#endif - sd = next_field(sd, p); -#ifndef NOBITFIELD - } while (sd && is_anon_idf(sd->sd_idf)); -#endif - p->s_def = sd; - return sd; -} - -gen_tpend() -{ - struct e_stack *p = p_stack; - struct type *tp; - struct sdef *sd; - int getout = 0; - - while (!getout && p) { - if (!gen_error) { - tp = *(p->s_tpp); - switch(tp->tp_fund) { - case ARRAY: - if (tp->tp_size == -1) { - *(p->s_tpp) = construct_type(ARRAY, - tp->tp_up, p->elem_count); - } - else { - while (p->nelem-- > p->elem_count) { - pad(tp->tp_up); - } - } - break; - case STRUCT: - sd = gen_align_to_next(p); - while (sd) { - pad(sd->sd_type); - if (sd->sd_sdef) - p->bytes_upto_here += zero_bytes(sd); - p->bytes_upto_here += - size_of_type(sd->sd_type, "selector"); - sd = sd->sd_sdef; - } - while (p->bytes_upto_here++ < tp->tp_size) - con_nullbyte(); - break; - } - } - if (! p->s_nested) getout = 1; - p = p->next; - free_e_stack(p_stack); - p_stack = p; - } -} - -/* check_and_pad() is given a simple initialisation expression - where the type can be either a simple or an aggregate type. - In the latter case, only the first member is initialised and - the rest is zeroed. -*/ -check_and_pad(expp, tpp) - struct type **tpp; - struct expr **expp; -{ - struct type *tp = *tpp; - - if (tp->tp_fund == ARRAY) { - check_and_pad(expp, &(tp->tp_up)); /* first member */ - if (tp->tp_size == (arith)-1) - /* no size specified upto here: just - set it to the size of one member. - */ - tp = *tpp = construct_type(ARRAY, tp->tp_up, (arith)1); - else { - int dim = tp->tp_size / tp->tp_up->tp_size; - /* pad remaining members with zeroes */ - while (--dim > 0) - pad(tp->tp_up); - } - } - else - if (tp->tp_fund == STRUCT) { - struct sdef *sd = tp->tp_sdef; - - check_and_pad(expp, &(sd->sd_type)); - /* next selector is aligned by adding extra zeroes */ - if (sd->sd_sdef) - zero_bytes(sd); - while (sd = sd->sd_sdef) { /* pad remaining selectors */ - pad(sd->sd_type); - if (sd->sd_sdef) - zero_bytes(sd); - } - } - else /* simple type */ - check_ival(expp, tp); -} - -/* pad() fills an element of type tp with zeroes. - If the element is an aggregate, pad() is called recursively. -*/ -pad(tpx) - struct type *tpx; -{ - struct type *tp = tpx; - arith sz = tp->tp_size; - - gen_tpcheck(&tpx, 1); - if (gen_error) return; - switch (tp->tp_fund) { - case UNION: -#ifndef NOROPTION - if (options['R']) { - warning("initialization of unions not allowed"); - } -#endif - break; -#ifndef NOBITFIELD - case FIELD: - put_bf(tp, (arith)0); - return; -#endif /* NOBITFIELD */ - default: - break; - } - - if (tp->tp_align >= word_align) while (sz >= word_size) { - C_con_cst((arith) 0); - sz -= word_size; - } - while (sz) { - C_con_icon("0", (arith) 1); - sz--; - } -} - -/* check_ival() checks whether the initialisation of an element - of a fundamental type is legal and, if so, performs the initialisation - by directly generating the necessary code. - No further comment is needed to explain the internal structure - of this straightforward function. -*/ -check_ival(expp, tp) - struct type *tp; - struct expr **expp; -{ - /* The philosophy here is that ch7cast puts an explicit - conversion node in front of the expression if the types - are not compatible. In this case, the initialisation - expression is no longer a constant. - */ - struct expr *expr = *expp; - - switch (tp->tp_fund) { - case CHAR: - case SHORT: - case INT: - case LONG: - case ENUM: - case POINTER: - ch7cast(expp, '=', tp); - expr = *expp; -#ifdef DEBUG - print_expr("init-expr after cast", expr); -#endif /* DEBUG */ - if (!is_ld_cst(expr)) - illegal_init_cst(expr); - else - if (expr->VL_CLASS == Const) - con_int(expr); - else - if (expr->VL_CLASS == Name) { - struct idf *idf = expr->VL_IDF; - - if (idf->id_def->df_level >= L_LOCAL) - illegal_init_cst(expr); - else /* e.g., int f(); int p = f; */ - if (idf->id_def->df_type->tp_fund == FUNCTION) - C_con_pnam(idf->id_text); - else /* e.g., int a; int *p = &a; */ - C_con_dnam(idf->id_text, expr->VL_VALUE); - } - else { - ASSERT(expr->VL_CLASS == Label); - C_con_dlb(expr->VL_LBL, expr->VL_VALUE); - } - break; -#ifndef NOFLOAT - case FLOAT: - case DOUBLE: - ch7cast(expp, '=', tp); - expr = *expp; -#ifdef DEBUG - print_expr("init-expr after cast", expr); -#endif /* DEBUG */ - if (expr->ex_class == Float) - C_con_fcon(expr->FL_VALUE, expr->ex_type->tp_size); -#ifdef NOTDEF - -Coercion from int to float is now always done compile time. -This, to accept declarations like -double x = -(double)1; + gen_tpcheck(tpp, union_allowed) struct type** tpp; + { + struct type* tp; + + if (gen_error) + return; + switch ((tp = *tpp)->tp_fund) + { + case ARRAY: + if (!valid_type(tp->tp_up, "array element")) + gen_error = pack_level; + break; + case STRUCT: + if (!valid_type(tp, "struct")) + gen_error = pack_level; + break; + case UNION: + if (!union_allowed) + { + error("union initialization not allowed"); + gen_error = pack_level; + break; + } + if (!valid_type(tp, "union")) + gen_error = pack_level; + break; + case ERRONEOUS: + if (!gen_error) + gen_error = pack_level; + break; + } + } + + gen_simple_exp(tpp, expp) struct type** tpp; + struct expr** expp; + { + struct type* tp; + + if (gen_error) + return; + tp = *tpp; + switch (tp->tp_fund) + { + case ARRAY: + if ((*expp)->ex_class == String && tp->tp_up->tp_fund == CHAR) + { + ch_array(tpp, *expp); + break; + } + /* Fall through */ + case STRUCT: + check_and_pad(expp, tpp); + break; + case ERRONEOUS: + gen_error = pack_level; + break; + default: + check_ival(expp, tp); + break; + } + } + + struct type** arr_elem(tpp, p) struct type** tpp; + struct e_stack* p; + { + struct type* tp = *tpp; + + if (tp->tp_up->tp_fund == CHAR && AHEAD == STRING && p->elem_count == 1) + { + p->nelem = 1; + return tpp; + } + if (AHEAD == '{' || !aggregate_type(tp->tp_up)) + return &(tp->tp_up); + return gen_tphead(&(tp->tp_up), 1); + } + + struct sdef* next_field(sd, p) struct sdef* sd; + struct e_stack* p; + { + if (sd->sd_sdef) + p->bytes_upto_here += zero_bytes(sd); + p->bytes_upto_here += size_of_type(sd->sd_type, "selector"); + p->last_offset = sd->sd_offset; + return sd->sd_sdef; + } + + struct type** gen_tphead(tpp, nest) struct type** tpp; + { + struct type* tp = *tpp; + struct e_stack* p; + struct sdef* sd; + + if (tpp && *tpp == error_type) + { + gen_error = pack_level; + return 0; + } + if (gen_error) + return tpp; + p = new_e_stack(); + p->next = p_stack; + p_stack = p; + p->s_nested = nest; + p->s_tpp = tpp; + switch (tp->tp_fund) + { + case ARRAY: + p->nelem = -1; + p->elem_count = 1; + if (tp->tp_size != (arith)-1) + { + p->nelem = (tp->tp_size / tp->tp_up->tp_size); + } + return arr_elem(tpp, p); + case STRUCT: + p->s_def = sd = tp->tp_sdef; + p->bytes_upto_here = 0; + p->last_offset = -1; + #ifndef NOBITFIELD + while (sd && is_anon_idf(sd->sd_idf)) + { + put_bf(sd->sd_type, (arith)0); + sd = next_field(sd, p); + } + #endif + if (!sd) + { + /* something wrong with this struct */ + gen_error = pack_level; + p_stack = p->next; + free_e_stack(p); + return 0; + } + p->s_def = sd; + if (AHEAD != '{' && aggregate_type(sd->sd_type)) + { + return gen_tphead(&(sd->sd_type), 1); + } + return &(sd->sd_type); + case ERRONEOUS: + if (!gen_error) + gen_error = pack_level; + /* fall through */ + default: + p->nelem = 1; + p->elem_count = 1; + return tpp; + } + } + + struct type** gen_tpmiddle() + { + struct type* tp; + struct sdef* sd; + struct e_stack* p = p_stack; + + if (gen_error) + { + if (p) + return p->s_tpp; + return 0; + } + again: + tp = *(p->s_tpp); + switch (tp->tp_fund) + { + case ERRONEOUS: + if (!gen_error) + gen_error = pack_level; + return p->s_tpp; + default: + if (p->elem_count == p->nelem && p->s_nested) + { + p = p->next; + free_e_stack(p_stack); + p_stack = p; + goto again; + } + p->elem_count++; + if (p->nelem >= 0 && p->elem_count > p->nelem) + { + too_many_initialisers(); + return p->s_tpp; + } + if (tp->tp_fund == ARRAY) + { + return arr_elem(p->s_tpp, p); + } + return p->s_tpp; + case STRUCT: + sd = gen_align_to_next(p); + if (!sd) + { + while (p->bytes_upto_here++ < tp->tp_size) + con_nullbyte(); + if (p->s_nested) + { + p = p->next; + free_e_stack(p_stack); + p_stack = p; + goto again; + } + too_many_initialisers(); + return p->s_tpp; + } + if (AHEAD != '{' && aggregate_type(sd->sd_type)) + { + return gen_tphead(&(sd->sd_type), 1); + } + return &(sd->sd_type); + } + } + + struct sdef* gen_align_to_next(p) struct e_stack* p; + { + struct sdef* sd = p->s_def; + + if (!sd) + return sd; + #ifndef NOBITFIELD + do + { + if (is_anon_idf(sd->sd_idf)) + put_bf(sd->sd_type, (arith)0); + #endif + sd = next_field(sd, p); + #ifndef NOBITFIELD + } while (sd && is_anon_idf(sd->sd_idf)); + #endif + p->s_def = sd; + return sd; + } + + gen_tpend() + { + struct e_stack* p = p_stack; + struct type* tp; + struct sdef* sd; + int getout = 0; + + while (!getout && p) + { + if (!gen_error) + { + tp = *(p->s_tpp); + switch (tp->tp_fund) + { + case ARRAY: + if (tp->tp_size == -1) + { + *(p->s_tpp) = construct_type(ARRAY, tp->tp_up, p->elem_count); + } + else + { + while (p->nelem-- > p->elem_count) + { + pad(tp->tp_up); + } + } + break; + case STRUCT: + sd = gen_align_to_next(p); + while (sd) + { + pad(sd->sd_type); + if (sd->sd_sdef) + p->bytes_upto_here += zero_bytes(sd); + p->bytes_upto_here += size_of_type(sd->sd_type, "selector"); + sd = sd->sd_sdef; + } + while (p->bytes_upto_here++ < tp->tp_size) + con_nullbyte(); + break; + } + } + if (!p->s_nested) + getout = 1; + p = p->next; + free_e_stack(p_stack); + p_stack = p; + } + } + + /* check_and_pad() is given a simple initialisation expression + where the type can be either a simple or an aggregate type. + In the latter case, only the first member is initialised and + the rest is zeroed. + */ + check_and_pad(expp, tpp) struct type** tpp; + struct expr** expp; + { + struct type* tp = *tpp; + + if (tp->tp_fund == ARRAY) + { + check_and_pad(expp, &(tp->tp_up)); /* first member */ + if (tp->tp_size == (arith)-1) + /* no size specified upto here: just + set it to the size of one member. + */ + tp = *tpp = construct_type(ARRAY, tp->tp_up, (arith)1); + else + { + int dim = tp->tp_size / tp->tp_up->tp_size; + /* pad remaining members with zeroes */ + while (--dim > 0) + pad(tp->tp_up); + } + } + else if (tp->tp_fund == STRUCT) + { + struct sdef* sd = tp->tp_sdef; + + check_and_pad(expp, &(sd->sd_type)); + /* next selector is aligned by adding extra zeroes */ + if (sd->sd_sdef) + zero_bytes(sd); + while (sd = sd->sd_sdef) + { /* pad remaining selectors */ + pad(sd->sd_type); + if (sd->sd_sdef) + zero_bytes(sd); + } + } + else /* simple type */ + check_ival(expp, tp); + } + + /* pad() fills an element of type tp with zeroes. + If the element is an aggregate, pad() is called recursively. + */ + pad(tpx) struct type* tpx; + { + struct type* tp = tpx; + arith sz = tp->tp_size; + + gen_tpcheck(&tpx, 1); + if (gen_error) + return; + switch (tp->tp_fund) + { + case UNION: + #ifndef NOROPTION + if (options['R']) + { + warning("initialization of unions not allowed"); + } + #endif + break; + #ifndef NOBITFIELD + case FIELD: + put_bf(tp, (arith)0); + return; + #endif /* NOBITFIELD */ + default: + break; + } + + if (tp->tp_align >= word_align) + while (sz >= word_size) + { + C_con_cst((arith)0); + sz -= word_size; + } + while (sz) + { + C_con_icon("0", (arith)1); + sz--; + } + } + + /* check_ival() checks whether the initialisation of an element + of a fundamental type is legal and, if so, performs the initialisation + by directly generating the necessary code. + No further comment is needed to explain the internal structure + of this straightforward function. + */ + check_ival(expp, tp) struct type* tp; + struct expr** expp; + { + /* The philosophy here is that ch7cast puts an explicit + conversion node in front of the expression if the types + are not compatible. In this case, the initialisation + expression is no longer a constant. + */ + struct expr* expr = *expp; + + switch (tp->tp_fund) + { + case CHAR: + case SHORT: + case INT: + case LONG: + case ENUM: + case POINTER: + ch7cast(expp, '=', tp); + expr = *expp; + #ifdef DEBUG + print_expr("init-expr after cast", expr); + #endif /* DEBUG */ + if (!is_ld_cst(expr)) + illegal_init_cst(expr); + else if (expr->VL_CLASS == Const) + con_int(expr); + else if (expr->VL_CLASS == Name) + { + struct idf* idf = expr->VL_IDF; + + if (idf->id_def->df_level >= L_LOCAL) + illegal_init_cst(expr); + else /* e.g., int f(); int p = f; */ + if (idf->id_def->df_type->tp_fund == FUNCTION) + C_con_pnam(idf->id_text); + else /* e.g., int a; int *p = &a; */ + C_con_dnam(idf->id_text, expr->VL_VALUE); + } + else + { + ASSERT(expr->VL_CLASS == Label); + C_con_dlb(expr->VL_LBL, expr->VL_VALUE); + } + break; + #ifndef NOFLOAT + case FLOAT: + case DOUBLE: + ch7cast(expp, '=', tp); + expr = *expp; + #ifdef DEBUG + print_expr("init-expr after cast", expr); + #endif /* DEBUG */ + if (expr->ex_class == Float) + C_con_fcon(expr->FL_VALUE, expr->ex_type->tp_size); + #ifdef NOTDEF + + Coercion from int to float is now always done compile time.This, + to accept declarations like double x = -(double)1; and also to prevent runtime coercions for compile-time constants. else - if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) { - /* float f = 1; */ - expr = expr->OP_RIGHT; - if (is_cp_cst(expr)) - C_con_fcon(long2str((long)expr->VL_VALUE, 10), - tp->tp_size); - else - illegal_init_cst(expr); - } -#endif /* NOTDEF */ - else - illegal_init_cst(expr); - break; -#endif /* NOFLOAT */ - -#ifndef NOBITFIELD - case FIELD: - ch7cast(expp, '=', tp->tp_up); - expr = *expp; -#ifdef DEBUG - print_expr("init-expr after cast", expr); -#endif /* DEBUG */ - if (is_cp_cst(expr)) - put_bf(tp, expr->VL_VALUE); - else - illegal_init_cst(expr); - break; -#endif /* NOBITFIELD */ - - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - break; - default: - crash("check_ival"); - /*NOTREACHED*/ - } -} - -/* ch_array() initialises an array of characters when given - a string constant. - Alignment is taken care of. -*/ -ch_array(tpp, ex) - struct type **tpp; /* type tp = array of characters */ - struct expr *ex; -{ - struct type *tp = *tpp; - int length = ex->SG_LEN, i; - char *to, *from, *s; - - ASSERT(ex->ex_class == String); - if (tp->tp_size == (arith)-1) { - /* set the dimension */ - tp = *tpp = construct_type(ARRAY, tp->tp_up, (arith)length); - } - else { - arith dim = tp->tp_size / tp->tp_up->tp_size; - - if (length > dim) { - expr_warning(ex, "too many initializers"); - } - length = dim; - } - /* throw out the characters of the already prepared string */ - s = malloc((unsigned) (length)); - clear(s, length); - i = length <= ex->SG_LEN ? length : ex->SG_LEN; - to = s; from = ex->SG_VALUE; - while(--i >= 0) { - *to++ = *from++; - } - free(ex->SG_VALUE); - str_cst(s, length); - free(s); -} - -/* As long as some parts of the pipeline cannot handle very long string - constants, string constants are written out in chunks -*/ -str_cst(str, len) - char *str; - int len; -{ - int chunksize = ((127 + (int) word_size) / (int) word_size) * (int) word_size; - - while (len > chunksize) { - C_con_scon(str, (arith) chunksize); - len -= chunksize; - str += chunksize; - } - C_con_scon(str, (arith) len); -} - -#ifndef NOBITFIELD -/* put_bf() takes care of the initialisation of (bit-)field - selectors of a struct: each time such an initialisation takes place, - put_bf() is called instead of the normal code generating routines. - Put_bf() stores the given integral value into "field" and - "throws" the result of "field" out if the current selector - is the last of this number of fields stored at the same address. -*/ -put_bf(tp, val) - struct type *tp; - arith val; -{ - static long field = (arith)0; - static arith offset = (arith)-1; - struct field *fd = tp->tp_field; - struct sdef *sd = fd->fd_sdef; - static struct expr exp; - - ASSERT(sd); - if (offset == (arith)-1) { - /* first bitfield in this field */ - offset = sd->sd_offset; - exp.ex_type = tp->tp_up; - exp.ex_class = Value; - exp.VL_CLASS = Const; - } - if (val != 0) /* insert the value into "field" */ - field |= (val & fd->fd_mask) << fd->fd_shift; - if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) { - /* the selector was the last stored at this address */ - exp.VL_VALUE = field; - con_int(&exp); - field = (arith)0; - offset = (arith)-1; - } -} -#endif /* NOBITFIELD */ - -int -zero_bytes(sd) - struct sdef *sd; -{ - /* fills the space between a selector of a struct - and the next selector of that struct with zero-bytes. - */ - int n = sd->sd_sdef->sd_offset - sd->sd_offset - - size_of_type(sd->sd_type, "struct member"); - int count = n; - - while (n-- > 0) - con_nullbyte(); - return count; -} - -int -valid_type(tp, str) - struct type *tp; - char *str; -{ - if (tp->tp_size < 0) { - error("size of %s unknown", str); - return 0; - } - return 1; -} - -con_int(ex) - struct expr *ex; -{ - struct type *tp = ex->ex_type; - - ASSERT(is_cp_cst(ex)); - if (tp->tp_unsigned) - C_con_ucon(long2str((long)ex->VL_VALUE, -10), tp->tp_size); - else if (tp->tp_size == word_size) - C_con_cst(ex->VL_VALUE); - else - C_con_icon(long2str((long)ex->VL_VALUE, 10), tp->tp_size); -} - -illegal_init_cst(ex) - struct expr *ex; -{ - expr_error(ex, "illegal initialization constant"); - gen_error = pack_level; -} - -too_many_initialisers() + if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) { - error("too many initializers"); - gen_error = pack_level; + /* float f = 1; */ + expr = expr->OP_RIGHT; + if (is_cp_cst(expr)) + C_con_fcon(long2str((long)expr->VL_VALUE, 10), tp->tp_size); + else + illegal_init_cst(expr); } + #endif /* NOTDEF */ +else illegal_init_cst(expr); +break; + #endif /* NOFLOAT */ + + #ifndef NOBITFIELD + case FIELD: + ch7cast(expp, '=', tp->tp_up); + expr = *expp; + #ifdef DEBUG + print_expr("init-expr after cast", expr); + #endif /* DEBUG */ + if (is_cp_cst(expr)) + put_bf(tp, expr->VL_VALUE); + else + illegal_init_cst(expr); + break; + #endif /* NOBITFIELD */ + + case ERRONEOUS: + if (!gen_error) + gen_error = pack_level; + break; + default: + crash("check_ival"); + /*NOTREACHED*/ + } + } + + /* ch_array() initialises an array of characters when given + a string constant. + Alignment is taken care of. + */ + ch_array(tpp, ex) struct type** tpp; /* type tp = array of characters */ + struct expr* ex; + { + struct type* tp = *tpp; + int length = ex->SG_LEN, i; + char *to, *from, *s; + + ASSERT(ex->ex_class == String); + if (tp->tp_size == (arith)-1) + { + /* set the dimension */ + tp = *tpp = construct_type(ARRAY, tp->tp_up, (arith)length); + } + else + { + arith dim = tp->tp_size / tp->tp_up->tp_size; + + if (length > dim) + { + expr_warning(ex, "too many initializers"); + } + length = dim; + } + /* throw out the characters of the already prepared string */ + s = malloc((unsigned)(length)); + clear(s, length); + i = length <= ex->SG_LEN ? length : ex->SG_LEN; + to = s; + from = ex->SG_VALUE; + while (--i >= 0) + { + *to++ = *from++; + } + free(ex->SG_VALUE); + str_cst(s, length); + free(s); + } + + /* As long as some parts of the pipeline cannot handle very long string + constants, string constants are written out in chunks + */ + str_cst(str, len) char* str; + int len; + { + int chunksize = ((127 + (int)word_size) / (int)word_size) * (int)word_size; + + while (len > chunksize) + { + C_con_scon(str, (arith)chunksize); + len -= chunksize; + str += chunksize; + } + C_con_scon(str, (arith)len); + } + + #ifndef NOBITFIELD + /* put_bf() takes care of the initialisation of (bit-)field + selectors of a struct: each time such an initialisation takes place, + put_bf() is called instead of the normal code generating routines. + Put_bf() stores the given integral value into "field" and + "throws" the result of "field" out if the current selector + is the last of this number of fields stored at the same address. + */ + put_bf(tp, val) struct type* tp; + arith val; + { + static long field = (arith)0; + static arith offset = (arith)-1; + struct field* fd = tp->tp_field; + struct sdef* sd = fd->fd_sdef; + static struct expr exp; + + ASSERT(sd); + if (offset == (arith)-1) + { + /* first bitfield in this field */ + offset = sd->sd_offset; + exp.ex_type = tp->tp_up; + exp.ex_class = Value; + exp.VL_CLASS = Const; + } + if (val != 0) /* insert the value into "field" */ + field |= (val & fd->fd_mask) << fd->fd_shift; + if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) + { + /* the selector was the last stored at this address */ + exp.VL_VALUE = field; + con_int(&exp); + field = (arith)0; + offset = (arith)-1; + } + } + #endif /* NOBITFIELD */ + + int zero_bytes(sd) struct sdef* sd; + { + /* fills the space between a selector of a struct + and the next selector of that struct with zero-bytes. + */ + int n = sd->sd_sdef->sd_offset - sd->sd_offset - size_of_type(sd->sd_type, "struct member"); + int count = n; + + while (n-- > 0) + con_nullbyte(); + return count; + } + + int valid_type(tp, str) struct type* tp; + char* str; + { + if (tp->tp_size < 0) + { + error("size of %s unknown", str); + return 0; + } + return 1; + } + + con_int(ex) struct expr* ex; + { + struct type* tp = ex->ex_type; + + ASSERT(is_cp_cst(ex)); + if (tp->tp_unsigned) + C_con_ucon(long2str((long)ex->VL_VALUE, -10), tp->tp_size); + else if (tp->tp_size == word_size) + C_con_cst(ex->VL_VALUE); + else + C_con_icon(long2str((long)ex->VL_VALUE, 10), tp->tp_size); + } + + illegal_init_cst(ex) struct expr* ex; + { + expr_error(ex, "illegal initialization constant"); + gen_error = pack_level; + } + + too_many_initialisers() + { + error("too many initializers"); + gen_error = pack_level; + } } diff --git a/lang/cem/cemcom/program.g b/lang/cem/cemcom/program.g index 394cd3cfc..08266c18d 100644 --- a/lang/cem/cemcom/program.g +++ b/lang/cem/cemcom/program.g @@ -2,211 +2,217 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cemcom/program.g + */ /* $Id$ */ /* PROGRAM PARSER */ /* The presence of typedef declarations renders it impossible to - make a context-free grammar of C. Consequently we need - context-sensitive parsing techniques, the simplest one being - a subtle cooperation between the parser and the lexical scanner. - The lexical scanner has to know whether to return IDENTIFIER - or TYPE_IDENTIFIER for a given tag, and it obtains this information - from the definition list, as constructed by the parser. - The present grammar is essentially LL(2), and is processed by - a parser generator which accepts LL(1) with tie breaking rules - in C, of the form %if(cond) and %while(cond). To solve the LL(1) - ambiguities, the lexical scanner does a one symbol look-ahead. - This symbol, however, cannot always be correctly assessed, since - the present symbol may cause a change in the definition list - which causes the identification of the look-ahead symbol to be - invalidated. - The lexical scanner relies on the parser (or its routines) to - detect this situation and then update the look-ahead symbol. - An alternative approach would be to reassess the look-ahead symbol - in the lexical scanner when it is promoted to dot symbol. This - would be more beautiful but less correct, since then for a short - while there would be a discrepancy between the look-ahead symbol - and the definition list; I think it would nevertheless work in - correct programs. - A third solution would be to enter the identifier as soon as it - is found; its storage class is then known, although its full type - isn't. We would have to fill that in afterwards. +make a context-free grammar of C. Consequently we need +context-sensitive parsing techniques, the simplest one being +a subtle cooperation between the parser and the lexical scanner. +The lexical scanner has to know whether to return IDENTIFIER +or TYPE_IDENTIFIER for a given tag, and it obtains this information +from the definition list, as constructed by the parser. +The present grammar is essentially LL(2), and is processed by +a parser generator which accepts LL(1) with tie breaking rules +in C, of the form %if(cond) and %while(cond). To solve the LL(1) +ambiguities, the lexical scanner does a one symbol look-ahead. +This symbol, however, cannot always be correctly assessed, since +the present symbol may cause a change in the definition list +which causes the identification of the look-ahead symbol to be +invalidated. +The lexical scanner relies on the parser (or its routines) to +detect this situation and then update the look-ahead symbol. +An alternative approach would be to reassess the look-ahead symbol +in the lexical scanner when it is promoted to dot symbol. This +would be more beautiful but less correct, since then for a short +while there would be a discrepancy between the look-ahead symbol +and the definition list; I think it would nevertheless work in +correct programs. +A third solution would be to enter the identifier as soon as it +is found; its storage class is then known, although its full type +isn't. We would have to fill that in afterwards. - At block exit the situation is even worse. Upon reading the - closing brace, the names declared inside the function are cleared - from the name list. This action may expose a type identifier that - is the same as the identifier in the look-ahead symbol. This - situation certainly invalidates the third solution, and casts - doubts upon the second. +At block exit the situation is even worse. Upon reading the +closing brace, the names declared inside the function are cleared +from the name list. This action may expose a type identifier that +is the same as the identifier in the look-ahead symbol. This +situation certainly invalidates the third solution, and casts +doubts upon the second. */ -%lexical LLlex; -%start C_program, program; -%start If_expr, control_if_expression; +%lexical LLlex; +%start C_program, program; +%start If_expr, control_if_expression; { -#include "lint.h" -#include "nopp.h" -#include "arith.h" -#include "LLlex.h" -#include "idf.h" -#include "label.h" -#include "type.h" -#include "declar.h" -#include "decspecs.h" -#include "code.h" -#include "expr.h" -#include "def.h" -#ifdef LINT -#include "l_lint.h" -#endif /* LINT */ + #include "lint.h" + #include "nopp.h" + #include "arith.h" + #include "LLlex.h" + #include "idf.h" + #include "label.h" + #include "type.h" + #include "declar.h" + #include "decspecs.h" + #include "code.h" + #include "expr.h" + #include "def.h" + #ifdef LINT + #include "l_lint.h" + #endif /* LINT */ -#ifndef NOPP -extern arith ifval; -#endif /* NOPP */ + #ifndef NOPP + extern arith ifval; + #endif /* NOPP */ -extern error(); + extern error(); } control_if_expression - { - struct expr *exprX; - } -: - constant_expression(&exprX) - { -#ifndef NOPP - struct expr *expr = exprX; - if (expr->ex_flags & EX_SIZEOF) - expr_error(expr, - "sizeof not allowed in preprocessor"); - ifval = expr->VL_VALUE; - free_expression(expr); -#endif /* NOPP */ - } -; + { + struct expr* exprX; + } + : constant_expression(&exprX) + { + #ifndef NOPP + struct expr* expr = exprX; + if (expr->ex_flags & EX_SIZEOF) + expr_error(expr, "sizeof not allowed in preprocessor"); + ifval = expr->VL_VALUE; + free_expression(expr); + #endif /* NOPP */ + } + ; /* 10 */ -program: - [%persistent external_definition]* - {unstack_world();} -; +program + : [ + %persistent + external_definition + ]* + { unstack_world(); } + ; /* A C identifier definition is remarkable in that it formulates - the declaration in a way different from most other languages: - e.g., rather than defining x as a pointer-to-integer, it defines - *x as an integer and lets the compiler deduce that x is actually - pointer-to-integer. This has profound consequences, both for the - structure of an identifier definition and for the compiler. - - A definition starts with a decl_specifiers, which contains things - like - typedef int - which is implicitly repeated for every definition in the list, and - then for each identifier a declarator is given, of the form - *a() - or so. The decl_specifiers is kept in a struct decspecs, to be - used again and again, while the declarator is stored in a struct - declarator, only to be passed to declare_idf together with the - struct decspecs. +the declaration in a way different from most other languages: +e.g., rather than defining x as a pointer-to-integer, it defines +*x as an integer and lets the compiler deduce that x is actually +pointer-to-integer. This has profound consequences, both for the +structure of an identifier definition and for the compiler. + +A definition starts with a decl_specifiers, which contains things +like +typedef int +which is implicitly repeated for every definition in the list, and +then for each identifier a declarator is given, of the form +*a() +or so. The decl_specifiers is kept in a struct decspecs, to be +used again and again, while the declarator is stored in a struct +declarator, only to be passed to declare_idf together with the +struct decspecs. */ external_definition - { - struct decspecs Ds; - struct declarator Dc; - } -: - { - Ds = null_decspecs; - Dc = null_declarator; - } - ext_decl_specifiers(&Ds) - [ - declarator(&Dc) - { - declare_idf(&Ds, &Dc, level); -#ifdef LINT - lint_ext_def(Dc.dc_idf, Ds.ds_sc); -#endif /* LINT */ - } - [ - function(&Ds, &Dc) - | - non_function(&Ds, &Dc) - ] - | - ';' - ] - {remove_declarator(&Dc);} -| - asm_statement /* top level, would you believe */ -; + { + struct decspecs Ds; + struct declarator Dc; + } + : + { + Ds = null_decspecs; + Dc = null_declarator; + } + ext_decl_specifiers(&Ds) + [ + declarator(&Dc) + { + declare_idf(&Ds, &Dc, level); + #ifdef LINT + lint_ext_def(Dc.dc_idf, Ds.ds_sc); + #endif /* LINT */ + } + [ + function(&Ds, &Dc) + | non_function(&Ds, &Dc) + ] + | ';' + ] + { remove_declarator(&Dc); } + | asm_statement + /* top level, would you believe */ + ; -ext_decl_specifiers(struct decspecs *ds;) : -%if (DOT != IDENTIFIER || AHEAD == IDENTIFIER) /* the thin ice in R.M. 11.1 */ - decl_specifiers(ds) -| - empty - {do_decspecs(ds);} -; +ext_decl_specifiers(struct decspecs* ds;) + : %if (DOT != IDENTIFIER || AHEAD == IDENTIFIER) + /* the thin ice in R.M. 11.1 */ + decl_specifiers(ds) + | empty + { do_decspecs(ds); } + ; -non_function(struct decspecs *ds; struct declarator *dc;) -: - {reject_params(dc);} - [ - initializer(dc->dc_idf, ds->ds_sc) - | - { code_declaration(dc->dc_idf, (struct expr *) 0, level, ds->ds_sc); } - ] - { -#ifdef LINT - lint_non_function_decl(ds, dc); -#endif /* LINT */ - } - [ - ',' - init_declarator(ds) - ]* - ';' -; +non_function(struct decspecs* ds; struct declarator* dc;) + : + { reject_params(dc); } + [ + initializer(dc->dc_idf, ds->ds_sc) + | + { code_declaration(dc->dc_idf, (struct expr*)0, level, ds->ds_sc); } + ] + { + #ifdef LINT + lint_non_function_decl(ds, dc); + #endif /* LINT */ + } + [ + ',' + init_declarator(ds) + ]* + ';' + ; /* 10.1 */ -function(struct decspecs *ds; struct declarator *dc;) - { - arith fbytes; - } -: - { struct idf *idf = dc->dc_idf; -#ifdef LINT - lint_start_function(); -#endif /* LINT */ - init_idf(idf); - stack_level(); /* L_FORMAL1 declarations */ - declare_params(dc); - begin_proc(ds, idf); /* sets global function info */ - stack_level(); /* L_FORMAL2 declarations */ - } - declaration* - { - declare_formals(&fbytes); -#ifdef LINT - lint_formals(); -#endif /* LINT */ - } - compound_statement - { - end_proc(fbytes); -#ifdef LINT - lint_implicit_return(); -#endif /* LINT */ - unstack_level(); /* L_FORMAL2 declarations */ -#ifdef LINT - lint_end_formals(); -#endif /* LINT */ - unstack_level(); /* L_FORMAL1 declarations */ -#ifdef LINT - lint_end_function(); -#endif /* LINT */ - } -; +function(struct decspecs* ds; struct declarator* dc;) + { + arith fbytes; + } + : + { + struct idf* idf = dc->dc_idf; + #ifdef LINT + lint_start_function(); + #endif /* LINT */ + init_idf(idf); + stack_level(); /* L_FORMAL1 declarations */ + declare_params(dc); + begin_proc(ds, idf); /* sets global function info */ + stack_level(); /* L_FORMAL2 declarations */ + } + declaration* + { + declare_formals(&fbytes); + #ifdef LINT + lint_formals(); + #endif /* LINT */ + } + compound_statement + { + end_proc(fbytes); + #ifdef LINT + lint_implicit_return(); + #endif /* LINT */ + unstack_level(); /* L_FORMAL2 declarations */ + #ifdef LINT + lint_end_formals(); + #endif /* LINT */ + unstack_level(); /* L_FORMAL1 declarations */ + #ifdef LINT + lint_end_function(); + #endif /* LINT */ + } + ; diff --git a/lang/cem/cemcom/statement.g b/lang/cem/cemcom/statement.g index 6ffb5ec73..4ce66b950 100644 --- a/lang/cem/cemcom/statement.g +++ b/lang/cem/cemcom/statement.g @@ -2,519 +2,498 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cemcom/statement.g + */ /* $Id$ */ /* STATEMENT SYNTAX PARSER */ { -#include "lint.h" -#ifndef LINT -#include -#else -#include "l_em.h" -#include "l_lint.h" -#endif /* LINT */ + #include "lint.h" + #ifndef LINT + #include + #else + #include "l_em.h" + #include "l_lint.h" + #endif /* LINT */ -#include "debug.h" -#include "botch_free.h" -#include "dbsymtab.h" + #include "debug.h" + #include "botch_free.h" + #include "dbsymtab.h" -#include "arith.h" -#include "LLlex.h" -#include "type.h" -#include "idf.h" -#include "label.h" -#include "expr.h" -#include "code.h" -#include "stack.h" -#include "def.h" -#ifdef DBSYMTAB -#include -#endif /* DBSYMTAB */ + #include "arith.h" + #include "LLlex.h" + #include "type.h" + #include "idf.h" + #include "label.h" + #include "expr.h" + #include "code.h" + #include "stack.h" + #include "def.h" + #ifdef DBSYMTAB + #include + #endif /* DBSYMTAB */ -extern int level; -extern char options[]; + extern int level; + extern char options[]; } /* Each statement construction is stacked in order to trace a ??? - statement to such a construction. Example: a case statement should - be recognized as a piece of the most enclosing switch statement. +statement to such a construction. Example: a case statement should +be recognized as a piece of the most enclosing switch statement. */ /* 9 */ statement - { -#ifdef LINT - lint_statement(); -#endif /* LINT */ - } -: -%if (AHEAD != ':') - expression_statement -| - label ':' statement -| - compound_statement -| - if_statement -| - while_statement -| - do_statement -| - for_statement -| - switch_statement -| - case_statement -| - default_statement -| - BREAK - { - code_break(); -#ifdef LINT - lint_break_stmt(); -#endif /* LINT */ - } - ';' -| - CONTINUE - { - code_continue(); -#ifdef LINT - lint_continue_stmt(); -#endif /* LINT */ - } - ';' -| - return_statement -| - jump -| - ';' -| - asm_statement -; - + { + #ifdef LINT + lint_statement(); + #endif /* LINT */ + } + : %if (AHEAD != ':') + expression_statement + | label ':' statement + | compound_statement + | if_statement + | while_statement + | do_statement + | for_statement + | switch_statement + | case_statement + | default_statement + | BREAK + { + code_break(); + #ifdef LINT + lint_break_stmt(); + #endif /* LINT */ + } + ';' + | CONTINUE + { + code_continue(); + #ifdef LINT + lint_continue_stmt(); + #endif /* LINT */ + } + ';' + | return_statement + | jump + | ';' + | asm_statement + ; expression_statement - { struct expr *expr; - } -: - expression(&expr) - ';' - { -#ifdef DEBUG - print_expr("expression_statement", expr); -#endif /* DEBUG */ - code_expr(expr, RVAL, FALSE, NO_LABEL, NO_LABEL); - free_expression(expr); - } -; + { + struct expr* expr; + } + : expression(&expr) + ';' + { + #ifdef DEBUG + print_expr("expression_statement", expr); + #endif /* DEBUG */ + code_expr(expr, RVAL, FALSE, NO_LABEL, NO_LABEL); + free_expression(expr); + } + ; label - { struct idf *idf; - } -: - identifier(&idf) - { - /* This allows the following absurd case: + { + struct idf* idf; + } + : identifier(&idf) + { + /* This allows the following absurd case: - typedef int grz; - main() { - grz: printf("A labelled statement\n"); - } - */ -#ifdef LINT - lint_label(); -#endif /* LINT */ - define_label(idf); - C_df_ilb((label)idf->id_def->df_address); - } -; + typedef int grz; + main() { + grz: printf("A labelled statement\n"); + } + */ + #ifdef LINT + lint_label(); + #endif /* LINT */ + define_label(idf); + C_df_ilb((label)idf->id_def->df_address); + } + ; if_statement - { - struct expr *expr; - label l_true = text_label(); - label l_false = text_label(); - label l_end = text_label(); - } -: - IF - '(' - expression(&expr) - { - opnd2test(&expr, IF); - if (is_cp_cst(expr)) { - /* The comparison has been optimized - to a 0 or 1. - */ - if (expr->VL_VALUE == (arith)0) { - C_bra(l_false); - } - /* else fall through */ -#ifdef LINT - start_if_part(1); -#endif /* LINT */ - } - else { - code_expr(expr, RVAL, TRUE, l_true, l_false); - C_df_ilb(l_true); -#ifdef LINT - start_if_part(0); -#endif /* LINT */ - } - free_expression(expr); - } - ')' - statement - [%prefer - ELSE - { -#ifdef LINT - start_else_part(); -#endif /* LINT */ - C_bra(l_end); - C_df_ilb(l_false); - } - statement - { C_df_ilb(l_end); -#ifdef LINT - end_if_else_stmt(); -#endif /* LINT */ - } - | - empty - { C_df_ilb(l_false); -#ifdef LINT - end_if_stmt(); -#endif /* LINT */ - } - ] -; + { + struct expr* expr; + label l_true = text_label(); + label l_false = text_label(); + label l_end = text_label(); + } + : IF '(' + expression(&expr) + { + opnd2test(&expr, IF); + if (is_cp_cst(expr)) + { + /* The comparison has been optimized + to a 0 or 1. + */ + if (expr->VL_VALUE == (arith)0) + { + C_bra(l_false); + } + /* else fall through */ + #ifdef LINT + start_if_part(1); + #endif /* LINT */ + } + else + { + code_expr(expr, RVAL, TRUE, l_true, l_false); + C_df_ilb(l_true); + #ifdef LINT + start_if_part(0); + #endif /* LINT */ + } + free_expression(expr); + } + ')' statement + [ + %prefer + ELSE + { + #ifdef LINT + start_else_part(); + #endif /* LINT */ + C_bra(l_end); + C_df_ilb(l_false); + } + statement + { + C_df_ilb(l_end); + #ifdef LINT + end_if_else_stmt(); + #endif /* LINT */ + } + | empty + { + C_df_ilb(l_false); + #ifdef LINT + end_if_stmt(); + #endif /* LINT */ + } + ] + ; while_statement - { - struct expr *expr; - label l_break = text_label(); - label l_continue = text_label(); - label l_body = text_label(); - } -: - WHILE - { - stack_stmt(l_break, l_continue); - C_df_ilb(l_continue); - } - '(' - expression(&expr) - { - opnd2test(&expr, WHILE); - if (is_cp_cst(expr)) { - if (expr->VL_VALUE == (arith)0) { - C_bra(l_break); - } - } - else { - code_expr(expr, RVAL, TRUE, l_body, l_break); - C_df_ilb(l_body); - } - -#ifdef LINT - start_while_stmt(expr); -#endif /* LINT */ + { + struct expr* expr; + label l_break = text_label(); + label l_continue = text_label(); + label l_body = text_label(); + } + : WHILE + { + stack_stmt(l_break, l_continue); + C_df_ilb(l_continue); + } + '(' + expression(&expr) + { + opnd2test(&expr, WHILE); + if (is_cp_cst(expr)) + { + if (expr->VL_VALUE == (arith)0) + { + C_bra(l_break); + } + } + else + { + code_expr(expr, RVAL, TRUE, l_body, l_break); + C_df_ilb(l_body); + } - } - ')' - statement - { - C_bra(l_continue); - C_df_ilb(l_break); - unstack_stmt(); - free_expression(expr); -#ifdef LINT - end_loop_body(); - end_loop_stmt(); -#endif /* LINT */ - } -; + #ifdef LINT + start_while_stmt(expr); + #endif /* LINT */ + } + ')' statement + { + C_bra(l_continue); + C_df_ilb(l_break); + unstack_stmt(); + free_expression(expr); + #ifdef LINT + end_loop_body(); + end_loop_stmt(); + #endif /* LINT */ + } + ; do_statement - { struct expr *expr; - label l_break = text_label(); - label l_continue = text_label(); - label l_body = text_label(); - } -: - DO - { C_df_ilb(l_body); - stack_stmt(l_break, l_continue); -#ifdef LINT - start_do_stmt(); -#endif /* LINT */ - } - statement - WHILE - '(' - { -#ifdef LINT - end_loop_body(); -#endif /* LINT */ - C_df_ilb(l_continue); - } - expression(&expr) - { - opnd2test(&expr, WHILE); - if (is_cp_cst(expr)) { - if (expr->VL_VALUE == (arith)1) { - C_bra(l_body); - } -#ifdef LINT - end_do_stmt(1, expr->VL_VALUE != (arith)0); -#endif /* LINT */ - } - else { - code_expr(expr, RVAL, TRUE, l_body, l_break); -#ifdef LINT - end_do_stmt(0, 0); -#endif /* LINT */ - } - C_df_ilb(l_break); - } - ')' - ';' - { - unstack_stmt(); - free_expression(expr); - } -; + { + struct expr* expr; + label l_break = text_label(); + label l_continue = text_label(); + label l_body = text_label(); + } + : DO + { + C_df_ilb(l_body); + stack_stmt(l_break, l_continue); + #ifdef LINT + start_do_stmt(); + #endif /* LINT */ + } + statement WHILE '(' + { + #ifdef LINT + end_loop_body(); + #endif /* LINT */ + C_df_ilb(l_continue); + } + expression(&expr) + { + opnd2test(&expr, WHILE); + if (is_cp_cst(expr)) + { + if (expr->VL_VALUE == (arith)1) + { + C_bra(l_body); + } + #ifdef LINT + end_do_stmt(1, expr->VL_VALUE != (arith)0); + #endif /* LINT */ + } + else + { + code_expr(expr, RVAL, TRUE, l_body, l_break); + #ifdef LINT + end_do_stmt(0, 0); + #endif /* LINT */ + } + C_df_ilb(l_break); + } + ')' ';' + { + unstack_stmt(); + free_expression(expr); + } + ; for_statement - { struct expr *e_init = 0, *e_test = 0, *e_incr = 0; - label l_break = text_label(); - label l_continue = text_label(); - label l_body = text_label(); - label l_test = text_label(); - } -: - FOR - { stack_stmt(l_break, l_continue); - } - '(' - [ - expression(&e_init) - { code_expr(e_init, RVAL, FALSE, NO_LABEL, NO_LABEL); - } - ]? - ';' - { C_df_ilb(l_test); - } - [ - expression(&e_test) - { - opnd2test(&e_test, FOR); - if (is_cp_cst(e_test)) { - if (e_test->VL_VALUE == (arith)0) { - C_bra(l_break); - } - } - else { - code_expr(e_test, RVAL, TRUE, l_body, l_break); - C_df_ilb(l_body); - } - } - ]? - ';' - expression(&e_incr)? - ')' - { -#ifdef LINT - start_for_stmt(e_test); -#endif /* LINT */ - } - statement - { -#ifdef LINT - end_loop_body(); -#endif /* LINT */ - C_df_ilb(l_continue); - if (e_incr) - code_expr(e_incr, RVAL, FALSE, - NO_LABEL, NO_LABEL); - C_bra(l_test); - C_df_ilb(l_break); - unstack_stmt(); - free_expression(e_init); - free_expression(e_test); - free_expression(e_incr); -#ifdef LINT - end_loop_stmt(); -#endif /* LINT */ - } -; + { + struct expr *e_init = 0, *e_test = 0, *e_incr = 0; + label l_break = text_label(); + label l_continue = text_label(); + label l_body = text_label(); + label l_test = text_label(); + } + : FOR + { stack_stmt(l_break, l_continue); } + '(' + [ + expression(&e_init) + { code_expr(e_init, RVAL, FALSE, NO_LABEL, NO_LABEL); } + ]? + ';' + { C_df_ilb(l_test); } + [ + expression(&e_test) + { + opnd2test(&e_test, FOR); + if (is_cp_cst(e_test)) + { + if (e_test->VL_VALUE == (arith)0) + { + C_bra(l_break); + } + } + else + { + code_expr(e_test, RVAL, TRUE, l_body, l_break); + C_df_ilb(l_body); + } + } + ]? + ';' + expression(&e_incr)? + ')' + { + #ifdef LINT + start_for_stmt(e_test); + #endif /* LINT */ + } + statement + { + #ifdef LINT + end_loop_body(); + #endif /* LINT */ + C_df_ilb(l_continue); + if (e_incr) + code_expr(e_incr, RVAL, FALSE, NO_LABEL, NO_LABEL); + C_bra(l_test); + C_df_ilb(l_break); + unstack_stmt(); + free_expression(e_init); + free_expression(e_test); + free_expression(e_incr); + #ifdef LINT + end_loop_stmt(); + #endif /* LINT */ + } + ; switch_statement - { - struct expr *expr; - } -: - SWITCH - '(' - expression(&expr) - { - code_startswitch(&expr); -#ifdef LINT - start_switch_part(is_cp_cst(expr)); -#endif /* LINT */ - } - ')' - statement - { -#ifdef LINT - end_switch_stmt(); -#endif /* LINT */ - code_endswitch(); - free_expression(expr); - } -; + { + struct expr* expr; + } + : SWITCH '(' + expression(&expr) + { + code_startswitch(&expr); + #ifdef LINT + start_switch_part(is_cp_cst(expr)); + #endif /* LINT */ + } + ')' statement + { + #ifdef LINT + end_switch_stmt(); + #endif /* LINT */ + code_endswitch(); + free_expression(expr); + } + ; case_statement - { - struct expr *expr; - } -: - CASE - constant_expression(&expr) - { -#ifdef LINT - lint_case_stmt(0); -#endif /* LINT */ - code_case(expr); - free_expression(expr); - } - ':' - statement -; + { + struct expr* expr; + } + : CASE + constant_expression(&expr) + { + #ifdef LINT + lint_case_stmt(0); + #endif /* LINT */ + code_case(expr); + free_expression(expr); + } + ':' statement + ; default_statement -: - DEFAULT - { -#ifdef LINT - lint_case_stmt(1); -#endif /* LINT */ - code_default(); - } - ':' - statement -; + : DEFAULT + { + #ifdef LINT + lint_case_stmt(1); + #endif /* LINT */ + code_default(); + } + ':' statement + ; return_statement - { struct expr *expr = 0; - } -: - RETURN - [ - expression(&expr) - { -#ifdef LINT - lint_ret_conv(expr); -#endif /* LINT */ + { + struct expr* expr = 0; + } + : RETURN + [ + expression(&expr) + { + #ifdef LINT + lint_ret_conv(expr); + #endif /* LINT */ - do_return_expr(expr); - free_expression(expr); -#ifdef LINT - lint_return_stmt(VALRETURNED); -#endif /* LINT */ - } - | - empty - { - do_return(); -#ifdef LINT - lint_return_stmt(NOVALRETURNED); -#endif /* LINT */ - } - ] - ';' -; + do_return_expr(expr); + free_expression(expr); + #ifdef LINT + lint_return_stmt(VALRETURNED); + #endif /* LINT */ + } + | empty + { + do_return(); + #ifdef LINT + lint_return_stmt(NOVALRETURNED); + #endif /* LINT */ + } + ] + ';' + ; jump - { struct idf *idf; - } -: - GOTO - identifier(&idf) - ';' - { - apply_label(idf); - C_bra((label)idf->id_def->df_address); -#ifdef LINT - lint_jump_stmt(idf); -#endif /* LINT */ - } -; + { + struct idf* idf; + } + : GOTO + identifier(&idf) + ';' + { + apply_label(idf); + C_bra((label)idf->id_def->df_address); + #ifdef LINT + lint_jump_stmt(idf); + #endif /* LINT */ + } + ; compound_statement - { -#ifdef DBSYMTAB - static int brc_level = 1; - int decl_seen = brc_level == 1; -#endif /* DBSYMTAB */ - } -: - '{' - { - stack_level(); - } - [%while ((DOT != IDENTIFIER && AHEAD != ':') || - (DOT == IDENTIFIER && AHEAD == IDENTIFIER)) - /* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */ - declaration - { -#ifdef DBSYMTAB - decl_seen++; -#endif /* DBSYMTAB */ - } - ]* - { -#ifdef DBSYMTAB - ++brc_level; - if (options['g'] && decl_seen) { - C_ms_std((char *) 0, N_LBRAC, brc_level); - } -#endif /* DBSYMTAB */ - } - [%persistent - statement - ]* - '}' - { - unstack_level(); -#ifdef DBSYMTAB - if (options['g'] && decl_seen) { - C_ms_std((char *) 0, N_RBRAC, brc_level); - } - brc_level--; -#endif /* DBSYMTAB */ - } -; + { + #ifdef DBSYMTAB + static int brc_level = 1; + int decl_seen = brc_level == 1; + #endif /* DBSYMTAB */ + } + : '{' + { stack_level(); } + [ + %while ((DOT != IDENTIFIER && AHEAD != ':') || (DOT == IDENTIFIER && AHEAD == IDENTIFIER)) + /* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */ + declaration + { + #ifdef DBSYMTAB + decl_seen++; + #endif /* DBSYMTAB */ + } + ]* + { + #ifdef DBSYMTAB + ++brc_level; + if (options['g'] && decl_seen) + { + C_ms_std((char*)0, N_LBRAC, brc_level); + } + #endif /* DBSYMTAB */ + } + [ + %persistent + statement + ]* + '}' + { + unstack_level(); + #ifdef DBSYMTAB + if (options['g'] && decl_seen) + { + C_ms_std((char*)0, N_RBRAC, brc_level); + } + brc_level--; + #endif /* DBSYMTAB */ + } + ; asm_statement - { char *asm_bts; - int asm_len; - } -: - ASM - '(' - STRING - { asm_bts = dot.tk_bts; - asm_len = dot.tk_len; - } - ')' - ';' - { code_asm(asm_bts, asm_len); - } -; - + { + char* asm_bts; + int asm_len; + } + : ASM '(' STRING + { + asm_bts = dot.tk_bts; + asm_len = dot.tk_len; + } + ')' ';' + { code_asm(asm_bts, asm_len); } + ; diff --git a/lang/cem/cpp.ansi/expression.g b/lang/cem/cpp.ansi/expression.g index 351a7c51a..616308618 100644 --- a/lang/cem/cpp.ansi/expression.g +++ b/lang/cem/cpp.ansi/expression.g @@ -2,138 +2,169 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/cem/cpp.ansi/expression.g + */ /* EXPRESSION SYNTAX PARSER */ -%lexical LLlex; -%start If_expr, if_expression; +%lexical LLlex; +%start If_expr, if_expression; { -#include "arith.h" -#include "LLlex.h" -#include "ch3mon.h" -#include "ch3bin.h" -#include "expr.h" + #include "arith.h" + #include "LLlex.h" + #include "ch3mon.h" + #include "ch3bin.h" + #include "expr.h" -extern arith ifval; + extern arith ifval; } if_expression -{ int is_unsigned = 0; } -: - constant_expression(&ifval, &is_unsigned) -; + { + int is_unsigned = 0; + } + : constant_expression(&ifval, &is_unsigned) + ; /* 7.1 */ -primary(arith *pval; int *is_uns;) -: - constant(pval, is_uns) -| - '(' expression(pval, is_uns) ')' -; - -unary(arith *pval; int *is_uns;) - {int oper;} -: - unop(&oper) - unary(pval, is_uns) - { ch3mon(oper, pval, is_uns); } -| - primary(pval, is_uns) -; - -binary_expression(int maxrank; arith *pval; int *is_uns;) - {int oper; arith val1; int u;} -: - unary(pval, is_uns) - [%while (rank_of(DOT) <= maxrank) - binop(&oper) - binary_expression(rank_of(oper)-1, &val1, &u) - { - ch3bin(pval, is_uns, oper, val1, u); - } - ]* -; +primary(arith* pval; int* is_uns;) + : constant(pval, is_uns) + | '(' + expression(pval, is_uns) + ')' + ; + +unary(arith* pval; int* is_uns;) + { + int oper; + } + : unop(&oper) + unary(pval, is_uns) + { ch3mon(oper, pval, is_uns); } + | primary(pval, is_uns) + ; + +binary_expression(int maxrank; arith* pval; int* is_uns;) + { + int oper; + arith val1; + int u; + } + : unary(pval, is_uns) + [ + %while (rank_of(DOT) <= maxrank) + binop(&oper) + binary_expression(rank_of(oper) - 1, &val1, &u) + { ch3bin(pval, is_uns, oper, val1, u); } + ]* + ; /* 7.13 */ -conditional_expression(arith *pval; int *is_uns) - {arith val1 = 0, val2 = 0; int u;} -: - /* allow all binary operators */ - binary_expression(rank_of('?') - 1, pval, is_uns) - [ '?' - expression(&val1, is_uns) - ':' - assignment_expression(&val2, &u) - { if (*pval) *pval = val1; - else { *pval = val2; *is_uns = u; } - } - ]? -; +conditional_expression(arith* pval; int* is_uns) + { + arith val1 = 0, val2 = 0; + int u; + } + : + /* allow all binary operators */ + binary_expression(rank_of('?') - 1, pval, is_uns) + [ + '?' + expression(&val1, is_uns) + ':' + assignment_expression(&val2, &u) + { if (*pval) *pval = val1; else { *pval = val2; *is_uns = u; } } + ]? + ; /* 7.14 */ -assignment_expression(arith *pval; int *is_uns) -: - conditional_expression(pval, is_uns) -; +assignment_expression(arith* pval; int* is_uns) + : conditional_expression(pval, is_uns) + ; /* 7.15 */ -expression(arith *pval; int *is_uns) - {arith val1; - int is_uns1; - } -: - assignment_expression(pval,is_uns) - [ ',' - assignment_expression(&val1, &is_uns1) - { - ch3bin(pval, is_uns, ',', val1, is_uns1); - } - ]* -; - -unop(int *oper;) : - [ '-' | '!' | '~' ] - {*oper = DOT;} -; - -multop: - '*' | '/' | '%' -; - -addop: - '+' | '-' -; - -shiftop: - LEFT | RIGHT -; - -relop: - '<' | '>' | LESSEQ | GREATEREQ -; - -eqop: - EQUAL | NOTEQUAL -; - -arithop: - multop | addop | shiftop -| - '&' | '^' | '|' -; - -binop(int *oper;) : - [ arithop | relop | eqop | AND | OR ] - {*oper = DOT;} -; - -constant(arith *pval; int *is_uns) : - INTEGER - {*pval = dot.tk_val; - *is_uns = dot.tk_unsigned; - } -; - -constant_expression (arith *pval; int *is_uns) : - assignment_expression(pval, is_uns) -; +expression(arith* pval; int* is_uns) + { + arith val1; + int is_uns1; + } + : assignment_expression(pval, is_uns) + [ + ',' + assignment_expression(&val1, &is_uns1) + { ch3bin(pval, is_uns, ',', val1, is_uns1); } + ]* + ; + +unop(int* oper;) + : [ + '-' + | '!' + | '~' + ] + { *oper = DOT; } + ; + +multop + : '*' + | '/' + | '%' + ; + +addop + : '+' + | '-' + ; + +shiftop + : LEFT + | RIGHT + ; + +relop + : '<' + | '>' + | LESSEQ + | GREATEREQ + ; + +eqop + : EQUAL + | NOTEQUAL + ; + +arithop + : multop + | addop + | shiftop + | '&' + | '^' + | '|' + ; + +binop(int* oper;) + : [ + arithop + | relop + | eqop + | AND + | OR + ] + { *oper = DOT; } + ; + +constant(arith* pval; int* is_uns) + : INTEGER + { + *pval = dot.tk_val; + *is_uns = dot.tk_unsigned; + } + ; + +constant_expression(arith* pval; int* is_uns) + : assignment_expression(pval, is_uns) + ; diff --git a/lang/m2/comp/declar.g b/lang/m2/comp/declar.g index 3dddc770b..fbeac1f1d 100644 --- a/lang/m2/comp/declar.g +++ b/lang/m2/comp/declar.g @@ -5,39 +5,45 @@ * Author: Ceriel J.H. Jacobs */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/m2/comp/declar.g + */ + /* D E C L A R A T I O N S */ /* $Id$ */ { -#include "parameters.h" -#include "debug.h" - -#include -#include "em_arith.h" -#include "em_label.h" -#include "alloc.h" - -#include "idf.h" -#include "LLlex.h" -#include "def.h" -#include "type.h" -#include "scope.h" -#include "node.h" -#include "enter.h" -#include "error.h" -#include "misc.h" -#include "main.h" -#include "typequiv.h" -#include "chk_expr.h" -#include "warning.h" - -int proclevel = 0; /* nesting level of procedures */ -int return_occurred; /* set if a return occurs in a block */ - -extern struct node *EmptyStatement; - -#define needs_static_link() (proclevel > 1) + #include "parameters.h" + #include "debug.h" + + #include + #include "em_arith.h" + #include "em_label.h" + #include "alloc.h" + + #include "idf.h" + #include "LLlex.h" + #include "def.h" + #include "type.h" + #include "scope.h" + #include "node.h" + #include "enter.h" + #include "error.h" + #include "misc.h" + #include "main.h" + #include "typequiv.h" + #include "chk_expr.h" + #include "warning.h" + + int proclevel = 0; /* nesting level of procedures */ + int return_occurred; /* set if a return occurs in a block */ + + extern struct node* EmptyStatement; + + #define needs_static_link() (proclevel > 1) } /* inline in declaration: need space @@ -53,80 +59,92 @@ extern struct node *EmptyStatement; * --proclevel; * } * ; -*/ + */ -ProcedureHeading(struct def **pdf; int type;) -{ - struct type *tp = 0; - arith parmaddr = needs_static_link() ? pointer_size : 0; - struct paramlist *pr = 0; -} : - PROCEDURE IDENT - { *pdf = DeclProc(type, dot.TOK_IDF); } - [ - '(' - [ - FPSection(&pr, &parmaddr) - [ - ';' FPSection(&pr, &parmaddr) - ]* - | - ] - ')' - [ ':' qualtype(&tp) - | - ] - | - ] - { CheckWithDef(*pdf, proc_type(tp, pr, parmaddr)); -#ifndef NOSTRICT - if (tp && IsConstructed(tp)) { -warning(W_STRICT, "procedure \"%s\" has a constructed result type", - (*pdf)->df_idf->id_text); - } -#endif - } -; - -block(struct node **pnd;) : - [ %persistent - declaration - ]* - { return_occurred = 0; } - [ %default - BEGIN - StatementSequence(pnd) - | - { *pnd = EmptyStatement; } - ] - END -; +ProcedureHeading(struct def** pdf; int type;) + { + struct type* tp = 0; + arith parmaddr = needs_static_link() ? pointer_size : 0; + struct paramlist* pr = 0; + } + : PROCEDURE IDENT + { *pdf = DeclProc(type, dot.TOK_IDF); } + [ + '(' + [ + FPSection(&pr, &parmaddr) + [ + ';' + FPSection(&pr, &parmaddr) + ]* + | + ] + ')' + [ + ':' + qualtype(&tp) + | + ] + | + ] + { + CheckWithDef(*pdf, proc_type(tp, pr, parmaddr)); + #ifndef NOSTRICT + if (tp && IsConstructed(tp)) + { + warning(W_STRICT, "procedure \"%s\" has a constructed result type", + (*pdf)->df_idf->id_text); + } + #endif + } + ; + +block(struct node** pnd;) + : [ + %persistent + declaration + ]* + { return_occurred = 0; } + [ + %default + BEGIN + StatementSequence(pnd) + | + { *pnd = EmptyStatement; } + ] + END + ; declaration -{ - struct def *df; -} : - CONST [ ConstantDeclaration ';' ]* -| - TYPE [ TypeDeclaration ';' ]* -| - VAR [ VariableDeclaration ';' ]* -| - { ++proclevel; } - ProcedureHeading(&df, D_PROCEDURE) - { - } - ';' - block(&(df->prc_body)) - IDENT - { - EndProc(df, dot.TOK_IDF); - --proclevel; - } - ';' -| - ModuleDeclaration ';' -; + { + struct def* df; + } + : CONST + [ + ConstantDeclaration ';' + ]* + | TYPE + [ + TypeDeclaration ';' + ]* + | VAR + [ + VariableDeclaration ';' + ]* + | + { ++proclevel; } + ProcedureHeading(&df, D_PROCEDURE) + {} + ';' + block(&(df->prc_body)) + IDENT + { + EndProc(df, dot.TOK_IDF); + --proclevel; + } + ';' + | ModuleDeclaration ';' + ; /* inline in procedureheading: need space * FormalParameters(struct paramlist **ppr; arith *parmaddr; struct type **ptp;): @@ -143,427 +161,489 @@ declaration * | * ] * ; -*/ + */ -FPSection(struct paramlist **ppr; arith *parmaddr;) -{ - struct node *FPList; - struct type *tp; - int VARp; -} : - var(&VARp) IdentList(&FPList) ':' FormalType(&tp) - { EnterParamList(ppr, FPList, tp, VARp, parmaddr); } -; - -FormalType(struct type **ptp;) - /* index type of conformant array is "CARDINAL". - Recognize a conformant array by size 0. - */ -{ register struct type *tp; -} : - ARRAY OF - { tp = construct_type(T_ARRAY, card_type); } - qualtype(&(tp->arr_elem)) - { ArrayElSize(tp); - *ptp = tp; - } -| - qualtype(ptp) -; +FPSection(struct paramlist** ppr; arith* parmaddr;) + { + struct node* FPList; + struct type* tp; + int VARp; + } + : var(&VARp) + IdentList(&FPList) + ':' + FormalType(&tp) + { EnterParamList(ppr, FPList, tp, VARp, parmaddr); } + ; + +FormalType(struct type** ptp;) + /* index type of conformant array is "CARDINAL". + Recognize a conformant array by size 0. + */ + { + register struct type* tp; + } + : ARRAY OF + { tp = construct_type(T_ARRAY, card_type); } + qualtype(&(tp->arr_elem)) + { + ArrayElSize(tp); + *ptp = tp; + } + | qualtype(ptp) + ; TypeDeclaration -{ - struct def *df; - struct type *tp; - register struct node *nd; -}: - IDENT { df = define(dot.TOK_IDF, CurrentScope, D_TYPE); - nd = dot2leaf(Name); - } - '=' type(&tp) - { DeclareType(nd, df, tp); - FreeNode(nd); - } -; - -type(struct type **ptp;): - %default SimpleType(ptp) -| - ArrayType(ptp) -| - RecordType(ptp) -| - SetType(ptp) -| - PointerType(ptp) -| - ProcedureType(ptp) -; - -SimpleType(struct type **ptp;) : - qualtype(ptp) - [ - /* nothing */ - | - SubrangeType(ptp) - /* The subrange type is given a base type by the - qualident (this is new modula-2). - */ - ] -| - enumeration(ptp) -| { *ptp = 0; /* no qualification */ } - SubrangeType(ptp) -; - -enumeration(struct type **ptp;) -{ - struct node *EnumList; -} : - '(' IdentList(&EnumList) ')' - { *ptp = enum_type(EnumList); } -; - -IdentList(struct node **p;) -{ - register struct node *q; -} : - IDENT { *p = q = dot2leaf(Select); } - [ %persistent - ',' IDENT - { q->nd_NEXT = dot2leaf(Select); - q = q->nd_NEXT; - } - ]* -; - -SubrangeType(struct type **ptp;) -{ - struct node *nd1, *nd2; -}: - /* - This is not exactly the rule in the new report, but see - the rule for "SimpleType". - */ - '[' ConstExpression(&nd1) - UPTO ConstExpression(&nd2) - ']' - { *ptp = subr_type(nd1, nd2, *ptp); - FreeNode(nd1); - FreeNode(nd2); - } -; - -ArrayType(struct type **ptp;) -{ - struct type *tp; - register struct type *tp1, *tp2; -} : - ARRAY SimpleType(&tp) - { tp1 = tp2 = construct_type(T_ARRAY, tp); } - [ - ',' SimpleType(&tp) - { tp2->arr_elem = construct_type(T_ARRAY, tp); - tp2 = tp2->arr_elem; - } - ]* OF type(&tp) - { tp2->arr_elem = tp; - ArraySizes(tp1); - *ptp = tp1; - } -; - -RecordType(struct type **ptp;) -{ - register struct scope *scope; - arith size = 0; - int xalign = struct_align; -} -: - RECORD - { scope = open_and_close_scope(OPENSCOPE); } - FieldListSequence(scope, &size, &xalign) - { if (size == 0) { - warning(W_ORDINARY, "empty record declaration"); - size = 1; - } - *ptp = standard_type(T_RECORD, xalign, align(size, xalign)); - (*ptp)->rec_scope = scope; - Reverse(&(scope->sc_def)); - } - END -; - -FieldListSequence(struct scope *scope; arith *cnt; int *palign;): - FieldList(scope, cnt, palign) - [ - ';' FieldList(scope, cnt, palign) - ]* -; - -FieldList(struct scope *scope; arith *cnt; int *palign;) -{ - struct node *FldList; - struct type *tp; - struct node *nd; - register struct def *df; - arith tcnt, max; -} : -[ - IdentList(&FldList) ':' type(&tp) - { - *palign = lcm(*palign, tp->tp_align); - EnterFieldList(FldList, tp, scope, cnt); - } -| - CASE - /* Also accept old fashioned Modula-2 syntax, but give a warning. - Sorry for the complicated code. - */ - [ qualident(&nd) - [ ':' qualtype(&tp) - /* This is correct, in both kinds of Modula-2, if - the first qualident is a single identifier. - */ - { if (nd->nd_class != Name) { - error("illegal variant tag"); - } - else { - df = define(nd->nd_IDF, scope, D_FIELD); - *palign = lcm(*palign, tp->tp_align); - if (!(tp->tp_fund & T_DISCRETE)) { - error("illegal type in variant"); - } - df->df_type = tp; - df->fld_off = align(*cnt, tp->tp_align); - *cnt = df->fld_off + tp->tp_size; - df->df_flags |= D_QEXPORTED; - } - FreeNode(nd); - } - | /* Old fashioned! the first qualident now represents - the type - */ - { -#ifndef STRICT_3RD_ED - if (! options['3']) warning(W_OLDFASHIONED, - "old fashioned Modula-2 syntax; ':' missing"); - else -#endif - error("':' missing"); - tp = qualified_type(&nd); - } - ] - | ':' qualtype(&tp) - /* Aha, third edition. Well done! */ - ] - { tcnt = *cnt; } - OF variant(scope, &tcnt, tp, palign) - { max = tcnt; tcnt = *cnt; } - [ - '|' variant(scope, &tcnt, tp, palign) - { if (tcnt > max) max = tcnt; tcnt = *cnt; } - ]* - [ ELSE FieldListSequence(scope, &tcnt, palign) - { if (tcnt > max) max = tcnt; } - | - ] - END - { *cnt = max; } -| -] -; - -variant(struct scope *scope; arith *cnt; struct type *tp; int *palign;) -{ - struct node *nd; -} : - [ - CaseLabelList(&tp, &nd) - { /* Ignore the cases for the time being. - Maybe a checking version will be supplied - later ??? - */ - FreeNode(nd); - } - ':' FieldListSequence(scope, cnt, palign) - | - ] - /* Changed rule in new modula-2 */ -; - -CaseLabelList(struct type **ptp; struct node **pnd;): - CaseLabels(ptp, pnd) - [ - { *pnd = dot2node(Link, *pnd, NULLNODE); } - ',' CaseLabels(ptp, &((*pnd)->nd_RIGHT)) - { pnd = &((*pnd)->nd_RIGHT); } - ]* -; - -CaseLabels(struct type **ptp; register struct node **pnd;) -{ - register struct node *nd; -}: - ConstExpression(pnd) - { - if (*ptp != 0) { - struct type *tp = intorcard(*ptp, - BaseType((*pnd)->nd_type)); - if (tp) *ptp = tp; - ChkCompat(pnd, *ptp, "case label"); - } - nd = *pnd; - nd->nd_type = BaseType(nd->nd_type); /* ??? */ - if (! (nd->nd_type->tp_fund & T_DISCRETE) || - nd->nd_type->tp_size > word_size) { - node_error(nd, "illegal type in case label"); - } - } - [ - UPTO { *pnd = nd = dot2node(Link,nd,NULLNODE); - nd->nd_type = nd->nd_LEFT->nd_type; - } - ConstExpression(&(*pnd)->nd_RIGHT) - { if (!ChkCompat(&((*pnd)->nd_RIGHT), nd->nd_type, - "case label")) { - nd->nd_type = error_type; - } - else if (! chk_bounds(nd->nd_LEFT->nd_INT, - nd->nd_RIGHT->nd_INT, - nd->nd_type->tp_fund)) { - node_error(nd, - "lower bound exceeds upper bound in case label range"); - } - - } - | - ] - { - *ptp = nd->nd_type; - } -; - -SetType(struct type **ptp;) -{ struct type *tp; -} : - SET OF SimpleType(&tp) - { *ptp = set_type(tp); } -; + { + struct def* df; + struct type* tp; + register struct node* nd; + } + : IDENT + { + df = define(dot.TOK_IDF, CurrentScope, D_TYPE); + nd = dot2leaf(Name); + } + '=' + type(&tp) + { + DeclareType(nd, df, tp); + FreeNode(nd); + } + ; + +type(struct type** ptp;) + : %default + SimpleType(ptp) + | ArrayType(ptp) + | RecordType(ptp) + | SetType(ptp) + | PointerType(ptp) + | ProcedureType(ptp) + ; + +SimpleType(struct type** ptp;) + : qualtype(ptp) + [ + /* nothing */ + | SubrangeType(ptp) + /* The subrange type is given a base type by the + qualident (this is new modula-2). + */ + ] + | enumeration(ptp) + | + { *ptp = 0; /* no qualification */ } + SubrangeType(ptp) + ; + +enumeration(struct type** ptp;) + { + struct node* EnumList; + } + : '(' + IdentList(&EnumList) + ')' + { *ptp = enum_type(EnumList); } + ; + +IdentList(struct node** p;) + { + register struct node* q; + } + : IDENT + { *p = q = dot2leaf(Select); } + [ + %persistent + ',' IDENT + { + q->nd_NEXT = dot2leaf(Select); + q = q->nd_NEXT; + } + ]* + ; + +SubrangeType(struct type** ptp;) + { + struct node *nd1, *nd2; + } + : + /* + This is not exactly the rule in the new report, but see + the rule for "SimpleType". + */ + '[' + ConstExpression(&nd1) + UPTO + ConstExpression(&nd2) + ']' + { + *ptp = subr_type(nd1, nd2, *ptp); + FreeNode(nd1); + FreeNode(nd2); + } + ; + +ArrayType(struct type** ptp;) + { + struct type* tp; + register struct type *tp1, *tp2; + } + : ARRAY + SimpleType(&tp) + { tp1 = tp2 = construct_type(T_ARRAY, tp); } + [ + ',' + SimpleType(&tp) + { + tp2->arr_elem = construct_type(T_ARRAY, tp); + tp2 = tp2->arr_elem; + } + ]* + OF + type(&tp) + { + tp2->arr_elem = tp; + ArraySizes(tp1); + *ptp = tp1; + } + ; + +RecordType(struct type** ptp;) + { + register struct scope* scope; + arith size = 0; + int xalign = struct_align; + } + : RECORD + { scope = open_and_close_scope(OPENSCOPE); } + FieldListSequence(scope, &size, &xalign) + { + if (size == 0) + { + warning(W_ORDINARY, "empty record declaration"); + size = 1; + } + *ptp = standard_type(T_RECORD, xalign, align(size, xalign)); + (*ptp)->rec_scope = scope; + Reverse(&(scope->sc_def)); + } + END + ; + +FieldListSequence(struct scope* scope; arith* cnt; int* palign;) + : FieldList(scope, cnt, palign) + [ + ';' + FieldList(scope, cnt, palign) + ]* + ; + +FieldList(struct scope* scope; arith* cnt; int* palign;) + { + struct node* FldList; + struct type* tp; + struct node* nd; + register struct def* df; + arith tcnt, max; + } + : [ + IdentList(&FldList) + ':' + type(&tp) + { + *palign = lcm(*palign, tp->tp_align); + EnterFieldList(FldList, tp, scope, cnt); + } + | CASE + /* Also accept old fashioned Modula-2 syntax, but give a warning. + Sorry for the complicated code. + */ + [ + qualident(&nd) + [ + ':' + qualtype(&tp) + /* This is correct, in both kinds of Modula-2, if + the first qualident is a single identifier. + */ + { + if (nd->nd_class != Name) + { + error("illegal variant tag"); + } + else + { + df = define(nd->nd_IDF, scope, D_FIELD); + *palign = lcm(*palign, tp->tp_align); + if (!(tp->tp_fund & T_DISCRETE)) + { + error("illegal type in variant"); + } + df->df_type = tp; + df->fld_off = align(*cnt, tp->tp_align); + *cnt = df->fld_off + tp->tp_size; + df->df_flags |= D_QEXPORTED; + } + FreeNode(nd); + } + | + /* Old fashioned! the first qualident now represents + the type + */ + { + #ifndef STRICT_3RD_ED + if (!options['3']) + warning(W_OLDFASHIONED, "old fashioned Modula-2 syntax; ':' missing"); + else + #endif + error("':' missing"); + tp = qualified_type(&nd); + } + ] + | ':' + qualtype(&tp) + /* Aha, third edition. Well done! */ + ] + { tcnt = *cnt; } + OF + variant(scope, &tcnt, tp, palign) + { + max = tcnt; + tcnt = *cnt; + } + [ + '|' + variant(scope, &tcnt, tp, palign) + { + if (tcnt > max) + max = tcnt; + tcnt = *cnt; + } + ]* + [ + ELSE + FieldListSequence(scope, &tcnt, palign) + { if (tcnt > max) max = tcnt; } + | + ] + END + { *cnt = max; } + | + ] + ; + +variant(struct scope* scope; arith* cnt; struct type* tp; int* palign;) + { + struct node* nd; + } + : [ + CaseLabelList(&tp, &nd) + { + /* Ignore the cases for the time being. + Maybe a checking version will be supplied + later ??? + */ + FreeNode(nd); + } + ':' + FieldListSequence(scope, cnt, palign) + | + ] + /* Changed rule in new modula-2 */ + ; + +CaseLabelList(struct type** ptp; struct node** pnd;) + : CaseLabels(ptp, pnd) + [ + { *pnd = dot2node(Link, *pnd, NULLNODE); } + ',' + CaseLabels(ptp, &((*pnd)->nd_RIGHT)) + { pnd = &((*pnd)->nd_RIGHT); } + ]* + ; + +CaseLabels(struct type** ptp; register struct node** pnd;) + { + register struct node* nd; + } + : ConstExpression(pnd) + { + if (*ptp != 0) + { + struct type* tp = intorcard(*ptp, BaseType((*pnd)->nd_type)); + if (tp) + *ptp = tp; + ChkCompat(pnd, *ptp, "case label"); + } + nd = *pnd; + nd->nd_type = BaseType(nd->nd_type); /* ??? */ + if (!(nd->nd_type->tp_fund & T_DISCRETE) || nd->nd_type->tp_size > word_size) + { + node_error(nd, "illegal type in case label"); + } + } + [ + UPTO + { + *pnd = nd = dot2node(Link, nd, NULLNODE); + nd->nd_type = nd->nd_LEFT->nd_type; + } + ConstExpression(&(*pnd)->nd_RIGHT) + { + if (!ChkCompat(&((*pnd)->nd_RIGHT), nd->nd_type, "case label")) + { + nd->nd_type = error_type; + } + else if (!chk_bounds(nd->nd_LEFT->nd_INT, nd->nd_RIGHT->nd_INT, + nd->nd_type->tp_fund)) + { + node_error(nd, "lower bound exceeds upper bound in case label range"); + } + } + | + ] + { *ptp = nd->nd_type; } + ; + +SetType(struct type** ptp;) + { + struct type* tp; + } + : SET OF + SimpleType(&tp) + { *ptp = set_type(tp); } + ; /* In a pointer type definition, the type pointed at does not - have to be declared yet, so be careful about identifying - type-identifiers. +have to be declared yet, so be careful about identifying +type-identifiers. */ -PointerType(struct type **ptp;) -{ register struct type *tp; -} : - { tp = construct_type(T_POINTER, NULLTYPE); } - POINTER TO - [ %if (type_or_forward(tp)) - type(&(tp->tp_next)) - | - IDENT - ] - { *ptp = tp; } -; - -qualtype(struct type **ptp;) -{ - struct node *nd; -} : - qualident(&nd) - { *ptp = qualified_type(&nd); } -; - -ProcedureType(struct type **ptp;) -{ - struct paramlist *pr = 0; - arith parmaddr = 0; - struct type *tp = 0; -} : - PROCEDURE - [ - FormalTypeList(&pr, &parmaddr, &tp) - | - ] - { *ptp = proc_type(tp, pr, parmaddr); } -; - -FormalTypeList(struct paramlist **ppr; arith *pparmaddr; struct type **ptp;) : - '(' - [ - VarFormalType(ppr, pparmaddr) - [ - ',' VarFormalType(ppr, pparmaddr) - ]* - | - ] - ')' - [ ':' qualtype(ptp) - | - ] -; - -VarFormalType(struct paramlist **ppr; arith *pparmaddr;) -{ - struct type *tp; - int isvar; -} : - var(&isvar) - FormalType(&tp) - { EnterParamList(ppr,NULLNODE,tp,isvar,pparmaddr); } -; - -var(int *VARp;) : - [ - VAR { *VARp = D_VARPAR; } - | - /* empty */ { *VARp = D_VALPAR; } - ] -; +PointerType(struct type** ptp;) + { + register struct type* tp; + } + : + { tp = construct_type(T_POINTER, NULLTYPE); } + POINTER TO + [ + %if (type_or_forward(tp)) + type(&(tp->tp_next)) + | IDENT + ] + { *ptp = tp; } + ; + +qualtype(struct type** ptp;) + { + struct node* nd; + } + : qualident(&nd) + { *ptp = qualified_type(&nd); } + ; + +ProcedureType(struct type** ptp;) + { + struct paramlist* pr = 0; + arith parmaddr = 0; + struct type* tp = 0; + } + : PROCEDURE + [ + FormalTypeList(&pr, &parmaddr, &tp) + | + ] + { *ptp = proc_type(tp, pr, parmaddr); } + ; + +FormalTypeList(struct paramlist** ppr; arith* pparmaddr; struct type** ptp;) + : '(' + [ + VarFormalType(ppr, pparmaddr) + [ + ',' + VarFormalType(ppr, pparmaddr) + ]* + | + ] + ')' + [ + ':' + qualtype(ptp) + | + ] + ; + +VarFormalType(struct paramlist** ppr; arith* pparmaddr;) + { + struct type* tp; + int isvar; + } + : var(&isvar) + FormalType(&tp) + { EnterParamList(ppr, NULLNODE, tp, isvar, pparmaddr); } + ; + +var(int* VARp;) + : [ + VAR + { *VARp = D_VARPAR; } + | + /* empty */ + { *VARp = D_VALPAR; } + ] + ; ConstantDeclaration -{ - struct idf *id; - struct node *nd; - register struct def *df; -}: - IDENT { id = dot.TOK_IDF; } - '=' ConstExpression(&nd) - { df = define(id,CurrentScope,D_CONST); - df->con_const = nd->nd_token; - df->df_type = nd->nd_type; - FreeNode(nd); - } -; + { + struct idf* id; + struct node* nd; + register struct def* df; + } + : IDENT + { id = dot.TOK_IDF; } + '=' + ConstExpression(&nd) + { + df = define(id, CurrentScope, D_CONST); + df->con_const = nd->nd_token; + df->df_type = nd->nd_type; + FreeNode(nd); + } + ; VariableDeclaration -{ - struct node *VarList; - register struct node *nd; - struct type *tp; -} : - IdentAddr(&VarList) - { nd = VarList; } - [ %persistent - ',' IdentAddr(&(nd->nd_RIGHT)) - { nd = nd->nd_RIGHT; } - ]* - ':' type(&tp) - { EnterVarList(VarList, tp, proclevel > 0); } -; - -IdentAddr(struct node **pnd;) -{ - register struct node *nd; -} : - IDENT { nd = dot2leaf(Name); - *pnd = dot2node(Link, nd, NULLNODE); - } - [ '[' - ConstExpression(&(nd->nd_NEXT)) - ']' - | - ] -; + { + struct node* VarList; + register struct node* nd; + struct type* tp; + } + : IdentAddr(&VarList) + { nd = VarList; } + [ + %persistent + ',' + IdentAddr(&(nd->nd_RIGHT)) + { nd = nd->nd_RIGHT; } + ]* + ':' + type(&tp) + { EnterVarList(VarList, tp, proclevel > 0); } + ; + +IdentAddr(struct node** pnd;) + { + register struct node* nd; + } + : IDENT + { + nd = dot2leaf(Name); + *pnd = dot2node(Link, nd, NULLNODE); + } + [ + '[' + ConstExpression(&(nd->nd_NEXT)) + ']' + | + ] + ; diff --git a/lang/m2/comp/expression.g b/lang/m2/comp/expression.g index e29f0b24e..2e7950aec 100644 --- a/lang/m2/comp/expression.g +++ b/lang/m2/comp/expression.g @@ -5,291 +5,335 @@ * Author: Ceriel J.H. Jacobs */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/m2/comp/expression.g + */ + /* E X P R E S S I O N S */ /* $Id$ */ { -#include "parameters.h" -#include "debug.h" + #include "parameters.h" + #include "debug.h" -#include "alloc.h" -#include "em_arith.h" -#include "em_label.h" -#include + #include "alloc.h" + #include "em_arith.h" + #include "em_label.h" + #include -#include "LLlex.h" -#include "idf.h" -#include "def.h" -#include "node.h" -#include "type.h" -#include "error.h" -#include "chk_expr.h" -#include "warning.h" + #include "LLlex.h" + #include "idf.h" + #include "def.h" + #include "node.h" + #include "type.h" + #include "error.h" + #include "chk_expr.h" + #include "warning.h" -extern char options[]; + extern char options[]; } /* inline, we need room for pdp/11 number(struct node **p;) : [ - %default - INTEGER +%default +INTEGER | - REAL +REAL ] { *p = dot2leaf(Value); - (*p)->nd_type = toktype; - } +(*p)->nd_type = toktype; +} ; */ -qualident(struct node **p;) -{ -} : - IDENT { *p = dot2leaf(Name); } - [ - selector(p) - ]* -; +qualident(struct node** p;) + {} + : IDENT + { *p = dot2leaf(Name); } + [ + selector(p) + ]* + ; -selector(struct node **pnd;) -{ struct node *nd; -} : - '.' { nd = dot2leaf(Select); nd->nd_NEXT = *pnd; *pnd = nd; } - IDENT { (*pnd)->nd_IDF = dot.TOK_IDF; } -; +selector(struct node** pnd;) + { + struct node* nd; + } + : '.' + { + nd = dot2leaf(Select); + nd->nd_NEXT = *pnd; + *pnd = nd; + } + IDENT + { (*pnd)->nd_IDF = dot.TOK_IDF; } + ; -ExpList(struct node **pnd;) -{ - register struct node *nd; -} : - expression(pnd) { *pnd = nd = dot2node(Link,*pnd,NULLNODE); - nd->nd_symb = ','; - } - [ - ',' { nd->nd_RIGHT = dot2leaf(Link); - nd = nd->nd_RIGHT; - } - expression(&(nd->nd_LEFT)) - ]* -; +ExpList(struct node** pnd;) + { + register struct node* nd; + } + : expression(pnd) + { + *pnd = nd = dot2node(Link, *pnd, NULLNODE); + nd->nd_symb = ','; + } + [ + ',' + { + nd->nd_RIGHT = dot2leaf(Link); + nd = nd->nd_RIGHT; + } + expression(&(nd->nd_LEFT)) + ]* + ; -ConstExpression(struct node **pnd;) -{ -}: - expression(pnd) - /* - * Changed rule in new Modula-2. - * Check that the expression is a constant expression and evaluate! - */ - { - DO_DEBUG(options['C'], printf("CONSTANT EXPRESSION\n")); - DO_DEBUG(options['C'], PrNode(*pnd, 0)); +ConstExpression(struct node** pnd;) + {} + : expression(pnd) + /* + * Changed rule in new Modula-2. + * Check that the expression is a constant expression and evaluate! + */ + { + DO_DEBUG(options['C'], printf("CONSTANT EXPRESSION\n")); + DO_DEBUG(options['C'], PrNode(*pnd, 0)); - if (ChkExpression(pnd) && - (*pnd)->nd_class != Set && - (*pnd)->nd_class != Value && - ! (options['l'] && (*pnd)->nd_class == Def && IsProc((*pnd)))) { - error("constant expression expected"); - } + if (ChkExpression(pnd) && (*pnd)->nd_class != Set && (*pnd)->nd_class != Value + && !(options['l'] && (*pnd)->nd_class == Def && IsProc((*pnd)))) + { + error("constant expression expected"); + } - DO_DEBUG(options['C'], printf("RESULTS IN\n")); - DO_DEBUG(options['C'], PrNode(*pnd, 0)); - } -; + DO_DEBUG(options['C'], printf("RESULTS IN\n")); + DO_DEBUG(options['C'], PrNode(*pnd, 0)); + } + ; -expression(struct node **pnd;) -{ -} : - SimpleExpression(pnd) - [ - /* relation */ - [ '=' | '#' | '<' | LESSEQUAL | '>' | GREATEREQUAL | IN ] - { *pnd = dot2node(Oper, *pnd, NULLNODE); } - SimpleExpression(&((*pnd)->nd_RIGHT)) - | - ] -; +expression(struct node** pnd;) + {} + : SimpleExpression(pnd) + [ + /* relation */ + [ + '=' + | '#' + | '<' + | LESSEQUAL + | '>' + | GREATEREQUAL + | IN + ] + { *pnd = dot2node(Oper, *pnd, NULLNODE); } + SimpleExpression(&((*pnd)->nd_RIGHT)) + | + ] + ; /* Inline in expression relation: - '=' | '#' | '<' | LESSEQUAL | '>' | GREATEREQUAL | IN +'=' | '#' | '<' | LESSEQUAL | '>' | GREATEREQUAL | IN ; */ -SimpleExpression(struct node **pnd;) -{ - register struct node *nd = 0; -} : - [ - [ '+' | '-' ] - { nd = dot2leaf(Uoper); - /* priority of unary operator ??? */ - } - | - ] - term(pnd) - { if (nd) { - nd->nd_RIGHT = *pnd; - *pnd = nd; - } - nd = *pnd; - } - [ - /* AddOperator */ - [ '+' | '-' | OR ] - { nd = dot2node(Oper, nd, NULLNODE); } - term(&(nd->nd_RIGHT)) - ]* - { *pnd = nd; } -; +SimpleExpression(struct node** pnd;) + { + register struct node* nd = 0; + } + : [ + [ + '+' + | '-' + ] + { nd = dot2leaf(Uoper); /* priority of unary operator ??? */ } + | + ] + term(pnd) + { + if (nd) + { + nd->nd_RIGHT = *pnd; + *pnd = nd; + } + nd = *pnd; + } + [ + /* AddOperator */ + [ + '+' + | '-' + | OR + ] + { nd = dot2node(Oper, nd, NULLNODE); } + term(&(nd->nd_RIGHT)) + ]* + { *pnd = nd; } + ; /* Inline in "SimpleExpression" AddOperator: - '+' | '-' | OR +'+' | '-' | OR ; */ -term(struct node **pnd;) -{ - register struct node *nd; -}: - factor(pnd) { nd = *pnd; } - [ - /* MulOperator */ - [ '*' | '/' | DIV | MOD | AND ] - { nd = dot2node(Oper, nd, NULLNODE); } - factor(&(nd->nd_RIGHT)) - ]* - { *pnd = nd; } -; +term(struct node** pnd;) + { + register struct node* nd; + } + : factor(pnd) + { nd = *pnd; } + [ + /* MulOperator */ + [ + '*' + | '/' + | DIV + | MOD + | AND + ] + { nd = dot2node(Oper, nd, NULLNODE); } + factor(&(nd->nd_RIGHT)) + ]* + { *pnd = nd; } + ; /* inline in "term" MulOperator: - '*' | '/' | DIV | MOD | AND +'*' | '/' | DIV | MOD | AND ; */ -factor(struct node **p;) -{ - register struct node *nd; - struct node *nd1; -} : - qualident(p) - [ - designator_tail(p) - [ - { *p = dot2node(Call, *p, NULLNODE); } - ActualParameters(&((*p)->nd_RIGHT)) - | - ] - | - bare_set(&nd1) - { nd = nd1; nd->nd_LEFT = *p; *p = nd; } - ] -| - bare_set(p) -| %default - [ - %default - INTEGER - | - REAL - | - STRING - ] { *p = dot2leaf(Value); - (*p)->nd_type = toktype; - } -| - '(' { nd = dot2leaf(Uoper); } - expression(p) - { /* In some cases we must leave the '(' as an unary - operator, because otherwise we cannot see that the - factor was not a designator - */ - register int class = (*p)->nd_class; +factor(struct node** p;) + { + register struct node* nd; + struct node* nd1; + } + : qualident(p) + [ + designator_tail(p) + [ + { *p = dot2node(Call, *p, NULLNODE); } + ActualParameters(&((*p)->nd_RIGHT)) + | + ] + | bare_set(&nd1) + { + nd = nd1; + nd->nd_LEFT = *p; + *p = nd; + } + ] + | bare_set(p) + | %default + [ + %default + INTEGER + | REAL + | STRING + ] + { + *p = dot2leaf(Value); + (*p)->nd_type = toktype; + } + | '(' + { nd = dot2leaf(Uoper); } + expression(p) + { + /* In some cases we must leave the '(' as an unary + operator, because otherwise we cannot see that the + factor was not a designator + */ + register int class = (*p)->nd_class; - if (class == Arrsel || - class == Arrow || - class == Name || - class == Select) { - nd->nd_RIGHT = *p; - *p = nd; - } - else FreeNode(nd); - } - ')' -| - NOT { *p = dot2leaf(Uoper); } - factor(&((*p)->nd_RIGHT)) -; + if (class == Arrsel || class == Arrow || class == Name || class == Select) + { + nd->nd_RIGHT = *p; + *p = nd; + } + else + FreeNode(nd); + } + ')' + | NOT + { *p = dot2leaf(Uoper); } + factor(&((*p)->nd_RIGHT)) + ; -bare_set(struct node **pnd;) -{ - register struct node *nd; -} : - '{' { DOT = SET; - *pnd = nd = dot2leaf(Xset); - nd->nd_type = bitset_type; - } - [ - element(nd) - [ { nd = nd->nd_RIGHT; } - ',' element(nd) - ]* - | - ] - '}' -; +bare_set(struct node** pnd;) + { + register struct node* nd; + } + : '{' + { + DOT = SET; + *pnd = nd = dot2leaf(Xset); + nd->nd_type = bitset_type; + } + [ + element(nd) + [ + { nd = nd->nd_RIGHT; } + ',' + element(nd) + ]* + | + ] + '}' + ; -ActualParameters(struct node **pnd;): - '(' ExpList(pnd)? ')' -; +ActualParameters(struct node** pnd;) + : '(' + ExpList(pnd)? + ')' + ; -element(struct node *nd;) : - expression(&(nd->nd_RIGHT)) - [ - UPTO - { nd->nd_RIGHT = dot2node(Link, nd->nd_RIGHT, NULLNODE);} - expression(&(nd->nd_RIGHT->nd_RIGHT)) - | - ] - { nd->nd_RIGHT = dot2node(Link, nd->nd_RIGHT, NULLNODE); - nd->nd_RIGHT->nd_symb = ','; - } -; +element(struct node* nd;) + : expression(&(nd->nd_RIGHT)) + [ + UPTO + { nd->nd_RIGHT = dot2node(Link, nd->nd_RIGHT, NULLNODE); } + expression(&(nd->nd_RIGHT->nd_RIGHT)) + | + ] + { + nd->nd_RIGHT = dot2node(Link, nd->nd_RIGHT, NULLNODE); + nd->nd_RIGHT->nd_symb = ','; + } + ; -designator(struct node **pnd;) -: - qualident(pnd) - designator_tail(pnd) -; +designator(struct node** pnd;) + : qualident(pnd) + designator_tail(pnd) + ; -designator_tail(struct node **pnd;): - visible_designator_tail(pnd) - [ %persistent - %default - selector(pnd) - | - visible_designator_tail(pnd) - ]* -| -; +designator_tail(struct node** pnd;) + : visible_designator_tail(pnd) + [ + %persistent + %default + selector(pnd) + | visible_designator_tail(pnd) + ]* + | + ; -visible_designator_tail(struct node **pnd;) -{ - register struct node *nd = *pnd; -}: - '[' { nd = dot2node(Arrsel, nd, NULLNODE); } - expression(&(nd->nd_RIGHT)) - [ - ',' - { nd = dot2node(Arrsel, nd, NULLNODE); - } - expression(&(nd->nd_RIGHT)) - ]* - ']' - { *pnd = nd; } -| - '^' { *pnd = dot2node(Arrow, NULLNODE, nd); } -; +visible_designator_tail(struct node** pnd;) + { + register struct node* nd = *pnd; + } + : '[' + { nd = dot2node(Arrsel, nd, NULLNODE); } + expression(&(nd->nd_RIGHT)) + [ + ',' + { nd = dot2node(Arrsel, nd, NULLNODE); } + expression(&(nd->nd_RIGHT)) + ]* + ']' + { *pnd = nd; } + | '^' + { *pnd = dot2node(Arrow, NULLNODE, nd); } + ; diff --git a/lang/m2/comp/program.g b/lang/m2/comp/program.g index 095764186..bc6ea81a2 100644 --- a/lang/m2/comp/program.g +++ b/lang/m2/comp/program.g @@ -5,284 +5,333 @@ * Author: Ceriel J.H. Jacobs */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/m2/comp/program.g + */ + /* O V E R A L L S T R U C T U R E */ /* $Id$ */ { -#include -#include -#include -#include "parameters.h" -#include "debug.h" - -#include "alloc.h" -#include "em_arith.h" -#include "em_label.h" -#include "em_code.h" -#include "stb.h" + #include + #include + #include + #include "parameters.h" + #include "debug.h" -#include "main.h" -#include "idf.h" -#include "LLlex.h" -#include "scope.h" -#include "def.h" -#include "type.h" -#include "lookup.h" -#include "error.h" -#include "stab.h" -#include "enter.h" -#include "node.h" -#include "f_info.h" -#include "warning.h" -#include "misc.h" -#include "defmodule.h" + #include "alloc.h" + #include "em_arith.h" + #include "em_label.h" + #include "em_code.h" + #include "stb.h" + #include "main.h" + #include "idf.h" + #include "LLlex.h" + #include "scope.h" + #include "def.h" + #include "type.h" + #include "lookup.h" + #include "error.h" + #include "stab.h" + #include "enter.h" + #include "node.h" + #include "f_info.h" + #include "warning.h" + #include "misc.h" + #include "defmodule.h" } /* - The grammar as given by Wirth is already almost LL(1); the - main problem is that the full form of a qualified designator - may be: - [ module_ident '.' ]* IDENT [ '.' field_ident ]* - which is quite confusing to an LL(1) parser. Rather than - resorting to context-sensitive techniques, I have decided - to render this as: - IDENT [ '.' IDENT ]* - on the grounds that it is quite natural to consider the first - IDENT to be the name of the object and regard the others as - field identifiers. +The grammar as given by Wirth is already almost LL(1); the +main problem is that the full form of a qualified designator +may be: +[ module_ident '.' ]* IDENT [ '.' field_ident ]* +which is quite confusing to an LL(1) parser. Rather than +resorting to context-sensitive techniques, I have decided +to render this as: +IDENT [ '.' IDENT ]* +on the grounds that it is quite natural to consider the first +IDENT to be the name of the object and regard the others as +field identifiers. */ %lexical LLlex; - -%start CompUnit, CompilationUnit; -%start DefModule, DefinitionModule; +%start CompUnit, CompilationUnit; +%start DefModule, DefinitionModule; ModuleDeclaration -{ - register struct def *df; - struct node *exportlist; - int qualified; -} : - MODULE IDENT { df = DefineLocalModule(dot.TOK_IDF); } - priority(&(df->mod_priority)) - ';' - import(1)* - export(&qualified, &exportlist) - block(&(df->mod_body)) - IDENT { EnterExportList(exportlist, qualified); - close_scope(SC_CHKFORW|SC_CHKPROC|SC_REVERSE); - match_id(df->df_idf, dot.TOK_IDF); - } -; + { + register struct def* df; + struct node* exportlist; + int qualified; + } + : MODULE IDENT + { df = DefineLocalModule(dot.TOK_IDF); } + priority(&(df->mod_priority)) + ';' + import(1)* + export(&qualified, &exportlist) + block(&(df->mod_body)) + IDENT + { + EnterExportList(exportlist, qualified); + close_scope(SC_CHKFORW | SC_CHKPROC | SC_REVERSE); + match_id(df->df_idf, dot.TOK_IDF); + } + ; -priority(struct node **prio;): - [ - '[' ConstExpression(prio) ']' - { if (! ((*prio)->nd_type->tp_fund & T_CARDINAL)) { - node_error(*prio, "illegal priority"); - } - } - | - ] -; +priority(struct node** prio;) + : [ + '[' + ConstExpression(prio) + ']' + { + if (!((*prio)->nd_type->tp_fund & T_CARDINAL)) + { + node_error(*prio, "illegal priority"); + } + } + | + ] + ; -export(int *QUALflag; struct node **ExportList;): - { *ExportList = 0; *QUALflag = D_EXPORTED; } - [ - EXPORT - [ - QUALIFIED - { *QUALflag = D_QEXPORTED; } - | - ] - IdentList(ExportList) ';' - | - ] -; +export(int* QUALflag; struct node** ExportList;) + : + { + *ExportList = 0; + *QUALflag = D_EXPORTED; + } + [ + EXPORT + [ + QUALIFIED + { *QUALflag = D_QEXPORTED; } + | + ] + IdentList(ExportList) + ';' + | + ] + ; import(int local;) -{ - struct node *ImportList; - register struct node *FromId = 0; - register struct def *df; -} : - /* - When parsing a global module, this is the place where we must - read already compiled definition modules. - If the FROM clause is present, the identifier in it is a module - name, otherwise the names in the import list are module names. - */ - [ FROM - IDENT - %substart DefinitionModule; - { FromId = dot2leaf(Name); - if (local) { - df = lookfor(FromId,enclosing(CurrVis),0,D_USED); - } - else df = GetDefinitionModule(dot.TOK_IDF, 1); - } - ]? - IMPORT IdentList(&ImportList) ';' - %substart DefinitionModule; - { if (FromId) { - EnterFromImportList(ImportList, df, FromId); - } - else { - EnterImportList(ImportList, - local, - enclosing(CurrVis)->sc_scope); - } - FreeNode(ImportList); - } -; + { + struct node* ImportList; + register struct node* FromId = 0; + register struct def* df; + } + : + /* + When parsing a global module, this is the place where we must + read already compiled definition modules. + If the FROM clause is present, the identifier in it is a module + name, otherwise the names in the import list are module names. + */ + [ + FROM IDENT + %substart DefinitionModule; + { + FromId = dot2leaf(Name); + if (local) + { + df = lookfor(FromId, enclosing(CurrVis), 0, D_USED); + } + else + df = GetDefinitionModule(dot.TOK_IDF, 1); + } + ]? + IMPORT + IdentList(&ImportList) + ';' + %substart DefinitionModule; + { + if (FromId) + { + EnterFromImportList(ImportList, df, FromId); + } + else + { + EnterImportList(ImportList, local, enclosing(CurrVis)->sc_scope); + } + FreeNode(ImportList); + } + ; DefinitionModule -{ - register struct def *df; - struct node *exportlist; - int dummy; - extern struct idf *DefId; - extern int ForeignFlag; - register struct scope *currscope = CurrentScope; - char buf[512]; -} : - DEFINITION - MODULE IDENT { df = define(dot.TOK_IDF, GlobalScope, D_MODULE); - df->df_flags |= D_BUSY | ForeignFlag; - currscope->sc_definedby = df; - if (DefId && - df->df_idf != DefId && - !is_anon_idf(df->df_idf)) { - error("DEFINITION MODULE name is \"%s\", not \"%s\"", - df->df_idf->id_text, DefId->id_text); - } - sprintf(buf, "_%s_", df->df_idf->id_text); - currscope->sc_name = strdup(buf); - df->mod_vis = CurrVis; - df->df_type = standard_type(T_RECORD, 1, (arith) 1); - df->df_type->rec_scope = currscope; - DefinitionModule++; - if (!Defined) { - Defined = df; - } - } - ';' - import(0)* - export(&dummy, &exportlist) - /* New Modula-2 does not have export lists in definition - modules. Issue a warning. - */ - { - if (exportlist) { -#ifndef STRICT_3RD_ED - if (! options['3']) -node_warning(exportlist, W_OLDFASHIONED, "export list in definition module ignored"); - else -#endif - error("export list not allowed in definition module"); - FreeNode(exportlist); - } - } - definition* END IDENT - { end_definition_list(&(currscope->sc_def)); - DefinitionModule--; - match_id(dot.TOK_IDF, df->df_idf); - df->df_flags &= ~D_BUSY; - } - '.' -; + { + register struct def* df; + struct node* exportlist; + int dummy; + extern struct idf* DefId; + extern int ForeignFlag; + register struct scope* currscope = CurrentScope; + char buf[512]; + } + : DEFINITION MODULE IDENT + { + df = define(dot.TOK_IDF, GlobalScope, D_MODULE); + df->df_flags |= D_BUSY | ForeignFlag; + currscope->sc_definedby = df; + if (DefId && df->df_idf != DefId && !is_anon_idf(df->df_idf)) + { + error("DEFINITION MODULE name is \"%s\", not \"%s\"", df->df_idf->id_text, + DefId->id_text); + } + sprintf(buf, "_%s_", df->df_idf->id_text); + currscope->sc_name = strdup(buf); + df->mod_vis = CurrVis; + df->df_type = standard_type(T_RECORD, 1, (arith)1); + df->df_type->rec_scope = currscope; + DefinitionModule++; + if (!Defined) + { + Defined = df; + } + } + ';' + import(0)* + export(&dummy, &exportlist) + /* New Modula-2 does not have export lists in definition + modules. Issue a warning. + */ + { + if (exportlist) + { + #ifndef STRICT_3RD_ED + if (!options['3']) + node_warning(exportlist, W_OLDFASHIONED, + "export list in definition module ignored"); + else + #endif + error("export list not allowed in definition module"); + FreeNode(exportlist); + } + } + definition* + END IDENT + { + end_definition_list(&(currscope->sc_def)); + DefinitionModule--; + match_id(dot.TOK_IDF, df->df_idf); + df->df_flags &= ~D_BUSY; + } + '.' + ; definition -{ - register struct def *df; - struct def *dummy; -} : - CONST [ %persistent ConstantDeclaration ';' ]* -| - TYPE - [ %persistent - IDENT { df = define(dot.TOK_IDF, CurrentScope, D_TYPE); } - [ '=' type(&(df->df_type)) - { SolveForwardTypeRefs(df); } - | /* empty */ - /* - Here, the exported type has a hidden implementation. - The export is said to be opaque. - It is restricted to pointer types. - */ - { df->df_kind = D_HIDDEN; - df->df_type = construct_type(T_HIDDEN, NULLTYPE); - } - ] - { -#ifdef DBSYMTAB - if (options['g']) stb_string(df, D_TYPE); -#endif - } - ';' - ]* -| - VAR [ %persistent VariableDeclaration ';' ]* -| - ProcedureHeading(&dummy, D_PROCHEAD) ';' -; + { + register struct def* df; + struct def* dummy; + } + : CONST + [ + %persistent + ConstantDeclaration ';' + ]* + | TYPE + [ + %persistent + IDENT + { df = define(dot.TOK_IDF, CurrentScope, D_TYPE); } + [ + '=' + type(&(df->df_type)) + { SolveForwardTypeRefs(df); } + | + /* empty */ + /* + Here, the exported type has a hidden implementation. + The export is said to be opaque. + It is restricted to pointer types. + */ + { + df->df_kind = D_HIDDEN; + df->df_type = construct_type(T_HIDDEN, NULLTYPE); + } + ] + { + #ifdef DBSYMTAB + if (options['g']) + stb_string(df, D_TYPE); + #endif + } + ';' + ]* + | VAR + [ + %persistent + VariableDeclaration ';' + ]* + | ProcedureHeading(&dummy, D_PROCHEAD) + ';' + ; ProgramModule -{ - register struct def *df; -} : - MODULE - IDENT - %substart DefinitionModule; - { - if (state == IMPLEMENTATION) { - int len = strlen(dot.TOK_IDF->id_text); - char* leafname = strrchr(FileName, '/'); - if (leafname) - leafname++; - else - leafname = FileName; + { + register struct def* df; + } + : MODULE IDENT + %substart DefinitionModule; + { + if (state == IMPLEMENTATION) + { + int len = strlen(dot.TOK_IDF->id_text); + char* leafname = strrchr(FileName, '/'); + if (leafname) + leafname++; + else + leafname = FileName; - if (len > 10) len = 10; - if (strncmp(leafname, dot.TOK_IDF->id_text, len)) { - warning(W_ORDINARY, "modulename %s does not match filename %s", dot.TOK_IDF->id_text, leafname); - } - df = GetDefinitionModule(dot.TOK_IDF, 0); - CurrVis = df->mod_vis; - } - else { - Defined = df = define(dot.TOK_IDF, GlobalScope, D_MODULE); - open_scope(CLOSEDSCOPE); - df->mod_vis = CurrVis; - CurrentScope->sc_name = "__M2M_"; - CurrentScope->sc_definedby = df; - } - } - priority(&(df->mod_priority)) - ';' import(0)* - block(&(df->mod_body)) IDENT - { - close_scope(SC_CHKFORW|SC_CHKPROC|SC_REVERSE); - match_id(df->df_idf, dot.TOK_IDF); - } - '.' -; + if (len > 10) + len = 10; + if (strncmp(leafname, dot.TOK_IDF->id_text, len)) + { + warning(W_ORDINARY, "modulename %s does not match filename %s", + dot.TOK_IDF->id_text, leafname); + } + df = GetDefinitionModule(dot.TOK_IDF, 0); + CurrVis = df->mod_vis; + } + else + { + Defined = df = define(dot.TOK_IDF, GlobalScope, D_MODULE); + open_scope(CLOSEDSCOPE); + df->mod_vis = CurrVis; + CurrentScope->sc_name = "__M2M_"; + CurrentScope->sc_definedby = df; + } + } + priority(&(df->mod_priority)) + ';' + import(0)* + block(&(df->mod_body)) + IDENT + { + close_scope(SC_CHKFORW | SC_CHKPROC | SC_REVERSE); + match_id(df->df_idf, dot.TOK_IDF); + } + '.' + ; -CompilationUnit: - { error("Compiling a definition module"); - open_scope(CLOSEDSCOPE); - state = DEFINITION; - } - DefinitionModule - { close_scope(SC_CHKFORW); } -| %default - [ - IMPLEMENTATION - { state = IMPLEMENTATION; } - | - /* empty */ - { state = PROGRAM; } - ] - ProgramModule -; +CompilationUnit + : + { + error("Compiling a definition module"); + open_scope(CLOSEDSCOPE); + state = DEFINITION; + } + DefinitionModule + { close_scope(SC_CHKFORW); } + | %default + [ + IMPLEMENTATION + { state = IMPLEMENTATION; } + | + /* empty */ + { state = PROGRAM; } + ] + ProgramModule + ; diff --git a/lang/m2/comp/statement.g b/lang/m2/comp/statement.g index 0efb4f769..43c41d0a6 100644 --- a/lang/m2/comp/statement.g +++ b/lang/m2/comp/statement.g @@ -5,289 +5,329 @@ * Author: Ceriel J.H. Jacobs */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/m2/comp/statement.g + */ + /* S T A T E M E N T S */ /* $Id$ */ { -#include -#include "em_arith.h" -#include "em_label.h" + #include + #include "em_arith.h" + #include "em_label.h" -#include "parameters.h" -#include "idf.h" -#include "LLlex.h" -#include "scope.h" -#include "def.h" -#include "type.h" -#include "error.h" -#include "node.h" + #include "parameters.h" + #include "idf.h" + #include "LLlex.h" + #include "scope.h" + #include "def.h" + #include "type.h" + #include "error.h" + #include "node.h" -static int loopcount = 0; /* Count nested loops */ -extern struct node *EmptyStatement; + static int loopcount = 0; /* Count nested loops */ + extern struct node* EmptyStatement; } -statement(struct node **pnd;) -{ - register struct node *nd; - extern int return_occurred; -} : - /* - * This part is not in the reference grammar. The reference grammar - * states : assignment | ProcedureCall | ... - * but this gives LL(1) conflicts - */ - designator(pnd) - [ { nd = dot2node(Stat, *pnd, NULLNODE); - nd->nd_symb = '('; - nd->nd_lineno = (*pnd)->nd_lineno; - } - ActualParameters(&(nd->nd_RIGHT))? - | - [ BECOMES - | %erroneous '=' - { error("':=' expected instead of '='"); - DOT = BECOMES; - } - ] - { nd = dot2node(Stat, *pnd, NULLNODE); } - expression(&(nd->nd_RIGHT)) - ] - { *pnd = nd; } - /* - * end of changed part - */ -| - IfStatement(pnd) -| - CaseStatement(pnd) -| - WHILE { *pnd = nd = dot2leaf(Stat); } - expression(&(nd->nd_LEFT)) - DO - StatementSequence(&(nd->nd_RIGHT)) - END -| - REPEAT { *pnd = nd = dot2leaf(Stat); } - StatementSequence(&(nd->nd_LEFT)) - UNTIL - expression(&(nd->nd_RIGHT)) -| - { loopcount++; } - LOOP { *pnd = nd = dot2leaf(Stat); } - StatementSequence(&((*pnd)->nd_RIGHT)) - END - { loopcount--; } -| - ForStatement(pnd) -| - WITH { *pnd = nd = dot2leaf(Stat); } - designator(&(nd->nd_LEFT)) - DO - StatementSequence(&(nd->nd_RIGHT)) - END -| - EXIT - { if (!loopcount) error("EXIT not in a LOOP"); - *pnd = dot2leaf(Stat); - } -| - ReturnStatement(pnd) - { return_occurred = 1; } -| - /* empty */ { *pnd = EmptyStatement; } -; +statement(struct node** pnd;) + { + register struct node* nd; + extern int return_occurred; + } + : + /* + * This part is not in the reference grammar. The reference grammar + * states : assignment | ProcedureCall | ... + * but this gives LL(1) conflicts + */ + designator(pnd) + [ + { + nd = dot2node(Stat, *pnd, NULLNODE); + nd->nd_symb = '('; + nd->nd_lineno = (*pnd)->nd_lineno; + } + ActualParameters(&(nd->nd_RIGHT))? + | [ + BECOMES + | %erroneous '=' + { + error("':=' expected instead of '='"); + DOT = BECOMES; + } + ] + { nd = dot2node(Stat, *pnd, NULLNODE); } + expression(&(nd->nd_RIGHT)) + ] + { *pnd = nd; } + /* + * end of changed part + */ + | IfStatement(pnd) + | CaseStatement(pnd) + | WHILE + { *pnd = nd = dot2leaf(Stat); } + expression(&(nd->nd_LEFT)) + DO + StatementSequence(&(nd->nd_RIGHT)) + END + | REPEAT + { *pnd = nd = dot2leaf(Stat); } + StatementSequence(&(nd->nd_LEFT)) + UNTIL + expression(&(nd->nd_RIGHT)) + | + { loopcount++; } + LOOP + { *pnd = nd = dot2leaf(Stat); } + StatementSequence(&((*pnd)->nd_RIGHT)) + END + { loopcount--; } + | ForStatement(pnd) + | WITH + { *pnd = nd = dot2leaf(Stat); } + designator(&(nd->nd_LEFT)) + DO + StatementSequence(&(nd->nd_RIGHT)) + END + | EXIT + { + if (!loopcount) + error("EXIT not in a LOOP"); + *pnd = dot2leaf(Stat); + } + | ReturnStatement(pnd) + { return_occurred = 1; } + | + /* empty */ + { *pnd = EmptyStatement; } + ; /* - * The next two rules in-line in "Statement", because of an LL(1) conflict +* The next two rules in-line in "Statement", because of an LL(1) conflict assignment: - designator BECOMES expression +designator BECOMES expression ; ProcedureCall: - designator ActualParameters? +designator ActualParameters? ; */ -StatementSequence(struct node **pnd;) -{ - struct node *nd; - register struct node *nd1; -} : - statement(pnd) - [ %persistent - ';' - statement(&nd) - { if (nd != EmptyStatement) { - nd1 = dot2node(Link, *pnd, nd); - *pnd = nd1; - nd1->nd_symb = ';'; - pnd = &(nd1->nd_RIGHT); - } - } - ]* -; +StatementSequence(struct node** pnd;) + { + struct node* nd; + register struct node* nd1; + } + : statement(pnd) + [ + %persistent + ';' + statement(&nd) + { + if (nd != EmptyStatement) + { + nd1 = dot2node(Link, *pnd, nd); + *pnd = nd1; + nd1->nd_symb = ';'; + pnd = &(nd1->nd_RIGHT); + } + } + ]* + ; -IfStatement(struct node **pnd;) -{ - register struct node *nd; -} : - IF { nd = dot2leaf(Stat); - *pnd = nd; - } - expression(&(nd->nd_LEFT)) - THEN { nd->nd_RIGHT = dot2leaf(Link); - nd = nd->nd_RIGHT; - } - StatementSequence(&(nd->nd_LEFT)) - [ - ELSIF { nd->nd_RIGHT = dot2leaf(Stat); - nd = nd->nd_RIGHT; - nd->nd_symb = IF; - } - expression(&(nd->nd_LEFT)) - THEN { nd->nd_RIGHT = dot2leaf(Link); - nd = nd->nd_RIGHT; - } - StatementSequence(&(nd->nd_LEFT)) - ]* - [ - ELSE - StatementSequence(&(nd->nd_RIGHT)) - | - ] - END -; +IfStatement(struct node** pnd;) + { + register struct node* nd; + } + : IF + { + nd = dot2leaf(Stat); + *pnd = nd; + } + expression(&(nd->nd_LEFT)) + THEN + { + nd->nd_RIGHT = dot2leaf(Link); + nd = nd->nd_RIGHT; + } + StatementSequence(&(nd->nd_LEFT)) + [ + ELSIF + { + nd->nd_RIGHT = dot2leaf(Stat); + nd = nd->nd_RIGHT; + nd->nd_symb = IF; + } + expression(&(nd->nd_LEFT)) + THEN + { + nd->nd_RIGHT = dot2leaf(Link); + nd = nd->nd_RIGHT; + } + StatementSequence(&(nd->nd_LEFT)) + ]* + [ + ELSE + StatementSequence(&(nd->nd_RIGHT)) + | + ] + END + ; -CaseStatement(struct node **pnd;) -{ - register struct node *nd; - struct type *tp = 0; -} : - CASE { *pnd = nd = dot2leaf(Stat); } - expression(&(nd->nd_LEFT)) - OF - case(&(nd->nd_RIGHT), &tp) - { nd = nd->nd_RIGHT; } - [ - '|' - case(&(nd->nd_RIGHT), &tp) - { nd = nd->nd_RIGHT; } - ]* - [ ELSE StatementSequence(&(nd->nd_RIGHT)) - | - ] - END -; +CaseStatement(struct node** pnd;) + { + register struct node* nd; + struct type* tp = 0; + } + : CASE + { *pnd = nd = dot2leaf(Stat); } + expression(&(nd->nd_LEFT)) + OF + case(&(nd->nd_RIGHT), &tp) + { nd = nd->nd_RIGHT; } + [ + '|' + case(&(nd->nd_RIGHT), &tp) + { nd = nd->nd_RIGHT; } + ]* + [ + ELSE + StatementSequence(&(nd->nd_RIGHT)) + | + ] + END + ; -case(struct node **pnd; struct type **ptp;) : - [ CaseLabelList(ptp, pnd) - ':' { *pnd = dot2node(Link, *pnd, NULLNODE); } - StatementSequence(&((*pnd)->nd_RIGHT)) - | - ] - { *pnd = dot2node(Link, *pnd, NULLNODE); - (*pnd)->nd_symb = '|'; - } -; +case(struct node** pnd; struct type** ptp;) + : [ + CaseLabelList(ptp, pnd) + ':' + { *pnd = dot2node(Link, *pnd, NULLNODE); } + StatementSequence(&((*pnd)->nd_RIGHT)) + | + ] + { + *pnd = dot2node(Link, *pnd, NULLNODE); + (*pnd)->nd_symb = '|'; + } + ; -/* inline in statement; lack of space +/* inline in statement; lack of space WhileStatement(struct node **pnd;) { - register struct node *nd; +register struct node *nd; }: - WHILE { *pnd = nd = dot2leaf(Stat); } - expression(&(nd->nd_LEFT)) - DO - StatementSequence(&(nd->nd_RIGHT)) - END +WHILE { *pnd = nd = dot2leaf(Stat); } +expression(&(nd->nd_LEFT)) +DO +StatementSequence(&(nd->nd_RIGHT)) +END ; RepeatStatement(struct node **pnd;) { - register struct node *nd; +register struct node *nd; }: - REPEAT { *pnd = nd = dot2leaf(Stat); } - StatementSequence(&(nd->nd_LEFT)) - UNTIL - expression(&(nd->nd_RIGHT)) +REPEAT { *pnd = nd = dot2leaf(Stat); } +StatementSequence(&(nd->nd_LEFT)) +UNTIL +expression(&(nd->nd_RIGHT)) ; */ -ForStatement(struct node **pnd;) -{ - register struct node *nd, *nd1; -}: - FOR { *pnd = nd = dot2leaf(Stat); } - IDENT { nd1 = dot2leaf(Name); } - BECOMES { nd->nd_LEFT = dot2node(Stat, nd1, dot2leaf(Link)); - nd1 = nd->nd_LEFT->nd_RIGHT; - nd1->nd_symb = TO; - } - expression(&(nd1->nd_LEFT)) - TO - expression(&(nd1->nd_RIGHT)) - { nd->nd_RIGHT = nd1 = dot2leaf(Link); - nd1->nd_symb = BY; - } - [ - BY - ConstExpression(&(nd1->nd_LEFT)) - { if (!(nd1->nd_LEFT->nd_type->tp_fund & T_INTORCARD)) { - error("illegal type in BY clause"); - } - } - | - { nd1->nd_LEFT = dot2leaf(Value); - nd1->nd_LEFT->nd_INT = 1; - } - ] - DO - StatementSequence(&(nd1->nd_RIGHT)) - END -; +ForStatement(struct node** pnd;) + { + register struct node *nd, *nd1; + } + : FOR + { *pnd = nd = dot2leaf(Stat); } + IDENT + { nd1 = dot2leaf(Name); } + BECOMES + { + nd->nd_LEFT = dot2node(Stat, nd1, dot2leaf(Link)); + nd1 = nd->nd_LEFT->nd_RIGHT; + nd1->nd_symb = TO; + } + expression(&(nd1->nd_LEFT)) + TO + expression(&(nd1->nd_RIGHT)) + { + nd->nd_RIGHT = nd1 = dot2leaf(Link); + nd1->nd_symb = BY; + } + [ + BY + ConstExpression(&(nd1->nd_LEFT)) + { + if (!(nd1->nd_LEFT->nd_type->tp_fund & T_INTORCARD)) + { + error("illegal type in BY clause"); + } + } + | + { + nd1->nd_LEFT = dot2leaf(Value); + nd1->nd_LEFT->nd_INT = 1; + } + ] + DO + StatementSequence(&(nd1->nd_RIGHT)) + END + ; /* inline in Statement; lack of space LoopStatement(struct node **pnd;): - LOOP { *pnd = dot2leaf(Stat); } - StatementSequence(&((*pnd)->nd_RIGHT)) - END +LOOP { *pnd = dot2leaf(Stat); } +StatementSequence(&((*pnd)->nd_RIGHT)) +END ; WithStatement(struct node **pnd;) { - register struct node *nd; +register struct node *nd; }: - WITH { *pnd = nd = dot2leaf(Stat); } - designator(&(nd->nd_LEFT)) - DO - StatementSequence(&(nd->nd_RIGHT)) - END +WITH { *pnd = nd = dot2leaf(Stat); } +designator(&(nd->nd_LEFT)) +DO +StatementSequence(&(nd->nd_RIGHT)) +END ; */ -ReturnStatement(struct node **pnd;) -{ - register struct def *df = CurrentScope->sc_definedby; - register struct type *tp = df->df_type ? ResultType(df->df_type) : 0; - register struct node *nd; -} : - - RETURN { *pnd = nd = dot2leaf(Stat); } - [ - expression(&(nd->nd_RIGHT)) - { if (scopeclosed(CurrentScope)) { -error("a module body cannot return a value"); - } - else if (! tp) { -error("procedure \"%s\" is not a function, so cannot return a value", df->df_idf->id_text); - } - } - | - { if (tp) { -error("function procedure \"%s\" must return a value", df->df_idf->id_text); - } - } - ] -; +ReturnStatement(struct node** pnd;) + { + register struct def* df = CurrentScope->sc_definedby; + register struct type* tp = df->df_type ? ResultType(df->df_type) : 0; + register struct node* nd; + } + : RETURN + { *pnd = nd = dot2leaf(Stat); } + [ + expression(&(nd->nd_RIGHT)) + { + if (scopeclosed(CurrentScope)) + { + error("a module body cannot return a value"); + } + else if (!tp) + { + error("procedure \"%s\" is not a function, so cannot return a value", + df->df_idf->id_text); + } + } + | + { + if (tp) + { + error("function procedure \"%s\" must return a value", df->df_idf->id_text); + } + } + ] + ; diff --git a/lang/m2/m2mm/declar.g b/lang/m2/m2mm/declar.g index 5d45709fc..44f5399e8 100644 --- a/lang/m2/m2mm/declar.g +++ b/lang/m2/m2mm/declar.g @@ -5,274 +5,279 @@ * Author: Ceriel J.H. Jacobs */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/m2/m2mm/declar.g + */ + /* D E C L A R A T I O N S */ /* stripped down version of the one in the Modula-2 compiler */ /* $Id$ */ -ProcedureHeading : - PROCEDURE IDENT - [ - '(' - [ - FPSection - [ - ';' FPSection - ]* - | - ] - ')' - [ - ':' qualtype - | - /* empty */ - ] - | - /* empty */ - ] -; - -block : - [ %persistent - declaration - ]* - [ %default - BEGIN StatementSequence - | - /* empty */ - ] - END -; - -declaration : - CONST [ ConstantDeclaration ';' ]* -| - TYPE [ TypeDeclaration ';' ]* -| - VAR [ VariableDeclaration ';' ]* -| - ProcedureHeading ';' block IDENT ';' -| - ModuleDeclaration ';' -; - -FPSection : - var IdentList ':' FormalType -; - -FormalType : - ARRAY OF qualtype -| - qualtype -; - -TypeDeclaration : - IDENT '=' type -; - -type : - %default - SimpleType -| - ArrayType -| - RecordType -| - SetType -| - PointerType -| - ProcedureType -; - -SimpleType : - qualtype - [ - /* empty */ - | - SubrangeType - /* The subrange type is given a base type by the - qualident (this is new modula-2). - */ - ] -| - enumeration -| - SubrangeType -; - -enumeration : - '(' IdentList ')' -; - -IdentList : - IDENT - [ %persistent - ',' IDENT - ]* -; - -SubrangeType : - /* - This is not exactly the rule in the new report, but see - the rule for "SimpleType". - */ - '[' ConstExpression UPTO ConstExpression ']' -; - -ArrayType : - ARRAY SimpleType - [ - ',' SimpleType - ]* - OF type -; - -RecordType : - RECORD FieldListSequence END -; - -FieldListSequence : - FieldList - [ - ';' FieldList - ]* -; - -FieldList : - IdentList ':' type -| - CASE - /* Also accept old fashioned Modula-2 syntax, but give a warning. - Sorry for the complicated code. - */ - [ - qualident - [ - ':' qualtype - /* This is correct, in both kinds of Modula-2, if - the first qualident is a single identifier. - */ - | - /* empty */ - /* Old fashioned! the first qualident now represents - the type - */ - ] - | - ':' qualtype - /* Aha, third edition. Well done! */ - ] - OF variant - [ - '|' variant - ]* - [ - ELSE FieldListSequence - | - /* empty */ - ] - END -| - /* empty */ -; - -variant : - [ - CaseLabelList ':' FieldListSequence - | - /* empty */ - ] - /* Changed rule in new modula-2 */ -; - -CaseLabelList : - CaseLabels - [ - ',' CaseLabels - ]* -; - -CaseLabels : - ConstExpression - [ - UPTO ConstExpression - | - /* empty */ - ] -; - -SetType : - SET OF SimpleType -; +ProcedureHeading + : PROCEDURE IDENT + [ + '(' + [ + FPSection + [ + ';' FPSection + ]* + | + ] + ')' + [ + ':' qualtype + | + /* empty */ + ] + | + /* empty */ + ] + ; + +block + : [ + %persistent + declaration + ]* + [ + %default + BEGIN StatementSequence + | + /* empty */ + ] + END + ; + +declaration + : CONST + [ + ConstantDeclaration ';' + ]* + | TYPE + [ + TypeDeclaration ';' + ]* + | VAR + [ + VariableDeclaration ';' + ]* + | ProcedureHeading ';' block IDENT ';' + | ModuleDeclaration ';' + ; + +FPSection + : var IdentList ':' FormalType + ; + +FormalType + : ARRAY OF qualtype + | qualtype + ; + +TypeDeclaration + : IDENT '=' type + ; + +type + : %default + SimpleType + | ArrayType + | RecordType + | SetType + | PointerType + | ProcedureType + ; + +SimpleType + : qualtype + [ + /* empty */ + | SubrangeType + /* The subrange type is given a base type by the + qualident (this is new modula-2). + */ + ] + | enumeration + | SubrangeType + ; + +enumeration + : '(' IdentList ')' + ; + +IdentList + : IDENT + [ + %persistent + ',' IDENT + ]* + ; + +SubrangeType + : + /* + This is not exactly the rule in the new report, but see + the rule for "SimpleType". + */ + '[' ConstExpression UPTO ConstExpression ']' + ; + +ArrayType + : ARRAY SimpleType + [ + ',' SimpleType + ]* + OF type + ; + +RecordType + : RECORD FieldListSequence END + ; + +FieldListSequence + : FieldList + [ + ';' FieldList + ]* + ; + +FieldList + : IdentList ':' type + | CASE + /* Also accept old fashioned Modula-2 syntax, but give a warning. + Sorry for the complicated code. + */ + [ + qualident + [ + ':' qualtype + /* This is correct, in both kinds of Modula-2, if + the first qualident is a single identifier. + */ + | + /* empty */ + /* Old fashioned! the first qualident now represents + the type + */ + ] + | ':' qualtype + /* Aha, third edition. Well done! */ + ] + OF variant + [ + '|' variant + ]* + [ + ELSE FieldListSequence + | + /* empty */ + ] + END + | + /* empty */ + ; + +variant + : [ + CaseLabelList ':' FieldListSequence + | + /* empty */ + ] + /* Changed rule in new modula-2 */ + ; + +CaseLabelList + : CaseLabels + [ + ',' CaseLabels + ]* + ; + +CaseLabels + : ConstExpression + [ + UPTO ConstExpression + | + /* empty */ + ] + ; + +SetType + : SET OF SimpleType + ; /* In a pointer type definition, the type pointed at does not - have to be declared yet, so be careful about identifying - type-identifiers +have to be declared yet, so be careful about identifying +type-identifiers */ -PointerType : - POINTER TO type -; - -qualtype : - qualident -; - -ProcedureType : - PROCEDURE - [ - FormalTypeList - | - /* empty */ - ] -; - -FormalTypeList : - '(' - [ - VarFormalType - [ - ',' VarFormalType - ]* - | - /* empty */ - ] - ')' - [ - ':' qualtype - | - /* empty */ - ] -; - -VarFormalType : - var FormalType -; - -var : - VAR -| - /* empty */ -; - -ConstantDeclaration : - IDENT '=' ConstExpression -; - -VariableDeclaration : - IdentAddr - [ %persistent - ',' IdentAddr - ]* - ':' type -; - -IdentAddr : - IDENT - [ - '[' ConstExpression ']' - | - /* empty */ - ] -; +PointerType + : POINTER TO type + ; + +qualtype + : qualident + ; + +ProcedureType + : PROCEDURE + [ + FormalTypeList + | + /* empty */ + ] + ; + +FormalTypeList + : '(' + [ + VarFormalType + [ + ',' VarFormalType + ]* + | + /* empty */ + ] + ')' + [ + ':' qualtype + | + /* empty */ + ] + ; + +VarFormalType + : var FormalType + ; + +var + : VAR + | + /* empty */ + ; + +ConstantDeclaration + : IDENT '=' ConstExpression + ; + +VariableDeclaration + : IdentAddr + [ + %persistent + ',' IdentAddr + ]* + ':' type + ; + +IdentAddr + : IDENT + [ + '[' ConstExpression ']' + | + /* empty */ + ] + ; diff --git a/lang/m2/m2mm/expression.g b/lang/m2/m2mm/expression.g index 06b10a85e..6e6ae6b48 100644 --- a/lang/m2/m2mm/expression.g +++ b/lang/m2/m2mm/expression.g @@ -5,146 +5,167 @@ * Author: Ceriel J.H. Jacobs */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/m2/m2mm/expression.g + */ + /* E X P R E S S I O N S */ /* stripped down version of the one in the Modula-2 compiler */ /* $Id$ */ -qualident : - IDENT - [ - selector - ]* -; - -selector : - '.' IDENT -; - -ExpList : - expression - [ - ',' expression - ]* -; - -ConstExpression : - expression - /* - * Changed rule in new Modula-2. - */ -; - -expression : - SimpleExpression - [ - /* relation */ - [ '=' | '#' | '<' | LESSEQUAL | '>' | GREATEREQUAL | IN ] - SimpleExpression - | - /* empty */ - ] -; - -SimpleExpression : - [ - '+' - | - '-' - | - /* empty */ - ] - term - [ - /* AddOperator */ - [ '+' | '-' | OR ] term - ]* -; - -term : - factor - [ - /* MulOperator */ - [ '*' | '/' | DIV | MOD | AND ] factor - ]* -; - -factor : - qualident - [ - designator_tail? - [ - ActualParameters - | - /* empty */ - ] - | - bare_set - ] -| - bare_set -| %default - [ %default - INTEGER - | - REAL - | - STRING - ] -| - '(' expression ')' -| - NOT factor -; - -bare_set : - '{' - [ - element - [ - ',' element - ]* - | - /* empty */ - ] - '}' -; - -ActualParameters : - '(' ExpList? ')' -; - -element : - expression - [ - UPTO expression - | - /* empty */ - ] -; - -designator : - qualident designator_tail? -; - -designator_tail : - visible_designator_tail - [ %persistent - %default - selector - | - visible_designator_tail - ]* -; - -visible_designator_tail : - '[' - expression - [ - ',' expression - ]* - ']' -| - '^' -; +qualident + : IDENT + [ + selector + ]* + ; + +selector + : '.' IDENT + ; + +ExpList + : expression + [ + ',' expression + ]* + ; + +ConstExpression + : expression + /* + * Changed rule in new Modula-2. + */ + ; + +expression + : SimpleExpression + [ + /* relation */ + [ + '=' + | '#' + | '<' + | LESSEQUAL + | '>' + | GREATEREQUAL + | IN + ] + SimpleExpression + | + /* empty */ + ] + ; + +SimpleExpression + : [ + '+' + | '-' + | + /* empty */ + ] + term + [ + /* AddOperator */ + [ + '+' + | '-' + | OR + ] + term + ]* + ; + +term + : factor + [ + /* MulOperator */ + [ + '*' + | '/' + | DIV + | MOD + | AND + ] + factor + ]* + ; + +factor + : qualident + [ + designator_tail? + [ + ActualParameters + | + /* empty */ + ] + | bare_set + ] + | bare_set + | %default + [ + %default + INTEGER + | REAL + | STRING + ] + | '(' expression ')' + | NOT factor + ; + +bare_set + : '{' + [ + element + [ + ',' element + ]* + | + /* empty */ + ] + '}' + ; + +ActualParameters + : '(' + ExpList? + ')' + ; + +element + : expression + [ + UPTO expression + | + /* empty */ + ] + ; + +designator + : qualident + designator_tail? + ; + +designator_tail + : visible_designator_tail + [ + %persistent + %default + selector + | visible_designator_tail + ]* + ; + +visible_designator_tail + : '[' expression + [ + ',' expression + ]* + ']' + | '^' + ; diff --git a/lang/m2/m2mm/program.g b/lang/m2/m2mm/program.g index 492c4398e..6e4e10bdf 100644 --- a/lang/m2/m2mm/program.g +++ b/lang/m2/m2mm/program.g @@ -5,6 +5,12 @@ * Author: Ceriel J.H. Jacobs */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/m2/m2mm/program.g + */ + /* O V E R A L L S T R U C T U R E */ /* stripped down version of the one in the Modula-2 compiler */ @@ -12,226 +18,260 @@ /* $Id$ */ /* - The grammar as given by Wirth is already almost LL(1); the - main problem is that the full form of a qualified designator - may be: - [ module_ident '.' ]* IDENT [ '.' field_ident ]* - which is quite confusing to an LL(1) parser. Rather than - resorting to context-sensitive techniques, I have decided - to render this as: - IDENT [ '.' IDENT ]* - on the grounds that it is quite natural to consider the first - IDENT to be the name of the object and regard the others as - field identifiers. +The grammar as given by Wirth is already almost LL(1); the +main problem is that the full form of a qualified designator +may be: +[ module_ident '.' ]* IDENT [ '.' field_ident ]* +which is quite confusing to an LL(1) parser. Rather than +resorting to context-sensitive techniques, I have decided +to render this as: +IDENT [ '.' IDENT ]* +on the grounds that it is quite natural to consider the first +IDENT to be the name of the object and regard the others as +field identifiers. */ { -#include "main.h" -#include "idf.h" -#include "f_info.h" -#include "LLlex.h" -#include - -struct lnk * -new_lnk() -{ - static struct lnk *p; - static int cnt; - - if (cnt-- <= 0) { - p = (struct lnk *)malloc(50*sizeof(struct lnk)); - cnt = 49; - } - p->lnk_next = 0; - p->lnk_imp = 0; - return p++; -} + #include "main.h" + #include "idf.h" + #include "f_info.h" + #include "LLlex.h" + #include + + struct lnk* new_lnk() + { + static struct lnk* p; + static int cnt; + + if (cnt-- <= 0) + { + p = (struct lnk*)malloc(50 * sizeof(struct lnk)); + cnt = 49; + } + p->lnk_next = 0; + p->lnk_imp = 0; + return p++; + } } %lexical LLlex; +%start CompUnit, CompilationUnit; +%start DefModule, DefinitionModule; -%start CompUnit, CompilationUnit; -%start DefModule, DefinitionModule; - -ModuleDeclaration : - MODULE IDENT priority ';' import((struct lnk **) 0)* export? - block IDENT -; - -priority: - [ - '[' ConstExpression ']' - | - /* empty */ - ] -; - -export : - EXPORT - [ - QUALIFIED - | - /* empty */ - ] - IdentList ';' -; - -import(struct lnk **p;) -{ - register struct idf *fromid = 0; - struct idf *id; -} -: - { if (p) while (*p) p = &((*p)->lnk_next); } - [ FROM - identifier(&id) { fromid = id; - if (p) { - if (AddToList(fromid->id_text, ".def")) { - *p = new_lnk(); - (*p)->lnk_imp = fromid; - } - } - } - ]? - IMPORT - identifier(&id) { if (! fromid && p) { - if (AddToList(id->id_text, ".def")) { - *p = new_lnk(); - (*p)->lnk_imp = id; - p = &((*p)->lnk_next); - } - } - } - [ - ',' identifier(&id) - { if (! fromid && p) { - if (AddToList(id->id_text, ".def")) { - *p = new_lnk(); - (*p)->lnk_imp = id; - p = &((*p)->lnk_next); - } - } - } - ]* - ';' - /* - When parsing a global module, this is the place where we must - read already compiled definition modules. - If the FROM clause is present, the identifier in it is a module - name, otherwise the names in the import list are module names. - */ -; +ModuleDeclaration + : MODULE IDENT priority ';' + import((struct lnk**)0)* + export? + block IDENT + ; + +priority + : [ + '[' ConstExpression ']' + | + /* empty */ + ] + ; + +export + : EXPORT + [ + QUALIFIED + | + /* empty */ + ] + IdentList ';' + ; + +import(struct lnk** p;) + { + register struct idf* fromid = 0; + struct idf* id; + } + : + { if (p) while (*p) p = &((*p)->lnk_next); } + [ + FROM + identifier(&id) + { + fromid = id; + if (p) + { + if (AddToList(fromid->id_text, ".def")) + { + *p = new_lnk(); + (*p)->lnk_imp = fromid; + } + } + } + ]? + IMPORT + identifier(&id) + { + if (!fromid && p) + { + if (AddToList(id->id_text, ".def")) + { + *p = new_lnk(); + (*p)->lnk_imp = id; + p = &((*p)->lnk_next); + } + } + } + [ + ',' + identifier(&id) + { + if (!fromid && p) + { + if (AddToList(id->id_text, ".def")) + { + *p = new_lnk(); + (*p)->lnk_imp = id; + p = &((*p)->lnk_next); + } + } + } + ]* + ';' + /* + When parsing a global module, this is the place where we must + read already compiled definition modules. + If the FROM clause is present, the identifier in it is a module + name, otherwise the names in the import list are module names. + */ + ; DefinitionModule -{ - struct idf *id; - extern char *strrchr(); -} -: - DEFINITION - MODULE identifier(&id) - { if (! ForeignFlag) { - AddToList(id->id_text, ".mod"); - } - if (! id->id_type) { - id->id_type = DEFINITION; - } - else if (id->id_type != IMPLEMENTATION) { - error("multiple declaration for module %s", - id->id_text); - } - if (! id->id_dir) { - id->id_dir = WorkingDir; - } - else if (strcmp(id->id_dir, WorkingDir)) { - Gerror("definition and implementation of module %s reside in different directories", id->id_text); - } - id->id_def = strrchr(FileName, '/'); - if (! id->id_def) id->id_def = FileName; - else (id->id_def)++; - CurrentArg->a_idf = id; - } - ';' - import(&(id->id_defimports))* - [ - export - | - /* empty */ - ] - definition* END IDENT - '.' -; - -definition : - CONST [ %persistent ConstantDeclaration ';' ]* -| - TYPE - [ %persistent - IDENT - [ '=' type - | /* empty */ - /* - Here, the exported type has a hidden implementation. - The export is said to be opaque. - It is restricted to pointer types. - */ - ] - ';' - ]* -| - VAR [ %persistent VariableDeclaration ';' ]* -| - ProcedureHeading - ';' -; + { + struct idf* id; + extern char* strrchr(); + } + : DEFINITION MODULE + identifier(&id) + { + if (!ForeignFlag) + { + AddToList(id->id_text, ".mod"); + } + if (!id->id_type) + { + id->id_type = DEFINITION; + } + else if (id->id_type != IMPLEMENTATION) + { + error("multiple declaration for module %s", id->id_text); + } + if (!id->id_dir) + { + id->id_dir = WorkingDir; + } + else if (strcmp(id->id_dir, WorkingDir)) + { + Gerror("definition and implementation of module %s reside in different directories", + id->id_text); + } + id->id_def = strrchr(FileName, '/'); + if (!id->id_def) + id->id_def = FileName; + else + (id->id_def)++; + CurrentArg->a_idf = id; + } + ';' + import(&(id->id_defimports))* + [ + export + | + /* empty */ + ] + definition* + END IDENT '.' + ; + +definition + : CONST + [ + %persistent + ConstantDeclaration ';' + ]* + | TYPE + [ + %persistent + IDENT + [ + '=' type + | + /* empty */ + /* + Here, the exported type has a hidden implementation. + The export is said to be opaque. + It is restricted to pointer types. + */ + ] + ';' + ]* + | VAR + [ + %persistent + VariableDeclaration ';' + ]* + | ProcedureHeading ';' + ; ProgramModule -{ - struct idf *id; -} -: - MODULE - identifier(&id) { if (! id->id_type) { - id->id_type = state; - } - else if (id->id_type != DEFINITION || - state != IMPLEMENTATION) { - error("multiple declaration for module %s", - id->id_text); - } - if (! id->id_dir) { - id->id_dir = WorkingDir; - } - else if (strcmp(id->id_dir, WorkingDir)) { - Gerror("definition and implementation of module %s reside in different directories", id->id_text); - } - CurrentArg->a_idf = id; - } - priority - ';' import(&(id->id_modimports))* - block IDENT - '.' -; - -Module: - DEFINITION - { fatal("Definition module in .mod file"); } -| %default - [ - IMPLEMENTATION { state = IMPLEMENTATION; } - | - /* empty */ { state = PROGRAM; } - ] - ProgramModule -; - -CompilationUnit: - Module -; - -identifier(struct idf **id;): - IDENT - { extern char idfbuf[]; - *id = str2idf(idfbuf, 1); - } -; + { + struct idf* id; + } + : MODULE + identifier(&id) + { + if (!id->id_type) + { + id->id_type = state; + } + else if (id->id_type != DEFINITION || state != IMPLEMENTATION) + { + error("multiple declaration for module %s", id->id_text); + } + if (!id->id_dir) + { + id->id_dir = WorkingDir; + } + else if (strcmp(id->id_dir, WorkingDir)) + { + Gerror("definition and implementation of module %s reside in different directories", + id->id_text); + } + CurrentArg->a_idf = id; + } + priority ';' + import(&(id->id_modimports))* + block IDENT '.' + ; + +Module + : DEFINITION + { fatal("Definition module in .mod file"); } + | %default + [ + IMPLEMENTATION + { state = IMPLEMENTATION; } + | + /* empty */ + { state = PROGRAM; } + ] + ProgramModule + ; + +CompilationUnit + : Module + ; + +identifier(struct idf** id;) + : IDENT + { + extern char idfbuf[]; + *id = str2idf(idfbuf, 1); + } + ; diff --git a/lang/m2/m2mm/statement.g b/lang/m2/m2mm/statement.g index bbdfd7a50..79ab21d14 100644 --- a/lang/m2/m2mm/statement.g +++ b/lang/m2/m2mm/statement.g @@ -5,6 +5,12 @@ * Author: Ceriel J.H. Jacobs */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/m2/m2mm/statement.g + */ + /* S T A T E M E N T S */ /* stripped down version from the one in the Modula-2 compiler */ @@ -12,126 +18,106 @@ /* $Id$ */ { -#include "idf.h" -#include "LLlex.h" + #include "idf.h" + #include "LLlex.h" -static int loopcount; + static int loopcount; } -statement : -[ - /* - * This part is not in the reference grammar. The reference grammar - * states : assignment | ProcedureCall | ... - * but this gives LL(1) conflicts - */ - designator - [ - ActualParameters? - | - [ BECOMES - | %erroneous - '=' { error("':=' expected instead of '='"); - DOT = BECOMES; - } - ] - expression - ] - /* - * end of changed part - */ -| - IfStatement -| - CaseStatement -| - WHILE - expression - DO - StatementSequence - END -| - REPEAT - StatementSequence - UNTIL - expression -| - { loopcount++; } - LOOP - StatementSequence - END - { loopcount--; } -| - ForStatement -| - WithStatement -| - EXIT - { if (!loopcount) error("EXIT not in a LOOP"); } -| - ReturnStatement -| - /* empty */ -] -; +statement + : [ + /* + * This part is not in the reference grammar. The reference grammar + * states : assignment | ProcedureCall | ... + * but this gives LL(1) conflicts + */ + designator + [ + ActualParameters? + | [ + BECOMES + | %erroneous '=' + { + error("':=' expected instead of '='"); + DOT = BECOMES; + } + ] + expression + ] + /* + * end of changed part + */ + | IfStatement + | CaseStatement + | WHILE expression DO StatementSequence END + | REPEAT StatementSequence UNTIL expression + | + { loopcount++; } + LOOP StatementSequence END + { loopcount--; } + | ForStatement + | WithStatement + | EXIT + { if (!loopcount) error("EXIT not in a LOOP"); } + | ReturnStatement + | + /* empty */ + ] + ; -StatementSequence : - statement - [ %persistent - ';' - statement - ]* -; +StatementSequence + : statement + [ + %persistent + ';' statement + ]* + ; -IfStatement : - IF expression - THEN StatementSequence - [ - ELSIF expression - THEN StatementSequence - ]* - [ - ELSE StatementSequence - ]? - END -; +IfStatement + : IF expression THEN StatementSequence + [ + ELSIF expression THEN StatementSequence + ]* + [ + ELSE StatementSequence + ]? + END + ; -CaseStatement : - CASE expression - OF case - [ - '|' case - ]* - [ ELSE StatementSequence - ]? - END -; +CaseStatement + : CASE expression OF case + [ + '|' case + ]* + [ + ELSE StatementSequence + ]? + END + ; -case : - [ CaseLabelList ':' - StatementSequence - ]? -; +case + : [ + CaseLabelList ':' StatementSequence + ]? + ; -ForStatement : - FOR IDENT BECOMES expression TO expression - [ - BY ConstExpression - | - ] - DO StatementSequence - END -; +ForStatement + : FOR IDENT BECOMES expression TO expression + [ + BY ConstExpression + | + ] + DO StatementSequence END + ; -WithStatement : - WITH designator DO StatementSequence - END -; +WithStatement + : WITH designator DO StatementSequence END + ; -ReturnStatement : - RETURN - [ - expression - | - ] -; +ReturnStatement + : RETURN + [ + expression + | + ] + ; diff --git a/lang/occam/comp/occam.g b/lang/occam/comp/occam.g index cf4f6d7a7..bf5191648 100644 --- a/lang/occam/comp/occam.g +++ b/lang/occam/comp/occam.g @@ -3,751 +3,1011 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ -/* OCCAM */ -{ -#include -#include "token.h" -#include "symtab.h" -#include "expr.h" -#include "code.h" -#include "sizes.h" -#include -#include - -#define MAXERRORS 10 /* Maximum number of insert/delete errors */ - -static void nonconst(), nonpositive(), rep_cleanup(), check_assoc(); -void init_builtins(); -char *strcpy(); - -extern int lineno, LLsymb; -union type_info info, none; -} -%token AFTER, ALLOCATE, ALT, AND, ANY, BYTE, CHAN, DEF, FALSE, FOR, IF, LOAD; -%token NOT, NOW, OR, PAR, PLACED, PORT, PRI, PROC, SEQ, SKIP, TABLE, TRUE; -%token VALUE, VAR, WAIT, WHILE; -%token IDENTIFIER, NUMBER, CHAR_CONST, STRING; -%token AS, LE, GE, NE, LS, RS, BA, BO, BX, BS; - -%start occam, program; - -program : { init_builtins(); - header(); - } - process - ; - -process : primitive - | construct - | { sym_down(); } - declaration ':' process - { sym_up(); } - ; - -primitive { struct expr *e; } : - statement(&e) { if (!valueless(e)) - report("primitive may not have a value"); - code_void(e); - destroy(e); - } - | WAIT val_expr(&e) { int BEGIN=0, END=0, TEST=0; - check_wait(e); - no_deadlock(); - branch(&TEST); - Label(new_label(&BEGIN)); - resumenext(); - Label(TEST); - code_bool(e, positive, &END, &BEGIN); - Label(END); - destroy(e); - } - | SKIP - ; - -guard(*F;) { struct expr *e1, *e2; - register full_guard=0; - int T=0; - static char EXPECT_INP[]="input process expected as guard"; - } : - expression(&e1) - [ '&' { full_guard=1; - if (!valued(e1)) - report("boolean part of guard has no value"); - code_bool(e1, positive, &T, F); - Label(T); - } - [ statement(&e2) - { if (!input_process(e2)) - report(EXPECT_INP); - code_any(e2, F); - destroy(e2); - } - | WAIT val_expr(&e2) - { check_wait(e2); - code_bool(e2, positive, &T, F); - Label(T); - destroy(e2); - } - | SKIP - ] - ]? - { if (!full_guard) { - if (!input_process(e1)) - report(EXPECT_INP); - code_any(e1, F); - } - destroy(e1); - } - | WAIT val_expr(&e1) - { check_wait(e1); - code_bool(e1, positive, &T, F); - Label(T); - destroy(e1); - } - | SKIP - ; - -guarded_process(*END;) { struct symbol *v; - struct expr *e1, *e2; - struct replicator to_test; - register line, oind; - int F=0; - } : - guard(&F) process { branch(END); - Label(F); - } - | ALT { line=lineno; oind=ind; } - [ %if (line==lineno) - replicator(&v, &e1, &e2) - { rep_init(v, e1, e2, &to_test); } - guarded_process(END) - { rep_test(v, e1, e2, &to_test); - rep_cleanup(e1, e2); - } - | - [ %while (tabulated(oind, ind)) guarded_process(END) ]* - ] - ; - -conditional(*END; ) { struct symbol *v; - struct expr *e1, *e2; - struct replicator to_test; - register line, oind; - int T=0, F=0; - } : - val_expr(&e1) { if (!valued(e1)) - report("conditional needs valued expression"); - code_bool(e1, positive, &T, &F); - Label(T); - destroy(e1); - } - process - { branch(END); - Label(F); - } - | IF { line=lineno; oind=ind; } - [ %if (line==lineno) - replicator(&v, &e1, &e2) - { rep_init(v, e1, e2, &to_test); } - conditional(END) - { rep_test(v, e1, e2, &to_test); - rep_cleanup(e1, e2); - } - | - [ %while (tabulated(oind, ind)) conditional(END) ]* - ] - ; - -replicator(struct symbol **s; register struct expr **e1; register struct expr **e2; ) - { register char *index; }: - IDENTIFIER { index=token.t_sval; } - '=' '[' val_expr(e1) FOR val_expr(e2) ']' - { if (!valued(*e1) || !valued(*e2)) - report("replicator needs valued expressions"); - sym_down(); - var_memory(&info, T_VAR, 1); - *s=insert(index, - T_VAR|T_REP|T_USED|T_ASSIGNED, 1, &info); - } - ; - -construct { struct symbol *v; - struct expr *e1, *e2; - struct replicator to_test; - register line, oind; - int BEGIN=0, END=0, NONZERO; - }: - SEQ { line=lineno; oind=ind; } - [ %if (line==lineno) - replicator(&v, &e1, &e2) - { rep_init(v, e1, e2, &to_test); } - process - { rep_test(v, e1, e2, &to_test); - rep_cleanup(e1, e2); - } - | - [ %while (tabulated(oind, ind)) process ]* - ] - | PRI ? - [ PAR { line=lineno; oind=ind; - par_begin(); - } - [ %if (line==lineno) - replicator(&v, &e1, &e2) - { rep_init(v, e1, e2, &to_test); - NONZERO=0; - par_fork(&NONZERO); - } - process - { branch(&END); - Label(NONZERO); - rep_test(v, e1, e2, &to_test); - rep_cleanup(e1, e2); - } - | - [ %while (tabulated(oind, ind)) - { NONZERO=0; - par_fork(&NONZERO); - } - process - { branch(&END); - Label(NONZERO); - } - ]* - ] - { Label(END); - par_end(); - } - | ALT { line=lineno; oind=ind; - no_deadlock(); - Label(new_label(&BEGIN)); - } - [ %if (line==lineno) - replicator(&v, &e1, &e2) - { rep_init(v, e1, e2, &to_test); } - guarded_process(&END) - { rep_test(v, e1, e2, &to_test); - rep_cleanup(e1, e2); - } - | - [ %while (tabulated(oind, ind)) guarded_process(&END) - ]* - ] - { resumenext(); - branch(&BEGIN); - Label(END); - } - ] - | IF { line=lineno; oind=ind; } - [ %if (line==lineno) - replicator(&v, &e1, &e2) - { rep_init(v, e1, e2, &to_test); } - conditional(&END) - { rep_test(v, e1, e2, &to_test); - rep_cleanup(e1, e2); - } - | - [ %while (tabulated(oind, ind)) conditional(&END) ]* - ] - { Label(END); } - | WHILE val_expr(&e1) { if (!valued(e1)) - report("WHILE needs valued expression"); - branch(&END); - Label(new_label(&BEGIN)); - } - process - { int DONE=0; - Label(END); - code_bool(e1, negative, &DONE, &BEGIN); - Label(DONE); - destroy(e1); - } - ; - -subscript(*byte; register struct expr **e; ) - { struct expr *e1; - register slice=0, err=0; - } : - '[' { *byte=0; } - [ BYTE { *byte=T_BYTE; } - ]? - val_expr(e) { if (!valued(*e)) - err++; - } - [ FOR expression(&e1) - { static char siz[]="slize size"; - if (!constant(e1)) { - if (!err) - nonconst(siz); - destroy(e1); - e1=new_const(0L); - } else - if (e1->u.cst<=0) - nonpositive(siz); - *e=new_node(FOR, *e, e1, *byte); - slice=1; - } - ]? - ']' - { if (err) - report(slice ? - "slice must be '[' value FOR constant ']'" : - "subscript needs valued expression"); - } - ; - -chan { register type, arr_siz=1; register char *name; struct expr *e; }: - IDENTIFIER { type=T_CHAN; - name=token.t_sval; - } - [ '[' expression(&e) ']' - { static char siz[]="channel array size"; - if (!constant(e)) - nonconst(siz); - else - if (e->u.cst<0) - nonpositive(siz); - else - arr_siz=e->u.cst; - destroy(e); - type|=T_ARR; - } - ]? - { chan_memory(&info, arr_siz); - chan_init(&info, arr_siz); - insert(name, type, arr_siz, &info); - } - ; - -var { register type, byte=0, arr_siz=1; - register char *name; - struct expr *e; - }: - IDENTIFIER { type=T_VAR; name=token.t_sval; } - [ '[' - [ BYTE { byte=T_BYTE; } - ]? - expression(&e) ']' - { static char siz[]="variable array size"; - if (!constant(e)) - nonconst(siz); - else - if (e->u.cst<=0) - nonpositive(siz); - else - arr_siz=e->u.cst; - destroy(e); - type|=T_ARR|byte; - } - ]? - { var_memory(&info, type, arr_siz); - insert(name, type, arr_siz, &info); - } - ; - -const_def { register char *name; struct expr *e; }: - IDENTIFIER { name=token.t_sval; } - '=' expression(&e) - { if (!constant(e) && !arr_constant(e)) - nonconst("expression in constant definition"); - info.t_const=e; - insert(name, T_CONST|T_USED, 0, &info); - } - ; - -form_parm(struct par_list ***aapars; register *g_type;) - { register char *name; - register type= *g_type; - }: - [ VAR { type=T_VAR|T_ASSIGNED|T_USED; } - | CHAN { type=T_CHAN; } - | VALUE { type=T_VALUE|T_ASSIGNED; } - ]? - IDENTIFIER { - if (type<0) { - report("VAR, CHAN or VALUE expected"); - type=T_VAR; - } - name=token.t_sval; - *g_type=type; - } - [ '[' ']' - { type|=T_ARR; } - ]? - { pars_add(aapars, type&(T_TYPE|T_ARR), - insert(name, type|T_PARAM, 0, &none)); - } - ; - -form_parms(struct par_list **apars;) { int type= -1; }: - '(' form_parm(&apars, &type) - [ ',' form_parm(&apars, &type) - ]* - ')' - ; - -declaration: - VAR - var [ ',' var ]* - | CHAN - chan [ ',' chan ]* - | DEF - const_def [ ',' const_def ]* - | proc_declaration - ; - -proc_declaration { struct par_list *pars=nil; - register struct symbol *proc; - int OVER=0; - register old_min_offset; - }: - PROC IDENTIFIER { branch(&OVER); - proc=insert(token.t_sval, - T_PROC|T_RECURS, 0, &none); - old_min_offset=min_offset; - sym_down(); - prologue(proc); - } - form_parms(&pars) ? { form_offsets(pars); - proc->s_info.proc.pars=pars; - } - '=' process { epilogue(proc); - sym_up(); - proc->s_type&= ~T_RECURS; - min_offset=old_min_offset; - Label(OVER); - } - ; - -vector_constant(struct expr **e;) - { struct table *pt=nil, **apt= &pt; - register Tlen=0; - }: - table(e) - | STRING { register char *ps= token.t_sval; - register len; - - Tlen+= len= (*ps++ & 0377); - while (--len>=0) - table_add(&apt, (long) *ps++); - } - [ %while (1) STRING - { register char *ps= token.t_sval; - register len; - - Tlen+= len= (*ps++ & 0377); - while (--len>=0) - table_add(&apt, (long) *ps++); - } - ]* - { apt= &pt; - table_add(&apt, (long) Tlen); - *e=new_table(E_BTAB, pt); - } - ; - -item(struct expr **e;) - { struct expr *e1; - register struct symbol *var; - struct par_list *pars=nil; - register line, oind; - int byte, err=0, subs_call=0; - struct expr_list *elp=nil, **aelp= &elp; - }: - IDENTIFIER { line=lineno; - oind=ind; - var=searchall(token.t_sval); - - if (var_constant(var)) - *e=copy_const(var->s_info.t_const); - else { - if (var_proc(var)) - pars=var->s_info.proc.pars; - *e=new_var(var); - } - } - [ %while (line==lineno || tabulated(oind, ind)) - [ subscript(&byte, &e1) - { *e=new_node('[', *e, e1, byte); } - | '(' { if (!var_declared(var)) { - var->s_type=T_PROC|T_USED|T_NOTDECL; - var->s_info.proc.pars=nil; - err=1; - } - if (!var_proc(var)) { - report("%s is not a named process", - var->s_name); - err=1; - } - } - expression(&e1) - { check_param(&pars, e1, &err); - expr_list_add(&aelp, e1); - } - [ ',' expression(&e1) - { check_param(&pars, e1, &err); - expr_list_add(&aelp, e1); - } - ]* - { - if (pars!=nil) - report("too few actual parameters"); - } - ')' - { *e=new_call(*e, elp); } - ] - { subs_call=1; } - ]? - { if (!subs_call && var_proc(var)) { - if (pars!=nil) - report("no actual parameters"); - *e=new_call(*e, (char *)nil); - } - } - | vector_constant(e) - [ subscript(&byte, &e1) - { *e=new_node('[', *e, e1, byte); } - ]? - ; - -statement(struct expr **e;) - { struct expr *e1; - struct expr_list *elp=nil, **aelp= &elp; - register out; - }: - item(e) - [ AS expression(&e1) - { *e=new_node(AS, *e, e1, 0); } - | [ - '?' { out=0; } - | '!' { out=1; } - ] - io_arg(&e1) - { if (e1!=nil) check_io(out, e1); - expr_list_add(&aelp, e1); - } - [ %while (1) ';' io_arg(&e1) - { if (e1!=nil) check_io(out, e1); - expr_list_add(&aelp, e1); - } - ]* - { *e=new_io(out, *e, elp); } - ]? - ; - -io_arg(struct expr **e; ) : - expression(e) - | ANY { *e=nil; } - ; - -table(struct expr **e;) - { struct table *pt=nil, **apt= &pt; - struct expr *e1; - register type; - }: - TABLE '[' { type=E_TABLE; } - [ BYTE { type=E_BTAB; } - ]? - expression(&e1) { if (!constant(e1)) - nonconst("table element"); - else - table_add(&apt, e1->u.cst); - destroy(e1); - } - [ ',' expression(&e1) - { if (!constant(e1)) - nonconst("table element"); - else - table_add(&apt, e1->u.cst); - destroy(e1); - } - ]* - { *e=new_table(type, pt); } - ']' - ; - -arithmetic_op: '+' | '-' | '*' | '/' | BS - ; - -comparison_op: '<' | '>' | LE | GE | NE | '=' | AFTER - ; - -logical_op: BA | BO | BX - ; - -boolean_op: AND | OR - ; - -shift_op: LS | RS - ; - -monadic_op(*op;): - '-' { *op='~'; } - | NOT { *op=NOT; } - ; - -operator: arithmetic_op | comparison_op | logical_op | boolean_op | shift_op - ; - -element(struct expr **e;) : - %default NUMBER { *e=new_const(token.t_lval); } - | statement(e) - | TRUE { *e=new_const(-1L); } - | FALSE { *e=new_const(0L); } - | NOW { *e=new_now(); } - | CHAR_CONST { *e=new_const(token.t_lval); } - | '(' expression(e) ')' { if (valueless(*e)) - warning("primitive should not be parenthesized"); - } - ; - -expression(struct expr **e;) - { int op=0; - struct expr *e1; - }: - element(e) - [ %while (1) { if (op!=0) check_assoc(op, LLsymb); - op=LLsymb; - } - operator element(&e1) - { *e=new_node(op, *e, e1, 0); } - ]* - | monadic_op(&op) element(&e1) - { *e=new_node(op, e1, (char *)nil, 0); } - ; - -val_expr(struct expr **e;) : - expression(e) { used(*e); } - ; - -%lexical scanner; -{ -int err=0; - -main(argc, argv) register argc; register char **argv; -{ - while (argc > 1 && argv[1][0] == '-') { - do_option(&argv[1][1]); - argc--; - argv++; - } - - leader(); - occam(); - trailer(); - - exit(err); -} - -do_option(text) - char *text; -{ - extern int Lflag; - - switch(*text++) { - - default: - fatal("illegal option: %c", *--text); - - case 'L' : /* no fil/lin */ - Lflag++; - break; - case 'V' : /* set object sizes and alignment requirements */ - { - arith size, align; - char c; - - while (c = *text++) { - size = txt2int(&text); - switch (c) { - case 'w': /* word */ - if (size != (arith)0) - wz = size; - break; - case 'p': /* pointer */ - if (size != (arith)0) - pz = size; - break; - case 'l': /* long */ - if (size != (arith)0) - vz = size; - break; - default: - fatal("-V: bad type indicator %c\n", c); - } - } - break; - } - } -} - -int -txt2int(tp) - char **tp; -{ - /* the integer pointed to by *tp is read, while increasing - *tp; the resulting value is yielded. - */ - register int val = 0, ch; - - while (ch = **tp, ch >= '0' && ch <= '9') { - val = val * 10 + ch - '0'; - (*tp)++; - } - return val; -} -LLmessage(tk) register tk; +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/occam/comp/occam.g + */ +/* OCCAM */ { - static errors=0; - - if (tk>0) { - repeat_token(LLsymb); - warning("syntax error: %s expected (inserted)", tokenname(tk, 1)); - } else - if (tk==0) - warning("syntax error: bad token %s (deleted)", tokenname(LLsymb, 0)); - else { /* tk<0 */ - warning("syntax error: garbage at end of program"); - } - if (++errors==MAXERRORS) { - fprintf(stderr, "Too many insert/delete errors. Compiler ends.\n"); - err=1; trailer(); exit(1); - } + #include + #include "token.h" + #include "symtab.h" + #include "expr.h" + #include "code.h" + #include "sizes.h" + #include + #include + + #define MAXERRORS 10 /* Maximum number of insert/delete errors */ + + static void nonconst(), nonpositive(), rep_cleanup(), check_assoc(); + void init_builtins(); + char* strcpy(); + + extern int lineno, LLsymb; + union type_info info, none; } -static void nonconst(siz) char *siz; -{ - report("%s should be a constant", siz); -} +%token AFTER, ALLOCATE, ALT, AND, ANY, BYTE, CHAN, DEF, FALSE, FOR, IF, LOAD; +%token NOT, NOW, OR, PAR, PLACED, PORT, PRI, PROC, SEQ, SKIP, TABLE, TRUE; +%token VALUE, VAR, WAIT, WHILE; +%token IDENTIFIER, NUMBER, CHAR_CONST, STRING; +%token AS, LE, GE, NE, LS, RS, BA, BO, BX, BS; +%start occam, program; + +program + : + { + init_builtins(); + header(); + } + process + ; + +process + : primitive + | construct + | + { sym_down(); } + declaration ':' process + { sym_up(); } + ; + +primitive + { + struct expr* e; + } + : statement(&e) + { + if (!valueless(e)) + report("primitive may not have a value"); + code_void(e); + destroy(e); + } + | WAIT + val_expr(&e) + { + int BEGIN = 0, END = 0, TEST = 0; + check_wait(e); + no_deadlock(); + branch(&TEST); + Label(new_label(&BEGIN)); + resumenext(); + Label(TEST); + code_bool(e, positive, &END, &BEGIN); + Label(END); + destroy(e); + } + | SKIP + ; + +guard(*F;) + { + struct expr *e1, *e2; + register full_guard = 0; + int T = 0; + static char EXPECT_INP[] = "input process expected as guard"; + } + : expression(&e1) + [ + '&' + { + full_guard = 1; + if (!valued(e1)) + report("boolean part of guard has no value"); + code_bool(e1, positive, &T, F); + Label(T); + } + [ + statement(&e2) + { + if (!input_process(e2)) + report(EXPECT_INP); + code_any(e2, F); + destroy(e2); + } + | WAIT + val_expr(&e2) + { + check_wait(e2); + code_bool(e2, positive, &T, F); + Label(T); + destroy(e2); + } + | SKIP + ] + ]? + { + if (!full_guard) + { + if (!input_process(e1)) + report(EXPECT_INP); + code_any(e1, F); + } + destroy(e1); + } + | WAIT + val_expr(&e1) + { + check_wait(e1); + code_bool(e1, positive, &T, F); + Label(T); + destroy(e1); + } + | SKIP + ; + +guarded_process(*END;) + { + struct symbol* v; + struct expr *e1, *e2; + struct replicator to_test; + register line, oind; + int F = 0; + } + : guard(&F) + process + { + branch(END); + Label(F); + } + | ALT + { + line = lineno; + oind = ind; + } + [ + %if (line == lineno) + replicator(&v, &e1, &e2) + { rep_init(v, e1, e2, &to_test); } + guarded_process(END) + { + rep_test(v, e1, e2, &to_test); + rep_cleanup(e1, e2); + } + | [ + %while (tabulated(oind, ind)) + guarded_process(END) + ]* + ] + ; + +conditional(*END;) + { + struct symbol* v; + struct expr *e1, *e2; + struct replicator to_test; + register line, oind; + int T = 0, F = 0; + } + : val_expr(&e1) + { + if (!valued(e1)) + report("conditional needs valued expression"); + code_bool(e1, positive, &T, &F); + Label(T); + destroy(e1); + } + process + { + branch(END); + Label(F); + } + | IF + { + line = lineno; + oind = ind; + } + [ + %if (line == lineno) + replicator(&v, &e1, &e2) + { rep_init(v, e1, e2, &to_test); } + conditional(END) + { + rep_test(v, e1, e2, &to_test); + rep_cleanup(e1, e2); + } + | [ + %while (tabulated(oind, ind)) + conditional(END) + ]* + ] + ; + +replicator(struct symbol** s; register struct expr** e1; register struct expr** e2;) + { + register char* index; + } + : IDENTIFIER + { index = token.t_sval; } + '=' '[' + val_expr(e1) + FOR + val_expr(e2) + ']' + { + if (!valued(*e1) || !valued(*e2)) + report("replicator needs valued expressions"); + sym_down(); + var_memory(&info, T_VAR, 1); + *s = insert(index, T_VAR | T_REP | T_USED | T_ASSIGNED, 1, &info); + } + ; + +construct + { + struct symbol* v; + struct expr *e1, *e2; + struct replicator to_test; + register line, oind; + int BEGIN = 0, END = 0, NONZERO; + } + : SEQ + { + line = lineno; + oind = ind; + } + [ + %if (line == lineno) + replicator(&v, &e1, &e2) + { rep_init(v, e1, e2, &to_test); } + process + { + rep_test(v, e1, e2, &to_test); + rep_cleanup(e1, e2); + } + | [ + %while (tabulated(oind, ind)) + process + ]* + ] + | PRI? + [ + PAR + { + line = lineno; + oind = ind; + par_begin(); + } + [ + %if (line == lineno) + replicator(&v, &e1, &e2) + { + rep_init(v, e1, e2, &to_test); + NONZERO = 0; + par_fork(&NONZERO); + } + process + { + branch(&END); + Label(NONZERO); + rep_test(v, e1, e2, &to_test); + rep_cleanup(e1, e2); + } + | [ + %while (tabulated(oind, ind)) + { + NONZERO = 0; + par_fork(&NONZERO); + } + process + { + branch(&END); + Label(NONZERO); + } + ]* + ] + { + Label(END); + par_end(); + } + | ALT + { + line = lineno; + oind = ind; + no_deadlock(); + Label(new_label(&BEGIN)); + } + [ + %if (line == lineno) + replicator(&v, &e1, &e2) + { rep_init(v, e1, e2, &to_test); } + guarded_process(&END) + { + rep_test(v, e1, e2, &to_test); + rep_cleanup(e1, e2); + } + | [ + %while (tabulated(oind, ind)) + guarded_process(&END) + ]* + ] + { + resumenext(); + branch(&BEGIN); + Label(END); + } + ] + | IF + { + line = lineno; + oind = ind; + } + [ + %if (line == lineno) + replicator(&v, &e1, &e2) + { rep_init(v, e1, e2, &to_test); } + conditional(&END) + { + rep_test(v, e1, e2, &to_test); + rep_cleanup(e1, e2); + } + | [ + %while (tabulated(oind, ind)) + conditional(&END) + ]* + ] + { Label(END); } + | WHILE + val_expr(&e1) + { + if (!valued(e1)) + report("WHILE needs valued expression"); + branch(&END); + Label(new_label(&BEGIN)); + } + process + { + int DONE = 0; + Label(END); + code_bool(e1, negative, &DONE, &BEGIN); + Label(DONE); + destroy(e1); + } + ; + +subscript(*byte; register struct expr** e;) + { + struct expr* e1; + register slice = 0, err = 0; + } + : '[' + { *byte = 0; } + [ + BYTE + { *byte = T_BYTE; } + ]? + val_expr(e) + { if (!valued(*e)) err++; } + [ + FOR + expression(&e1) + { + static char siz[] = "slize size"; + if (!constant(e1)) + { + if (!err) + nonconst(siz); + destroy(e1); + e1 = new_const(0L); + } + else if (e1->u.cst <= 0) + nonpositive(siz); + *e = new_node(FOR, *e, e1, *byte); + slice = 1; + } + ]? + ']' + { + if (err) + report(slice ? "slice must be '[' value FOR constant ']'" + : "subscript needs valued expression"); + } + ; + +chan + { + register type, arr_siz = 1; + register char* name; + struct expr* e; + } + : IDENTIFIER + { + type = T_CHAN; + name = token.t_sval; + } + [ + '[' + expression(&e) + ']' + { + static char siz[] = "channel array size"; + if (!constant(e)) + nonconst(siz); + else if (e->u.cst < 0) + nonpositive(siz); + else + arr_siz = e->u.cst; + destroy(e); + type |= T_ARR; + } + ]? + { + chan_memory(&info, arr_siz); + chan_init(&info, arr_siz); + insert(name, type, arr_siz, &info); + } + ; + +var + { + register type, byte = 0, arr_siz = 1; + register char* name; + struct expr* e; + } + : IDENTIFIER + { + type = T_VAR; + name = token.t_sval; + } + [ + '[' + [ + BYTE + { byte = T_BYTE; } + ]? + expression(&e) + ']' + { + static char siz[] = "variable array size"; + if (!constant(e)) + nonconst(siz); + else if (e->u.cst <= 0) + nonpositive(siz); + else + arr_siz = e->u.cst; + destroy(e); + type |= T_ARR | byte; + } + ]? + { + var_memory(&info, type, arr_siz); + insert(name, type, arr_siz, &info); + } + ; + +const_def + { + register char* name; + struct expr* e; + } + : IDENTIFIER + { name = token.t_sval; } + '=' + expression(&e) + { + if (!constant(e) && !arr_constant(e)) + nonconst("expression in constant definition"); + info.t_const = e; + insert(name, T_CONST | T_USED, 0, &info); + } + ; + +form_parm(struct par_list*** aapars; register* g_type;) + { + register char* name; + register type = *g_type; + } + : [ + VAR + { type = T_VAR | T_ASSIGNED | T_USED; } + | CHAN + { type = T_CHAN; } + | VALUE + { type = T_VALUE | T_ASSIGNED; } + ]? + IDENTIFIER + { + if (type < 0) + { + report("VAR, CHAN or VALUE expected"); + type = T_VAR; + } + name = token.t_sval; + *g_type = type; + } + [ + '[' ']' + { type |= T_ARR; } + ]? + { pars_add(aapars, type & (T_TYPE | T_ARR), insert(name, type | T_PARAM, 0, &none)); } + ; + +form_parms(struct par_list** apars;) + { + int type = -1; + } + : '(' + form_parm(&apars, &type) + [ + ',' + form_parm(&apars, &type) + ]* + ')' + ; + +declaration + : VAR var + [ + ',' var + ]* + | CHAN chan + [ + ',' chan + ]* + | DEF const_def + [ + ',' const_def + ]* + | proc_declaration + ; + +proc_declaration + { + struct par_list* pars = nil; + register struct symbol* proc; + int OVER = 0; + register old_min_offset; + } + : PROC IDENTIFIER + { + branch(&OVER); + proc = insert(token.t_sval, T_PROC | T_RECURS, 0, &none); + old_min_offset = min_offset; + sym_down(); + prologue(proc); + } + form_parms(&pars)? + { + form_offsets(pars); + proc->s_info.proc.pars = pars; + } + '=' process + { + epilogue(proc); + sym_up(); + proc->s_type &= ~T_RECURS; + min_offset = old_min_offset; + Label(OVER); + } + ; + +vector_constant(struct expr** e;) + { + struct table *pt = nil, **apt = &pt; + register Tlen = 0; + } + : table(e) + | STRING + { + register char* ps = token.t_sval; + register len; + + Tlen += len = (*ps++ & 0377); + while (--len >= 0) + table_add(&apt, (long)*ps++); + } + [ + %while (1) + STRING + { + register char* ps = token.t_sval; + register len; + + Tlen += len = (*ps++ & 0377); + while (--len >= 0) + table_add(&apt, (long)*ps++); + } + ]* + { + apt = &pt; + table_add(&apt, (long)Tlen); + *e = new_table(E_BTAB, pt); + } + ; + +item(struct expr** e;) + { + struct expr* e1; + register struct symbol* var; + struct par_list* pars = nil; + register line, oind; + int byte, err = 0, subs_call = 0; + struct expr_list *elp = nil, **aelp = &elp; + } + : IDENTIFIER + { + line = lineno; + oind = ind; + var = searchall(token.t_sval); + + if (var_constant(var)) + *e = copy_const(var->s_info.t_const); + else + { + if (var_proc(var)) + pars = var->s_info.proc.pars; + *e = new_var(var); + } + } + [ + %while (line == lineno || tabulated(oind, ind)) + [ + subscript(&byte, &e1) + { *e = new_node('[', *e, e1, byte); } + | '(' + { + if (!var_declared(var)) + { + var->s_type = T_PROC | T_USED | T_NOTDECL; + var->s_info.proc.pars = nil; + err = 1; + } + if (!var_proc(var)) + { + report("%s is not a named process", var->s_name); + err = 1; + } + } + expression(&e1) + { + check_param(&pars, e1, &err); + expr_list_add(&aelp, e1); + } + [ + ',' + expression(&e1) + { + check_param(&pars, e1, &err); + expr_list_add(&aelp, e1); + } + ]* + { if (pars != nil) report("too few actual parameters"); } + ')' + { *e = new_call(*e, elp); } + ] + { subs_call = 1; } + ]? + { + if (!subs_call && var_proc(var)) + { + if (pars != nil) + report("no actual parameters"); + *e = new_call(*e, (char*)nil); + } + } + | vector_constant(e) + [ + subscript(&byte, &e1) + { *e = new_node('[', *e, e1, byte); } + ]? + ; + +statement(struct expr** e;) + { + struct expr* e1; + struct expr_list *elp = nil, **aelp = &elp; + register out; + } + : item(e) + [ + AS + expression(&e1) + { *e = new_node(AS, *e, e1, 0); } + | [ + '?' + { out = 0; } + | '!' + { out = 1; } + ] + io_arg(&e1) + { + if (e1 != nil) + check_io(out, e1); + expr_list_add(&aelp, e1); + } + [ + %while (1) + ';' + io_arg(&e1) + { + if (e1 != nil) + check_io(out, e1); + expr_list_add(&aelp, e1); + } + ]* + { *e = new_io(out, *e, elp); } + ]? + ; + +io_arg(struct expr** e;) + : expression(e) + | ANY + { *e = nil; } + ; + +table(struct expr** e;) + { + struct table *pt = nil, **apt = &pt; + struct expr* e1; + register type; + } + : TABLE '[' + { type = E_TABLE; } + [ + BYTE + { type = E_BTAB; } + ]? + expression(&e1) + { + if (!constant(e1)) + nonconst("table element"); + else + table_add(&apt, e1->u.cst); + destroy(e1); + } + [ + ',' + expression(&e1) + { + if (!constant(e1)) + nonconst("table element"); + else + table_add(&apt, e1->u.cst); + destroy(e1); + } + ]* + { *e = new_table(type, pt); } + ']' + ; + +arithmetic_op + : '+' + | '-' + | '*' + | '/' + | BS + ; + +comparison_op + : '<' + | '>' + | LE + | GE + | NE + | '=' + | AFTER + ; + +logical_op + : BA + | BO + | BX + ; + +boolean_op + : AND + | OR + ; + +shift_op + : LS + | RS + ; + +monadic_op(*op;) + : '-' + { *op = '~'; } + | NOT + { *op = NOT; } + ; + +operator + : arithmetic_op + | comparison_op + | logical_op + | boolean_op + | shift_op + ; + +element(struct expr** e;) + : %default + NUMBER + { *e = new_const(token.t_lval); } + | statement(e) + | TRUE + { *e = new_const(-1L); } + | FALSE + { *e = new_const(0L); } + | NOW + { *e = new_now(); } + | CHAR_CONST + { *e = new_const(token.t_lval); } + | '(' + expression(e) + ')' + { if (valueless(*e)) warning("primitive should not be parenthesized"); } + ; + +expression(struct expr** e;) + { + int op = 0; + struct expr* e1; + } + : element(e) + [ + %while (1) + { + if (op != 0) + check_assoc(op, LLsymb); + op = LLsymb; + } + operator + element(&e1) + { *e = new_node(op, *e, e1, 0); } + ]* + | monadic_op(&op) + element(&e1) + { *e = new_node(op, e1, (char*)nil, 0); } + ; + +val_expr(struct expr** e;) + : expression(e) + { used(*e); } + ; -static void nonpositive(siz) char *siz; -{ - report("%s must be positive", siz); -} - -static void rep_cleanup(e1, e2) struct expr *e1, *e2; -{ - destroy(e1); - destroy(e2); - sym_up(); -} +%lexical scanner; -static void check_assoc(prev_op, op) register prev_op, op; { - switch (op) { - char prev[5]; - case '+': case '*': - case AND: case OR: - case BA: case BO: case BX: - if (prev_op==op) break; - default: - strcpy(prev, tokenname(prev_op, 0)); - - warning("Operators %s and %s don't associate", - prev, tokenname(op, 0) - ); - } -} - + int err = 0; + + main(argc, argv) register argc; + register char** argv; + { + while (argc > 1 && argv[1][0] == '-') + { + do_option(&argv[1][1]); + argc--; + argv++; + } + + leader(); + occam(); + trailer(); + + exit(err); + } + + do_option(text) char* text; + { + extern int Lflag; + + switch (*text++) + { + + default: + fatal("illegal option: %c", *--text); + + case 'L': /* no fil/lin */ + Lflag++; + break; + case 'V': /* set object sizes and alignment requirements */ + { + arith size, align; + char c; + + while (c = *text++) + { + size = txt2int(&text); + switch (c) + { + case 'w': /* word */ + if (size != (arith)0) + wz = size; + break; + case 'p': /* pointer */ + if (size != (arith)0) + pz = size; + break; + case 'l': /* long */ + if (size != (arith)0) + vz = size; + break; + default: + fatal("-V: bad type indicator %c\n", c); + } + } + break; + } + } + } + + int txt2int(tp) char** tp; + { + /* the integer pointed to by *tp is read, while increasing + *tp; the resulting value is yielded. + */ + register int val = 0, ch; + + while (ch = **tp, ch >= '0' && ch <= '9') + { + val = val * 10 + ch - '0'; + (*tp)++; + } + return val; + } + + LLmessage(tk) register tk; + { + static errors = 0; + + if (tk > 0) + { + repeat_token(LLsymb); + warning("syntax error: %s expected (inserted)", tokenname(tk, 1)); + } + else if (tk == 0) + warning("syntax error: bad token %s (deleted)", tokenname(LLsymb, 0)); + else + { /* tk<0 */ + warning("syntax error: garbage at end of program"); + } + if (++errors == MAXERRORS) + { + fprintf(stderr, "Too many insert/delete errors. Compiler ends.\n"); + err = 1; + trailer(); + exit(1); + } + } + + static void nonconst(siz) char* siz; + { + report("%s should be a constant", siz); + } + + static void nonpositive(siz) char* siz; + { + report("%s must be positive", siz); + } + + static void rep_cleanup(e1, e2) struct expr *e1, *e2; + { + destroy(e1); + destroy(e2); + sym_up(); + } + + static void check_assoc(prev_op, op) register prev_op, op; + { + switch (op) + { + char prev[5]; + case '+': + case '*': + case AND: + case OR: + case BA: + case BO: + case BX: + if (prev_op == op) + break; + default: + strcpy(prev, tokenname(prev_op, 0)); + + warning("Operators %s and %s don't associate", prev, tokenname(op, 0)); + } + } } diff --git a/lang/pc/comp/declar.g b/lang/pc/comp/declar.g index c71afbd1d..68ad3dad3 100644 --- a/lang/pc/comp/declar.g +++ b/lang/pc/comp/declar.g @@ -1,1021 +1,1129 @@ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/pc/comp/declar.g + */ + /* D E C L A R A T I O N S */ { -#include "parameters.h" -/* next line DEBUG */ -#include "debug.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "LLlex.h" -#include "chk_expr.h" -#include "def.h" -#include "idf.h" -#include "main.h" -#include "misc.h" -#include "node.h" -#include "scope.h" -#include "type.h" -#include "code.h" -#include "error.h" -#include "label.h" -#include "enter.h" -#include "lookup.h" -#ifdef DBSYMTAB -#include "stab.h" -#endif - - -#define PC_BUFSIZ (sizeof(struct file) - offsetof(struct file, bufadr)) - -int proclevel = 0; /* nesting level of procedures */ -int parlevel = 0; /* nesting level of parametersections */ -int expect_label = 0; /* so the parser knows that we expect a label */ -static int in_type_defs; /* in type definition part or not */ + #include "parameters.h" + /* next line DEBUG */ + #include "debug.h" + + #include + #include + #include + #include + #include + #include + #include + #include + + #include "LLlex.h" + #include "chk_expr.h" + #include "def.h" + #include "idf.h" + #include "main.h" + #include "misc.h" + #include "node.h" + #include "scope.h" + #include "type.h" + #include "code.h" + #include "error.h" + #include "label.h" + #include "enter.h" + #include "lookup.h" + #ifdef DBSYMTAB + #include "stab.h" + #endif + + #define PC_BUFSIZ (sizeof(struct file) - offsetof(struct file, bufadr)) + + int proclevel = 0; /* nesting level of procedures */ + int parlevel = 0; /* nesting level of parametersections */ + int expect_label = 0; /* so the parser knows that we expect a label */ + static int in_type_defs; /* in type definition part or not */ } /* ISO section 6.2.1, p. 93 */ -Block(struct def *df;) -{ - arith i; -} : - { text_label = (label) 0; } - LabelDeclarationPart - Module(df, &i) - CompoundStatement - { if( !err_occurred ) - CodeEndBlock(df, i); - if( df ) EndBlock(df); - FreeNode(BlockScope->sc_lablist); - } -; +Block(struct def* df;) + { + arith i; + } + : + { text_label = (label)0; } + LabelDeclarationPart + Module(df, &i) + CompoundStatement + { + if (!err_occurred) + CodeEndBlock(df, i); + if (df) + EndBlock(df); + FreeNode(BlockScope->sc_lablist); + } + ; LabelDeclarationPart -{ - struct node *nd; -} : - [ - LABEL Label(&nd) - { if( nd ) { - DeclLabel(nd); - nd->nd_next = CurrentScope->sc_lablist; - CurrentScope->sc_lablist = nd; - } - } - [ %persistent - ',' Label(&nd) - { if( nd ) { - DeclLabel(nd); - nd->nd_next = CurrentScope->sc_lablist; - CurrentScope->sc_lablist = nd; - } - } - ]* - ';' - ]? -; - -Module(struct def *df; arith *i;) -{ - label save_label; -} : - ConstantDefinitionPart - { in_type_defs = 1; } - TypeDefinitionPart - { in_type_defs = 0; - /* resolve forward references */ - chk_forw_types(); - } - VariableDeclarationPart - { if( !proclevel ) { - chk_prog_params(); - BssVar(); - } - proclevel++; - save_label = text_label; - } - ProcedureAndFunctionDeclarationPart - { text_label = save_label; - - proclevel--; - chk_directives(); - - /* needed with labeldefinitions - and for-statement - */ - BlockScope = CurrentScope; - - if( !err_occurred ) - *i = CodeBeginBlock( df ); - } -; - - - - -ConstantDefinitionPart: - [ - CONST - [ %persistent - ConstantDefinition ';' - ]+ - ]? -; - -TypeDefinitionPart: - [ - TYPE - [ %persistent - TypeDefinition ';' - ]+ - ]? -; - -VariableDeclarationPart: - [ - VAR - [ %persistent - VariableDeclaration ';' - ]+ - ]? -; - -ProcedureAndFunctionDeclarationPart: - [ - [ - ProcedureDeclaration - | - FunctionDeclaration - ] ';' - ]* -; + { + struct node* nd; + } + : [ + LABEL + Label(&nd) + { + if (nd) + { + DeclLabel(nd); + nd->nd_next = CurrentScope->sc_lablist; + CurrentScope->sc_lablist = nd; + } + } + [ + %persistent + ',' + Label(&nd) + { + if (nd) + { + DeclLabel(nd); + nd->nd_next = CurrentScope->sc_lablist; + CurrentScope->sc_lablist = nd; + } + } + ]* + ';' + ]? + ; + +Module(struct def* df; arith* i;) + { + label save_label; + } + : ConstantDefinitionPart + { in_type_defs = 1; } + TypeDefinitionPart + { + in_type_defs = 0; + /* resolve forward references */ + chk_forw_types(); + } + VariableDeclarationPart + { + if (!proclevel) + { + chk_prog_params(); + BssVar(); + } + proclevel++; + save_label = text_label; + } + ProcedureAndFunctionDeclarationPart + { + text_label = save_label; + + proclevel--; + chk_directives(); + + /* needed with labeldefinitions + and for-statement + */ + BlockScope = CurrentScope; + + if (!err_occurred) + *i = CodeBeginBlock(df); + } + ; + +ConstantDefinitionPart + : [ + CONST + [ + %persistent + ConstantDefinition ';' + ]+ + ]? + ; + +TypeDefinitionPart + : [ + TYPE + [ + %persistent + TypeDefinition ';' + ]+ + ]? + ; + +VariableDeclarationPart + : [ + VAR + [ + %persistent + VariableDeclaration ';' + ]+ + ]? + ; + +ProcedureAndFunctionDeclarationPart + : [ + [ + ProcedureDeclaration + | FunctionDeclaration + ] + ';' + ]* + ; /* ISO section 6.1.6, p. 92 */ -Label(struct node **pnd;) -{ - char lab[5]; -} : { expect_label = 1; } - INTEGER /* not really an integer, in [0..9999] */ - { if( dot.TOK_INT < 0 || dot.TOK_INT > 9999 ) { - if( dot.TOK_INT != -1 ) /* This means insertion */ - error("label must lie in closed interval [0..9999]"); - *pnd = NULLNODE; - } - else { - sprintf(lab, "%d", (int) dot.TOK_INT); - *pnd = MkLeaf(Name, &dot); - (*pnd)->nd_IDF = str2idf(lab, 1); - } - expect_label = 0; - } -; +Label(struct node** pnd;) + { + char lab[5]; + } + : + { expect_label = 1; } + INTEGER + /* not really an integer, in [0..9999] */ + { + if (dot.TOK_INT < 0 || dot.TOK_INT > 9999) + { + if (dot.TOK_INT != -1) /* This means insertion */ + error("label must lie in closed interval [0..9999]"); + *pnd = NULLNODE; + } + else + { + sprintf(lab, "%d", (int)dot.TOK_INT); + *pnd = MkLeaf(Name, &dot); + (*pnd)->nd_IDF = str2idf(lab, 1); + } + expect_label = 0; + } + ; /* ISO section 6.3, p. 95 */ ConstantDefinition -{ - register struct idf *id; - register struct def *df; - struct node *nd; -} : - IDENT { id = dot.TOK_IDF; } - '=' Constant(&nd) - { if (( df = define(id,CurrentScope,D_CONST))) { - df->con_const = nd; - df->df_type = nd->nd_type; - df->df_flags |= D_SET; -#ifdef DBSYMTAB - if (options['g']) stb_string(df, D_CONST); -#endif /* DBSYMTAB */ - } - } -; + { + register struct idf* id; + register struct def* df; + struct node* nd; + } + : IDENT + { id = dot.TOK_IDF; } + '=' + Constant(&nd) + { + if ((df = define(id, CurrentScope, D_CONST))) + { + df->con_const = nd; + df->df_type = nd->nd_type; + df->df_flags |= D_SET; + #ifdef DBSYMTAB + if (options['g']) + stb_string(df, D_CONST); + #endif /* DBSYMTAB */ + } + } + ; /* ISO section 6.4.1, p. 96 */ TypeDefinition -{ - register struct idf *id; - register struct def *df; - struct type *tp; -} : - IDENT { id = dot.TOK_IDF; } - '=' TypeDenoter(&tp) - { if ((df = define(id, CurrentScope, D_TYPE)) ) { - df->df_type = tp; - df->df_flags |= D_SET; -#ifdef DBSYMTAB - if (options['g']) stb_string(df, D_TYPE); -#endif /* DBSYMTAB */ - } - } -; - -TypeDenoter(struct type **ptp;): - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - */ - TypeIdentifierOrSubrangeType(ptp) -| - PointerType(ptp) -| - StructuredType(ptp) -| - EnumeratedType(ptp) -; - -TypeIdentifierOrSubrangeType(struct type **ptp;) -{ - struct node *nd1, *nd2; -} : - /* This is a new rule because the grammar specified by the standard - * is not exactly LL(1) (see TypeDenoter). - */ -[ - %prefer - IDENT { nd1 = MkLeaf(Name, &dot); } - [ - /* empty */ - /* at this point IDENT must be a TypeIdentifier !! */ - { chk_type_id(ptp, nd1); - FreeNode(nd1); - } - | - /* at this point IDENT must be a Constant !! */ - { (void) ChkConstant(nd1); } - UPTO Constant(&nd2) - { *ptp = subr_type(nd1, nd2); - FreeNode(nd1); - FreeNode(nd2); - } - ] -| - Constant(&nd1) UPTO Constant(&nd2) - { *ptp = subr_type(nd1, nd2); - FreeNode(nd1); - FreeNode(nd2); - } -] -; - -TypeIdentifier(struct type **ptp;): - IDENT { register struct node *nd = MkLeaf(Name, &dot); - chk_type_id(ptp, nd); - FreeNode(nd); - } -; + { + register struct idf* id; + register struct def* df; + struct type* tp; + } + : IDENT + { id = dot.TOK_IDF; } + '=' + TypeDenoter(&tp) + { + if ((df = define(id, CurrentScope, D_TYPE))) + { + df->df_type = tp; + df->df_flags |= D_SET; + #ifdef DBSYMTAB + if (options['g']) + stb_string(df, D_TYPE); + #endif /* DBSYMTAB */ + } + } + ; + +TypeDenoter(struct type** ptp;) + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + */ + TypeIdentifierOrSubrangeType(ptp) + | PointerType(ptp) + | StructuredType(ptp) + | EnumeratedType(ptp) + ; + +TypeIdentifierOrSubrangeType(struct type** ptp;) + { + struct node *nd1, *nd2; + } + : + /* This is a new rule because the grammar specified by the standard + * is not exactly LL(1) (see TypeDenoter). + */ + [ + %prefer + IDENT + { nd1 = MkLeaf(Name, &dot); } + [ + /* empty */ + /* at this point IDENT must be a TypeIdentifier !! */ + { + chk_type_id(ptp, nd1); + FreeNode(nd1); + } + | + /* at this point IDENT must be a Constant !! */ + { (void)ChkConstant(nd1); } + UPTO + Constant(&nd2) + { + *ptp = subr_type(nd1, nd2); + FreeNode(nd1); + FreeNode(nd2); + } + ] + | Constant(&nd1) + UPTO + Constant(&nd2) + { + *ptp = subr_type(nd1, nd2); + FreeNode(nd1); + FreeNode(nd2); + } + ] + ; + +TypeIdentifier(struct type** ptp;) + : IDENT + { + register struct node* nd = MkLeaf(Name, &dot); + chk_type_id(ptp, nd); + FreeNode(nd); + } + ; /* ISO section 6.5.1, p. 105 */ VariableDeclaration -{ - struct node *VarList; - struct type *tp; -} : - IdentifierList(&VarList) ':' TypeDenoter(&tp) - { EnterVarList(VarList, tp, proclevel > 0); } -; + { + struct node* VarList; + struct type* tp; + } + : IdentifierList(&VarList) + ':' + TypeDenoter(&tp) + { EnterVarList(VarList, tp, proclevel > 0); } + ; /* ISO section 6.6.1, p. 108 */ ProcedureDeclaration -{ - struct node *nd; - struct type *tp; - register struct scopelist *scl; - register struct def *df; -} : - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - * - * ProcedureHeading without a FormalParameterList can be a - * ProcedureIdentification, i.e. the IDENT used in the Heading is - * also used in a "forward" declaration. - */ - { open_scope(); } - ProcedureHeading(&nd, &tp) ';' - { scl = CurrVis; close_scope(0); } - [ - Directive - { DoDirective(dot.TOK_IDF, nd, tp, scl, 0); } - | - { df = DeclProc(nd, tp, scl); -#ifdef DBSYMTAB - if (options['g']) stb_string(df, D_PROCEDURE); -#endif /* DBSYMTAB */ - } - Block(df) - { /* open_scope() is simulated in DeclProc() */ -#ifdef DBSYMTAB - if (options['g']) stb_string(df, D_PEND); -#endif /* DBSYMTAB */ - close_scope(1); - } - ] -; - -ProcedureHeading(struct node **pnd; register struct type **ptp;) -{ - struct node *fpl; -} : - PROCEDURE - IDENT { - *pnd = MkLeaf(Name, &dot); - } - [ - FormalParameterList(&fpl) - { arith nb_pars = 0; - struct paramlist *pr = 0; - - if( !parlevel ) - /* procedure declaration */ - nb_pars = EnterParamList(fpl, &pr); - else - /* procedure parameter */ - nb_pars = EnterParTypes(fpl, &pr); - - *ptp = proc_type(pr, nb_pars); - FreeNode(fpl); - } - | - /* empty */ - { *ptp = - proc_type((struct paramlist *)0, - (proclevel > 1) ? pointer_size : (arith) 0); - } - ] -; - -Directive: - /* see also Functiondeclaration (6.6.2, p. 110) - * Not actually an identifier but 'letter {letter | digit}' - */ - IDENT -; + { + struct node* nd; + struct type* tp; + register struct scopelist* scl; + register struct def* df; + } + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + * + * ProcedureHeading without a FormalParameterList can be a + * ProcedureIdentification, i.e. the IDENT used in the Heading is + * also used in a "forward" declaration. + */ + { open_scope(); } + ProcedureHeading(&nd, &tp) + ';' + { + scl = CurrVis; + close_scope(0); + } + [ + Directive + { DoDirective(dot.TOK_IDF, nd, tp, scl, 0); } + | + { + df = DeclProc(nd, tp, scl); + #ifdef DBSYMTAB + if (options['g']) + stb_string(df, D_PROCEDURE); + #endif /* DBSYMTAB */ + } + Block(df) + { + /* open_scope() is simulated in DeclProc() */ + #ifdef DBSYMTAB + if (options['g']) + stb_string(df, D_PEND); + #endif /* DBSYMTAB */ + close_scope(1); + } + ] + ; + +ProcedureHeading(struct node** pnd; register struct type** ptp;) + { + struct node* fpl; + } + : PROCEDURE IDENT + { *pnd = MkLeaf(Name, &dot); } + [ + FormalParameterList(&fpl) + { + arith nb_pars = 0; + struct paramlist* pr = 0; + + if (!parlevel) + /* procedure declaration */ + nb_pars = EnterParamList(fpl, &pr); + else + /* procedure parameter */ + nb_pars = EnterParTypes(fpl, &pr); + + *ptp = proc_type(pr, nb_pars); + FreeNode(fpl); + } + | + /* empty */ + { *ptp = proc_type((struct paramlist*)0, (proclevel > 1) ? pointer_size : (arith)0); } + ] + ; + +Directive + : + /* see also Functiondeclaration (6.6.2, p. 110) + * Not actually an identifier but 'letter {letter | digit}' + */ + IDENT + ; /* ISO section 6.6.1, p. 108 */ FunctionDeclaration -{ - struct node *nd; - struct type *tp; - register struct scopelist *scl; - register struct def *df; -} : - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - */ - { open_scope(); } - FunctionHeading(&nd, &tp) ';' - { scl = CurrVis; close_scope(0); } - [ - Directive - { if( !tp ) { - node_error(nd, - "function \"%s\": illegal declaration", - nd->nd_IDF->id_text); - } - else DoDirective(dot.TOK_IDF, nd, tp, scl, 1); - } - | - { if ((df = DeclFunc(nd, tp, scl) )) { - df->prc_res = - - ResultType(df->df_type)->tp_size; - df->prc_bool = - CurrentScope->sc_off = - df->prc_res - int_size; -#ifdef DBSYMTAB - if (options['g']) stb_string(df, D_FUNCTION); -#endif /* DBSYMTAB */ - } - } - Block(df) - { if( df ) { -#ifdef DBSYMTAB - if (options['g']) stb_string(df, D_PEND); -#endif /* DBSYMTAB */ - EndFunc(df); - } - - /* open_scope() is simulated in DeclFunc() */ - close_scope(1); - } - ] -; - -FunctionHeading(struct node **pnd; register struct type **ptp;) -{ - /* This is the Function AND FunctionIdentification part. - If it is a identification, *ptp is set to NULLTYPE. - */ - struct node *fpl = NULLNODE; - struct type *tp; - struct paramlist *pr = 0; - arith nb_pars = (proclevel > 1) ? pointer_size : 0; -} : - FUNCTION - IDENT { *pnd = MkLeaf(Name, &dot); - *ptp = NULLTYPE; - } -[ - [ - FormalParameterList(&fpl) - { if( !parlevel ) - /* function declaration */ - nb_pars = EnterParamList(fpl, &pr); - else - /* function parameter */ - nb_pars = EnterParTypes(fpl, &pr); - } - | - /* empty */ - ] - ':' TypeIdentifier(&tp) - { if( IsConstructed(tp) ) { - node_error(*pnd, - "function has an illegal result type"); - tp = error_type; - } - *ptp = func_type(pr, nb_pars, tp); - FreeNode(fpl); - } -]? -; + { + struct node* nd; + struct type* tp; + register struct scopelist* scl; + register struct def* df; + } + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + */ + { open_scope(); } + FunctionHeading(&nd, &tp) + ';' + { + scl = CurrVis; + close_scope(0); + } + [ + Directive + { + if (!tp) + { + node_error(nd, "function \"%s\": illegal declaration", nd->nd_IDF->id_text); + } + else + DoDirective(dot.TOK_IDF, nd, tp, scl, 1); + } + | + { + if ((df = DeclFunc(nd, tp, scl))) + { + df->prc_res = -ResultType(df->df_type)->tp_size; + df->prc_bool = CurrentScope->sc_off = df->prc_res - int_size; + #ifdef DBSYMTAB + if (options['g']) + stb_string(df, D_FUNCTION); + #endif /* DBSYMTAB */ + } + } + Block(df) + { + if (df) + { + #ifdef DBSYMTAB + if (options['g']) + stb_string(df, D_PEND); + #endif /* DBSYMTAB */ + EndFunc(df); + } + + /* open_scope() is simulated in DeclFunc() */ + close_scope(1); + } + ] + ; + +FunctionHeading(struct node** pnd; register struct type** ptp;) + { + /* This is the Function AND FunctionIdentification part. + If it is a identification, *ptp is set to NULLTYPE. + */ + struct node* fpl = NULLNODE; + struct type* tp; + struct paramlist* pr = 0; + arith nb_pars = (proclevel > 1) ? pointer_size : 0; + } + : FUNCTION IDENT + { + *pnd = MkLeaf(Name, &dot); + *ptp = NULLTYPE; + } + [ + [ + FormalParameterList(&fpl) + { + if (!parlevel) + /* function declaration */ + nb_pars = EnterParamList(fpl, &pr); + else + /* function parameter */ + nb_pars = EnterParTypes(fpl, &pr); + } + | + /* empty */ + ] + ':' + TypeIdentifier(&tp) + { + if (IsConstructed(tp)) + { + node_error(*pnd, "function has an illegal result type"); + tp = error_type; + } + *ptp = func_type(pr, nb_pars, tp); + FreeNode(fpl); + } + ]? + ; /* ISO section 6.4.2.1, p. 96 */ -OrdinalType(struct type **ptp;): - /* This is a changed rule, because the grammar as specified in the - * reference states that a SubrangeType can start with an IDENT and - * so can an OrdinalTypeIdentifier, and this is not LL(1). - */ - TypeIdentifierOrSubrangeType(ptp) -| - EnumeratedType(ptp) -; +OrdinalType(struct type** ptp;) + : + /* This is a changed rule, because the grammar as specified in the + * reference states that a SubrangeType can start with an IDENT and + * so can an OrdinalTypeIdentifier, and this is not LL(1). + */ + TypeIdentifierOrSubrangeType(ptp) + | EnumeratedType(ptp) + ; /* ISO section 6.4.2.3, p. 97 */ -EnumeratedType(struct type **ptp;) -{ - struct node *EnumList; - arith i = (arith) 1; -} : - '(' IdentifierList(&EnumList) ')' - { register struct type *tp = - standard_type(T_ENUMERATION, word_align, word_size); - - *ptp = tp; - EnterEnumList(EnumList, tp); - if( tp->enm_ncst == 0 ) - *ptp = error_type; - else do { - if( ufit(tp->enm_ncst-1, i) ) { - tp->tp_psize = i; - tp->tp_palign = i; - break; - } - i <<= 1; - } while( i < word_size ); - } -; - -IdentifierList(struct node **nd;) -{ - register struct node *tnd; -} : - IDENT { *nd = tnd = MkLeaf(Name, &dot); } - [ %persistent - ',' IDENT - { tnd->nd_next = MkLeaf(Name, &dot); - tnd = tnd->nd_next; - } - ]* -; +EnumeratedType(struct type** ptp;) + { + struct node* EnumList; + arith i = (arith)1; + } + : '(' + IdentifierList(&EnumList) + ')' + { + register struct type* tp = standard_type(T_ENUMERATION, word_align, word_size); + + *ptp = tp; + EnterEnumList(EnumList, tp); + if (tp->enm_ncst == 0) + *ptp = error_type; + else + do + { + if (ufit(tp->enm_ncst - 1, i)) + { + tp->tp_psize = i; + tp->tp_palign = i; + break; + } + i <<= 1; + } while (i < word_size); + } + ; + +IdentifierList(struct node** nd;) + { + register struct node* tnd; + } + : IDENT + { *nd = tnd = MkLeaf(Name, &dot); } + [ + %persistent + ',' IDENT + { + tnd->nd_next = MkLeaf(Name, &dot); + tnd = tnd->nd_next; + } + ]* + ; /* ISO section 6.4.3.2, p. 98 */ -StructuredType(struct type **ptp;) -{ - unsigned short packed = 0; -} : - [ - PACKED { packed = T_PACKED; } - ]? - UnpackedStructuredType(ptp, packed) -; - -UnpackedStructuredType(struct type **ptp; unsigned short packed;): - ArrayType(ptp, packed) -| - RecordType(ptp, packed) -| - SetType(ptp, packed) -| - FileType(ptp) -; +StructuredType(struct type** ptp;) + { + unsigned short packed = 0; + } + : [ + PACKED + { packed = T_PACKED; } + ]? + UnpackedStructuredType(ptp, packed) + ; + +UnpackedStructuredType(struct type** ptp; unsigned short packed;) + : ArrayType(ptp, packed) + | RecordType(ptp, packed) + | SetType(ptp, packed) + | FileType(ptp) + ; /* ISO section 6.4.3.2, p. 98 */ -ArrayType(struct type **ptp; unsigned short packed;) -{ - struct type *tp; - register struct type *tp2; -} : - ARRAY - '[' - Indextype(&tp) - { *ptp = tp2 = construct_type(T_ARRAY, tp); - tp2->tp_flags |= packed; - } - [ %persistent - ',' Indextype(&tp) - { tp2->arr_elem = construct_type(T_ARRAY, tp); - tp2 = tp2->arr_elem; - tp2->tp_flags |= packed; - } - ]* - ']' - OF ComponentType(&tp) - { tp2->arr_elem = tp; - ArraySizes(*ptp); - if( tp->tp_flags & T_HASFILE ) - (*ptp)->tp_flags |= T_HASFILE; - } -; - -Indextype(struct type **ptp;): - OrdinalType(ptp) -; - -ComponentType(struct type **ptp;): - TypeDenoter(ptp) -; +ArrayType(struct type** ptp; unsigned short packed;) + { + struct type* tp; + register struct type* tp2; + } + : ARRAY '[' + Indextype(&tp) + { + *ptp = tp2 = construct_type(T_ARRAY, tp); + tp2->tp_flags |= packed; + } + [ + %persistent + ',' + Indextype(&tp) + { + tp2->arr_elem = construct_type(T_ARRAY, tp); + tp2 = tp2->arr_elem; + tp2->tp_flags |= packed; + } + ]* + ']' OF + ComponentType(&tp) + { + tp2->arr_elem = tp; + ArraySizes(*ptp); + if (tp->tp_flags & T_HASFILE) + (*ptp)->tp_flags |= T_HASFILE; + } + ; + +Indextype(struct type** ptp;) + : OrdinalType(ptp) + ; + +ComponentType(struct type** ptp;) + : TypeDenoter(ptp) + ; /* ISO section 6.4.3.3, p. 99 */ -RecordType(struct type **ptp; unsigned short packed;) -{ - register struct scope *scope; - register struct def *df; - struct selector *sel = 0; - arith size = 0; - int xalign = struct_align; -} : - RECORD - { open_scope(); /* scope for fields of record */ - scope = CurrentScope; - close_scope(0); - } - FieldList(scope, &size, &xalign, packed, &sel) - { if( size == 0 ) { - warning("empty record declaration"); - size = 1; - } - *ptp = standard_type(T_RECORD, xalign, size); - (*ptp)->rec_scope = scope; - (*ptp)->rec_sel = sel; - (*ptp)->tp_flags |= packed; - - /* copy the file component flag */ - df = scope->sc_def; - while( df && !(df->df_type->tp_flags & T_HASFILE) ) - df = df->df_nextinscope; - - if( df ) - (*ptp)->tp_flags |= T_HASFILE; - } - END -; - -FieldList(struct scope *scope; arith *cnt; int *palign; unsigned short packed; - struct selector **sel;): - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - * Those irritating, annoying (Siklossy !!) semicolons. - */ - - /* empty */ -| - FixedPart(scope, cnt, palign, packed, sel) -| - VariantPart(scope, cnt, palign, packed, sel) -; - -FixedPart(struct scope *scope; arith *cnt; int *palign; unsigned short packed; - struct selector **sel;): - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - * Again those frustrating semicolons !! - */ - RecordSection(scope, cnt, palign, packed) - FixedPartTail(scope, cnt, palign, packed, sel) -; - -FixedPartTail(struct scope *scope; arith *cnt; int *palign; - unsigned short packed; struct selector **sel;): - /* This is a new rule because the grammar specified by the standard - * is not exactly LL(1). - * We see the light at the end of the tunnel ! - */ - - /* empty */ -| - %default - ';' - [ - /* empty */ - | - VariantPart(scope, cnt, palign, packed, sel) - | - RecordSection(scope, cnt, palign, packed) - FixedPartTail(scope, cnt, palign, packed, sel) - ] -; - -RecordSection(struct scope *scope; arith *cnt; int *palign; - unsigned short packed;) -{ - struct node *FldList; - struct type *tp; -} : - - IdentifierList(&FldList) ':' TypeDenoter(&tp) - { *palign = - lcm(*palign, packed ? tp->tp_palign : word_align); - EnterFieldList(FldList, tp, scope, cnt, packed); - } -; - -VariantPart(struct scope *scope; arith *cnt; int *palign; - unsigned short packed; struct selector **sel;) -{ - struct type *tp; - struct def *df = 0; - struct idf *id = 0; - arith tcnt, max; - register arith ncst = 0;/* the number of values of the tagtype */ - register struct selector **sp; -} : - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - * We're almost there !! - */ - - { *sel = (struct selector *) malloc(sizeof(struct selector)); - (*sel)->sel_ptrs = 0; - } - CASE - VariantSelector(&tp, &id) - { if (id) - df = define(id, scope, D_FIELD); -/* ISO 6.4.3.3 (p. 100) - * The standard permits the integertype as tagtype, but demands that the set - * of values denoted by the case-constants is equal to the set of values - * specified by the tagtype. - */ - if( !(tp->tp_fund & T_INDEX)) { - error("illegal type in variant"); - tp = error_type; - } - else { - arith lb, ub; - - getbounds(tp, &lb, &ub); - ncst = ub - lb + 1; - if (ncst < 0 || ncst > (~(1L<<(8*sizeof(arith)-1)))/sizeof(struct selector *)) { - error("range of variant tag too wide"); - tp = error_type; - } - else { - /* initialize selector */ - (*sel)->sel_ptrs = (struct selector **) - malloc((unsigned)ncst * sizeof(struct selector *)); - (*sel)->sel_ncst = ncst; - (*sel)->sel_lb = lb; - - /* initialize tagvalue-table */ - sp = (*sel)->sel_ptrs; - while( ncst-- ) *sp++ = *sel; - } - } - (*sel)->sel_type = tp; - if( df ) { - df->df_type = tp; - df->fld_flags |= - packed ? (F_PACKED | F_SELECTOR) : F_SELECTOR; - df->fld_off = align(*cnt, - packed ? tp->tp_palign : tp->tp_align); - *cnt = df->fld_off + - (packed ? tp->tp_psize : tp->tp_size); - } - tcnt = *cnt; - } - OF - Variant(scope, &tcnt, palign, packed, *sel) - { max = tcnt; } - VariantTail(scope, &tcnt, &max, cnt, palign, packed, *sel) - { *cnt = max; - if ( (sp = (*sel)->sel_ptrs) ) { - int errflag = 0; - - ncst = (*sel)->sel_ncst; - while( ncst-- ) - if( *sp == *sel ) { - *sp++ = 0; - errflag = 1; - } - else *sp++; - if( errflag ) - error("record variant part: each tagvalue must have a variant"); - } - } -; - -VariantTail(struct scope *scope; arith *tcnt; arith *max; arith *cnt; - int *palign; unsigned short packed; struct selector *sel;): - /* This is a new rule because the grammar specified by the standard - * is not exactly LL(1). - * At last, the garden of Eden !! - */ - - /* empty */ -| -%default - ';' - [ - /* empty */ - | - { *tcnt = *cnt; } - Variant(scope, tcnt, palign, packed, sel) - { if( *tcnt > *max ) *max = *tcnt; } - VariantTail(scope, tcnt, max, cnt, palign, packed, sel) - ] -; - -VariantSelector(struct type **ptp; register struct idf **pid;) -{ - register struct node *nd; -} : - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - */ - - IDENT { nd = MkLeaf(Name, &dot); } - [ - /* Old fashioned ! at this point the IDENT represents - * the TagType - */ - { warning("old-fashioned syntax ':' missing"); - chk_type_id(ptp, nd); - FreeNode(nd); - } - | - /* IDENT is now the TagField */ - ':' - TypeIdentifier(ptp) - { *pid = nd->nd_IDF; - FreeNode(nd); - } - ] -; - -Variant(struct scope *scope; arith *cnt; int *palign; unsigned short packed; - struct selector *sel;) -{ - struct node *nd; - struct selector *sel1 = 0; -} : - CaseConstantList(&nd) - ':' - '(' FieldList(scope, cnt, palign, packed, &sel1) ')' - { TstCaseConstants(nd, sel, sel1); - FreeNode(nd); - } -; - -CaseConstantList(struct node **nd;) -{ - struct node *nd1; -} : - Constant(&nd1) { *nd = nd1; } - [ %persistent - ',' Constant(&(nd1->nd_next)) - { nd1 = nd1->nd_next; } - ]* -; +RecordType(struct type** ptp; unsigned short packed;) + { + register struct scope* scope; + register struct def* df; + struct selector* sel = 0; + arith size = 0; + int xalign = struct_align; + } + : RECORD + { + open_scope(); /* scope for fields of record */ + scope = CurrentScope; + close_scope(0); + } + FieldList(scope, &size, &xalign, packed, &sel) + { + if (size == 0) + { + warning("empty record declaration"); + size = 1; + } + *ptp = standard_type(T_RECORD, xalign, size); + (*ptp)->rec_scope = scope; + (*ptp)->rec_sel = sel; + (*ptp)->tp_flags |= packed; + + /* copy the file component flag */ + df = scope->sc_def; + while (df && !(df->df_type->tp_flags & T_HASFILE)) + df = df->df_nextinscope; + + if (df) + (*ptp)->tp_flags |= T_HASFILE; + } + END + ; + +FieldList( + struct scope* scope; arith* cnt; int* palign; unsigned short packed; struct selector** sel;) + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + * Those irritating, annoying (Siklossy !!) semicolons. + */ + + /* empty */ + | FixedPart(scope, cnt, palign, packed, sel) + | VariantPart(scope, cnt, palign, packed, sel) + ; + +FixedPart( + struct scope* scope; arith* cnt; int* palign; unsigned short packed; struct selector** sel;) + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + * Again those frustrating semicolons !! + */ + RecordSection(scope, cnt, palign, packed) + FixedPartTail(scope, cnt, palign, packed, sel) + ; + +FixedPartTail( + struct scope* scope; arith* cnt; int* palign; unsigned short packed; struct selector** sel;) + : + /* This is a new rule because the grammar specified by the standard + * is not exactly LL(1). + * We see the light at the end of the tunnel ! + */ + + /* empty */ + | %default + ';' + [ + /* empty */ + | VariantPart(scope, cnt, palign, packed, sel) + | RecordSection(scope, cnt, palign, packed) + FixedPartTail(scope, cnt, palign, packed, sel) + ] + ; + +RecordSection(struct scope* scope; arith* cnt; int* palign; unsigned short packed;) + { + struct node* FldList; + struct type* tp; + } + : IdentifierList(&FldList) + ':' + TypeDenoter(&tp) + { + *palign = lcm(*palign, packed ? tp->tp_palign : word_align); + EnterFieldList(FldList, tp, scope, cnt, packed); + } + ; + +VariantPart( + struct scope* scope; arith* cnt; int* palign; unsigned short packed; struct selector** sel;) + { + struct type* tp; + struct def* df = 0; + struct idf* id = 0; + arith tcnt, max; + register arith ncst = 0; /* the number of values of the tagtype */ + register struct selector** sp; + } + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + * We're almost there !! + */ + + { + *sel = (struct selector*)malloc(sizeof(struct selector)); + (*sel)->sel_ptrs = 0; + } + CASE + VariantSelector(&tp, &id) + { + if (id) + df = define(id, scope, D_FIELD); + /* ISO 6.4.3.3 (p. 100) + * The standard permits the integertype as tagtype, but demands that the set + * of values denoted by the case-constants is equal to the set of values + * specified by the tagtype. + */ + if (!(tp->tp_fund & T_INDEX)) + { + error("illegal type in variant"); + tp = error_type; + } + else + { + arith lb, ub; + + getbounds(tp, &lb, &ub); + ncst = ub - lb + 1; + if (ncst < 0 + || ncst > (~(1L << (8 * sizeof(arith) - 1))) / sizeof(struct selector*)) + { + error("range of variant tag too wide"); + tp = error_type; + } + else + { + /* initialize selector */ + (*sel)->sel_ptrs + = (struct selector**)malloc((unsigned)ncst * sizeof(struct selector*)); + (*sel)->sel_ncst = ncst; + (*sel)->sel_lb = lb; + + /* initialize tagvalue-table */ + sp = (*sel)->sel_ptrs; + while (ncst--) + *sp++ = *sel; + } + } + (*sel)->sel_type = tp; + if (df) + { + df->df_type = tp; + df->fld_flags |= packed ? (F_PACKED | F_SELECTOR) : F_SELECTOR; + df->fld_off = align(*cnt, packed ? tp->tp_palign : tp->tp_align); + *cnt = df->fld_off + (packed ? tp->tp_psize : tp->tp_size); + } + tcnt = *cnt; + } + OF + Variant(scope, &tcnt, palign, packed, *sel) + { max = tcnt; } + VariantTail(scope, &tcnt, &max, cnt, palign, packed, *sel) + { + *cnt = max; + if ((sp = (*sel)->sel_ptrs)) + { + int errflag = 0; + + ncst = (*sel)->sel_ncst; + while (ncst--) + if (*sp == *sel) + { + *sp++ = 0; + errflag = 1; + } + else + *sp++; + if (errflag) + error("record variant part: each tagvalue must have a variant"); + } + } + ; + +VariantTail(struct scope* scope; + arith* tcnt; + arith* max; + arith* cnt; + int* palign; + unsigned short packed; + struct selector* sel;) + : + /* This is a new rule because the grammar specified by the standard + * is not exactly LL(1). + * At last, the garden of Eden !! + */ + + /* empty */ + | %default + ';' + [ + /* empty */ + | + { *tcnt = *cnt; } + Variant(scope, tcnt, palign, packed, sel) + { if (*tcnt > *max) *max = *tcnt; } + VariantTail(scope, tcnt, max, cnt, palign, packed, sel) + ] + ; + +VariantSelector(struct type** ptp; register struct idf** pid;) + { + register struct node* nd; + } + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + */ + + IDENT + { nd = MkLeaf(Name, &dot); } + [ + /* Old fashioned ! at this point the IDENT represents + * the TagType + */ + { + warning("old-fashioned syntax ':' missing"); + chk_type_id(ptp, nd); + FreeNode(nd); + } + | + /* IDENT is now the TagField */ + ':' + TypeIdentifier(ptp) + { + *pid = nd->nd_IDF; + FreeNode(nd); + } + ] + ; + +Variant(struct scope* scope; arith* cnt; int* palign; unsigned short packed; struct selector* sel;) + { + struct node* nd; + struct selector* sel1 = 0; + } + : CaseConstantList(&nd) + ':' '(' + FieldList(scope, cnt, palign, packed, &sel1) + ')' + { + TstCaseConstants(nd, sel, sel1); + FreeNode(nd); + } + ; + +CaseConstantList(struct node** nd;) + { + struct node* nd1; + } + : Constant(&nd1) + { *nd = nd1; } + [ + %persistent + ',' + Constant(&(nd1->nd_next)) + { nd1 = nd1->nd_next; } + ]* + ; /* ISO section 6.4.3.4, p. 101 */ -SetType(struct type **ptp; unsigned short packed;): - SET OF OrdinalType(ptp) - { *ptp = set_type(*ptp, packed); } -; +SetType(struct type** ptp; unsigned short packed;) + : SET OF + OrdinalType(ptp) + { *ptp = set_type(*ptp, packed); } + ; /* ISO section 6.4.3.5, p. 101 */ -FileType(struct type **ptp;): - FILET OF - { *ptp = construct_type(T_FILE, NULLTYPE); - (*ptp)->tp_flags |= T_HASFILE; - } - ComponentType(&(*ptp)->next) - { if( (*ptp)->next->tp_flags & T_HASFILE ) { - error("file type has an illegal component type"); - (*ptp)->next = error_type; - } - else { - if( (*ptp)->next->tp_size > PC_BUFSIZ ) - (*ptp)->tp_size = (*ptp)->tp_psize = - (*ptp)->next->tp_size + - sizeof(struct file) - PC_BUFSIZ; - } - } -; +FileType(struct type** ptp;) + : FILET OF + { + *ptp = construct_type(T_FILE, NULLTYPE); + (*ptp)->tp_flags |= T_HASFILE; + } + ComponentType(&(*ptp)->next) + { + if ((*ptp)->next->tp_flags & T_HASFILE) + { + error("file type has an illegal component type"); + (*ptp)->next = error_type; + } + else + { + if ((*ptp)->next->tp_size > PC_BUFSIZ) + (*ptp)->tp_size = (*ptp)->tp_psize + = (*ptp)->next->tp_size + sizeof(struct file) - PC_BUFSIZ; + } + } + ; /* ISO section 6.4.4, p. 103 */ -PointerType(struct type **ptp;) -{ - register struct node *nd; - register struct def *df; -} : - '^' - { *ptp = construct_type(T_POINTER, NULLTYPE); } - IDENT - { nd = MkLeaf(Name, &dot); - df = lookup(nd->nd_IDF, CurrentScope, D_INUSE); - /* if( !df && CurrentScope == GlobalScope) - df = lookup(nd->nd_IDF, PervasiveScope, D_INUSE); - */ - if( in_type_defs && - (!df || (df->df_kind & (D_ERROR | D_FORWTYPE))) - ) - /* forward declarations only in typedefintion - part - */ - Forward(nd, *ptp); - else { - chk_type_id(&(*ptp)->next, nd); - FreeNode(nd); - } - } -; +PointerType(struct type** ptp;) + { + register struct node* nd; + register struct def* df; + } + : '^' + { *ptp = construct_type(T_POINTER, NULLTYPE); } + IDENT + { + nd = MkLeaf(Name, &dot); + df = lookup(nd->nd_IDF, CurrentScope, D_INUSE); + /* if( !df && CurrentScope == GlobalScope) + df = lookup(nd->nd_IDF, PervasiveScope, D_INUSE); + */ + if (in_type_defs && (!df || (df->df_kind & (D_ERROR | D_FORWTYPE)))) + /* forward declarations only in typedefintion + part + */ + Forward(nd, *ptp); + else + { + chk_type_id(&(*ptp)->next, nd); + FreeNode(nd); + } + } + ; /* ISO section 6.6.3.1, p. 112 */ -FormalParameterList(struct node **pnd;) -{ - struct node *nd; -} : - '(' - { *pnd = nd = MkLeaf(Link, &dot); } - FormalParameterSection(nd) - [ %persistent - { nd->nd_right = MkLeaf(Link, &dot); - nd = nd->nd_right; - } - ';' FormalParameterSection(nd) - ]* - ')' -; - -FormalParameterSection(struct node *nd;): -/* This is a changed rule, because the grammar as specified - * in the reference is not LL(1), and this gives conflicts. - */ - { /* kind of parameter */ - nd->nd_INT = 0; - } -[ - [ - /* ValueParameterSpecification */ - /* empty */ - { nd->nd_INT = (D_VALPAR | D_SET); } - | - /* VariableParameterSpecification */ - VAR - { nd->nd_INT = (D_VARPAR | D_USED); } - ] - IdentifierList(&(nd->nd_left)) ':' - [ - /* ISO section 6.6.3.7.1, p. 115 */ - /* ConformantArrayParameterSpecification */ - ConformantArraySchema(&(nd->nd_type)) - | - TypeIdentifier(&(nd->nd_type)) - ] - { if( nd->nd_type->tp_flags & T_HASFILE && - (nd->nd_INT & D_VALPAR) ) { - error("value parameter can't have a filecomponent"); - nd->nd_type = error_type; - } - } -| - ProceduralParameterSpecification(&(nd->nd_left), &(nd->nd_type)) - { nd->nd_INT = (D_VALPAR | D_SET); } -| - FunctionalParameterSpecification(&(nd->nd_left), &(nd->nd_type)) - { nd->nd_INT = (D_VALPAR | D_SET); } -] -; - -ProceduralParameterSpecification(struct node **pnd; - register struct type **ptp;): - { parlevel++; } - ProcedureHeading(pnd, ptp) - { parlevel--; } -; - -FunctionalParameterSpecification(struct node **pnd; - register struct type **ptp;): - { parlevel++; } - FunctionHeading(pnd, ptp) - { parlevel--; - if( !*ptp ) { - node_error(*pnd, - "illegal function parameter declaration"); - *ptp = error_type; - } - } -; - -ConformantArraySchema(struct type **ptp;): - PackedConformantArraySchema(ptp) -| - %default - UnpackedConformantArraySchema(ptp) -; - -PackedConformantArraySchema(struct type **ptp;) -{ - struct type *tp; -} : - PACKED ARRAY - { tp = construct_type(T_ARRAY, NULLTYPE); - tp->tp_flags |= T_PACKED; - } - '[' - Index_TypeSpecification(ptp, tp) - { tp->next = *ptp; } - ']' - OF TypeIdentifier(ptp) - { if( (*ptp)->tp_flags & T_HASFILE ) - tp->tp_flags |= T_HASFILE; - tp->arr_elem = *ptp; - *ptp = tp; - } -; - -UnpackedConformantArraySchema(struct type **ptp;) -{ - struct type *tp, *tp2; -} : - ARRAY - { *ptp = tp = construct_type(T_ARRAY,NULLTYPE);} - '[' - Index_TypeSpecification(&tp2, tp) - { tp->next = tp2; } - [ - { tp->arr_elem = - construct_type(T_ARRAY, NULLTYPE); - tp = tp->arr_elem; - } - ';' Index_TypeSpecification(&tp2, tp) - { tp->next = tp2; } - ]* - ']' - OF - [ - TypeIdentifier(&tp2) - | - ConformantArraySchema(&tp2) - ] - { if( tp2->tp_flags & T_HASFILE ) - (*ptp)->tp_flags |= T_HASFILE; - tp->arr_elem = tp2; - } -; - -Index_TypeSpecification(struct type **ptp; register struct type *tp;) -{ - register struct def *df1, *df2; -} : - IDENT - { if( (df1 = - define(dot.TOK_IDF, CurrentScope, D_LBOUND)) ) { - df1->bnd_type = tp; /* type conf. array */ - df1->df_flags |= D_SET; - } - } - UPTO - IDENT - { if( (df2 = - define(dot.TOK_IDF, CurrentScope, D_UBOUND)) ) { - df2->bnd_type = tp; /* type conf. array */ - df2->df_flags |= D_SET; - } - } - ':' TypeIdentifier(ptp) - { if( !bounded(*ptp) && - (*ptp)->tp_fund != T_INTEGER ) { - error("Indextypespecification: illegal type"); - *ptp = error_type; - } - df1->df_type = df2->df_type = *ptp; - } -; +FormalParameterList(struct node** pnd;) + { + struct node* nd; + } + : '(' + { *pnd = nd = MkLeaf(Link, &dot); } + FormalParameterSection(nd) + [ + %persistent + { + nd->nd_right = MkLeaf(Link, &dot); + nd = nd->nd_right; + } + ';' + FormalParameterSection(nd) + ]* + ')' + ; + +FormalParameterSection(struct node* nd;) + : + /* This is a changed rule, because the grammar as specified + * in the reference is not LL(1), and this gives conflicts. + */ + { /* kind of parameter */ nd->nd_INT = 0; } + [ + [ + /* ValueParameterSpecification */ + /* empty */ + { nd->nd_INT = (D_VALPAR | D_SET); } + | + /* VariableParameterSpecification */ + VAR + { nd->nd_INT = (D_VARPAR | D_USED); } + ] + IdentifierList(&(nd->nd_left)) + ':' + [ + /* ISO section 6.6.3.7.1, p. 115 */ + /* ConformantArrayParameterSpecification */ + ConformantArraySchema(&(nd->nd_type)) + | TypeIdentifier(&(nd->nd_type)) + ] + { + if (nd->nd_type->tp_flags & T_HASFILE && (nd->nd_INT & D_VALPAR)) + { + error("value parameter can't have a filecomponent"); + nd->nd_type = error_type; + } + } + | ProceduralParameterSpecification(&(nd->nd_left), &(nd->nd_type)) + { nd->nd_INT = (D_VALPAR | D_SET); } + | FunctionalParameterSpecification(&(nd->nd_left), &(nd->nd_type)) + { nd->nd_INT = (D_VALPAR | D_SET); } + ] + ; + +ProceduralParameterSpecification(struct node** pnd; register struct type** ptp;) + : + { parlevel++; } + ProcedureHeading(pnd, ptp) + { parlevel--; } + ; + +FunctionalParameterSpecification(struct node** pnd; register struct type** ptp;) + : + { parlevel++; } + FunctionHeading(pnd, ptp) + { + parlevel--; + if (!*ptp) + { + node_error(*pnd, "illegal function parameter declaration"); + *ptp = error_type; + } + } + ; + +ConformantArraySchema(struct type** ptp;) + : PackedConformantArraySchema(ptp) + | %default + UnpackedConformantArraySchema(ptp) + ; + +PackedConformantArraySchema(struct type** ptp;) + { + struct type* tp; + } + : PACKED ARRAY + { + tp = construct_type(T_ARRAY, NULLTYPE); + tp->tp_flags |= T_PACKED; + } + '[' + Index_TypeSpecification(ptp, tp) + { tp->next = *ptp; } + ']' OF + TypeIdentifier(ptp) + { + if ((*ptp)->tp_flags & T_HASFILE) + tp->tp_flags |= T_HASFILE; + tp->arr_elem = *ptp; + *ptp = tp; + } + ; + +UnpackedConformantArraySchema(struct type** ptp;) + { + struct type *tp, *tp2; + } + : ARRAY + { *ptp = tp = construct_type(T_ARRAY, NULLTYPE); } + '[' + Index_TypeSpecification(&tp2, tp) + { tp->next = tp2; } + [ + { + tp->arr_elem = construct_type(T_ARRAY, NULLTYPE); + tp = tp->arr_elem; + } + ';' + Index_TypeSpecification(&tp2, tp) + { tp->next = tp2; } + ]* + ']' OF + [ + TypeIdentifier(&tp2) + | ConformantArraySchema(&tp2) + ] + { + if (tp2->tp_flags & T_HASFILE) + (*ptp)->tp_flags |= T_HASFILE; + tp->arr_elem = tp2; + } + ; + +Index_TypeSpecification(struct type** ptp; register struct type* tp;) + { + register struct def *df1, *df2; + } + : IDENT + { + if ((df1 = define(dot.TOK_IDF, CurrentScope, D_LBOUND))) + { + df1->bnd_type = tp; /* type conf. array */ + df1->df_flags |= D_SET; + } + } + UPTO IDENT + { + if ((df2 = define(dot.TOK_IDF, CurrentScope, D_UBOUND))) + { + df2->bnd_type = tp; /* type conf. array */ + df2->df_flags |= D_SET; + } + } + ':' + TypeIdentifier(ptp) + { + if (!bounded(*ptp) && (*ptp)->tp_fund != T_INTEGER) + { + error("Indextypespecification: illegal type"); + *ptp = error_type; + } + df1->df_type = df2->df_type = *ptp; + } + ; diff --git a/lang/pc/comp/expression.g b/lang/pc/comp/expression.g index 9c61cff66..6a6a8e1ab 100644 --- a/lang/pc/comp/expression.g +++ b/lang/pc/comp/expression.g @@ -1,300 +1,356 @@ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/pc/comp/expression.g + */ + /* EXPRESSIONS */ { -#include "debug.h" + #include "debug.h" -#include -#include -#include + #include + #include + #include -#include "LLlex.h" -#include "chk_expr.h" -#include "def.h" -#include "main.h" -#include "misc.h" -#include "idf.h" -#include "node.h" -#include "scope.h" -#include "type.h" -#include "code.h" -#include "error.h" -#include "lookup.h" + #include "LLlex.h" + #include "chk_expr.h" + #include "def.h" + #include "main.h" + #include "misc.h" + #include "idf.h" + #include "node.h" + #include "scope.h" + #include "type.h" + #include "code.h" + #include "error.h" + #include "lookup.h" } -Constant(struct node **pnd;) -{ - register struct node **nd = pnd; -} : -%default - [ - Sign(nd) { nd = &((*nd)->nd_right); } - ]? - [ %default - UnsignedNumber(nd) - | - ConstantIdentifier(nd) - ] - { (void) ChkConstant(*pnd); } -| - STRING { *pnd = MkLeaf(Value, &dot); - if( ((*pnd)->nd_type = toktype) != char_type ) - RomString(*pnd); - } -; +Constant(struct node** pnd;) + { + register struct node** nd = pnd; + } + : %default + [ + Sign(nd) + { nd = &((*nd)->nd_right); } + ]? + [ + %default + UnsignedNumber(nd) + | ConstantIdentifier(nd) + ] + { (void)ChkConstant(*pnd); } + | STRING + { + *pnd = MkLeaf(Value, &dot); + if (((*pnd)->nd_type = toktype) != char_type) + RomString(*pnd); + } + ; -Sign(struct node **pnd;): - ['+' | '-'] { *pnd = MkLeaf(Uoper, &dot); } -; +Sign(struct node** pnd;) + : [ + '+' + | '-' + ] + { *pnd = MkLeaf(Uoper, &dot); } + ; -UnsignedNumber(struct node **pnd;): - [INTEGER | REAL] { *pnd = MkLeaf(Value, &dot); - (*pnd)->nd_type = toktype; - } -; +UnsignedNumber(struct node** pnd;) + : [ + INTEGER + | REAL + ] + { + *pnd = MkLeaf(Value, &dot); + (*pnd)->nd_type = toktype; + } + ; -ConstantIdentifier(struct node **pnd;): - IDENT { *pnd = MkLeaf(Name, &dot); - } -; +ConstantIdentifier(struct node** pnd;) + : IDENT + { *pnd = MkLeaf(Name, &dot); } + ; /* ISO section 6.7.1, p. 121 */ -Expression(struct node **pnd;): - SimpleExpression(pnd) - [ - /* RelationalOperator substituted inline */ - [ '=' | NOTEQUAL | '<' | '>' | LESSEQUAL | GREATEREQUAL | IN ] - { *pnd = MkNode(Boper, *pnd, NULLNODE, &dot); } - SimpleExpression(&((*pnd)->nd_right)) - ]? -; +Expression(struct node** pnd;) + : SimpleExpression(pnd) + [ + /* RelationalOperator substituted inline */ + [ + '=' + | NOTEQUAL + | '<' + | '>' + | LESSEQUAL + | GREATEREQUAL + | IN + ] + { *pnd = MkNode(Boper, *pnd, NULLNODE, &dot); } + SimpleExpression(&((*pnd)->nd_right)) + ]? + ; -SimpleExpression(struct node **pnd;): - /* ISO 6.7.1: The signs and the adding-operators have equal precedence, - and are left-associative. - */ - [ - Sign(pnd) - Term(&((*pnd)->nd_right)) - | - Term(pnd) - ] - [ - /* AddingOperator substituted inline */ - [ '+' | '-' | OR ] - { *pnd = MkNode(Boper, *pnd, NULLNODE, &dot); } - Term(&((*pnd)->nd_right)) - ]* -; +SimpleExpression(struct node** pnd;) + : + /* ISO 6.7.1: The signs and the adding-operators have equal precedence, + and are left-associative. + */ + [ + Sign(pnd) + Term(&((*pnd)->nd_right)) + | Term(pnd) + ] + [ + /* AddingOperator substituted inline */ + [ + '+' + | '-' + | OR + ] + { *pnd = MkNode(Boper, *pnd, NULLNODE, &dot); } + Term(&((*pnd)->nd_right)) + ]* + ; -Term(struct node **pnd;): - Factor(pnd) - [ - /* MultiplyingOperator substituted inline */ - [ '*' | '/' | DIV | MOD | AND ] - { *pnd = MkNode(Boper, *pnd, NULLNODE, &dot); } - Factor(&((*pnd)->nd_right)) - ]* -; +Term(struct node** pnd;) + : Factor(pnd) + [ + /* MultiplyingOperator substituted inline */ + [ + '*' + | '/' + | DIV + | MOD + | AND + ] + { *pnd = MkNode(Boper, *pnd, NULLNODE, &dot); } + Factor(&((*pnd)->nd_right)) + ]* + ; -Factor(struct node **pnd;) -{ - register struct def *df; -} : - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - */ - %default - %prefer /* solve conflicts on IDENT and UnsignedConstant */ - IDENT { *pnd = MkLeaf(Name, &dot); } - [ - /* ISO section 6.7.3, p. 126 - * IDENT is a FunctionIdentifier - */ - { - *pnd = MkNode(Call, *pnd, NULLNODE, &dot); - } - ActualParameterList(&((*pnd)->nd_right)) - | - /* IDENT can be a BoundIdentifier or a ConstantIdentifier or - * a FunctionIdentifier (no parameterlist), in which case - * VariableAccessTail is empty. - * It could also be the beginning of a normal VariableAccess - * (most likely). - */ - { int class; +Factor(struct node** pnd;) + { + register struct def* df; + } + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + */ + %default + %prefer + /* solve conflicts on IDENT and UnsignedConstant */ + IDENT + { *pnd = MkLeaf(Name, &dot); } + [ + /* ISO section 6.7.3, p. 126 + * IDENT is a FunctionIdentifier + */ + { *pnd = MkNode(Call, *pnd, NULLNODE, &dot); } + ActualParameterList(&((*pnd)->nd_right)) + | + /* IDENT can be a BoundIdentifier or a ConstantIdentifier or + * a FunctionIdentifier (no parameterlist), in which case + * VariableAccessTail is empty. + * It could also be the beginning of a normal VariableAccess + * (most likely). + */ + { + int class; - df = lookfor(*pnd, CurrVis, 1); - /* df->df_flags |= D_USED; */ - if( df->df_type->tp_fund & T_ROUTINE ) { - /* This part is context-sensitive: - is the occurence of the proc/func name - a call or not ? - */ - if( df->df_type == std_type ) - class = Call; - else - class = NameOrCall; - *pnd = MkNode(class, *pnd, NULLNODE, &dot); - (*pnd)->nd_symb = '('; - } - } + df = lookfor(*pnd, CurrVis, 1); + /* df->df_flags |= D_USED; */ + if (df->df_type->tp_fund & T_ROUTINE) + { + /* This part is context-sensitive: + is the occurence of the proc/func name + a call or not ? + */ + if (df->df_type == std_type) + class = Call; + else + class = NameOrCall; + *pnd = MkNode(class, *pnd, NULLNODE, &dot); + (*pnd)->nd_symb = '('; + } + } + VariableAccessTail(pnd) + ] + | UnsignedConstant(pnd) + | SetConstructor(pnd) + | '(' + { /* dummy node to force ChkVariable */ *pnd = MkLeaf(Uoper, &dot); } + Expression(&((*pnd)->nd_right)) + ')' + | NOT + { *pnd = MkLeaf(Uoper, &dot); } + Factor(&((*pnd)->nd_right)) + ; - VariableAccessTail(pnd) - ] -| - UnsignedConstant(pnd) -| - SetConstructor(pnd) -| - '(' { /* dummy node to force ChkVariable */ - *pnd = MkLeaf(Uoper, &dot); - } - Expression(&((*pnd)->nd_right)) - ')' -| - NOT { *pnd = MkLeaf(Uoper, &dot); } - Factor(&((*pnd)->nd_right)) -; +UnsignedConstant(struct node** pnd;) + : UnsignedNumber(pnd) + | STRING + { + *pnd = MkLeaf(Value, &dot); + if (((*pnd)->nd_type = toktype) != char_type) + RomString(*pnd); + } + | ConstantIdentifier(pnd) + | NIL + { + *pnd = MkLeaf(Value, &dot); + (*pnd)->nd_type = nil_type; + /* to evaluate NIL = NIL */ + (*pnd)->nd_INT = 0; + } + ; -UnsignedConstant(struct node **pnd;): - UnsignedNumber(pnd) -| - STRING { *pnd = MkLeaf(Value, &dot); - if( ((*pnd)->nd_type = toktype) != char_type ) - RomString(*pnd); - } -| - ConstantIdentifier(pnd) -| - NIL { *pnd = MkLeaf(Value, &dot); - (*pnd)->nd_type = nil_type; - /* to evaluate NIL = NIL */ - (*pnd)->nd_INT = 0; - } -; +SetConstructor(struct node** pnd;) + { + register struct node* nd; + } + : '[' + { + dot.tk_symb = SET; + *pnd = nd = MkLeaf(Xset, &dot); + } + [ + MemberDesignator(nd) + [ + %persistent + { nd = nd->nd_right; } + ',' + MemberDesignator(nd) + ]* + ]? + ']' + ; -SetConstructor(struct node **pnd;) -{ - register struct node *nd; -} : - '[' { dot.tk_symb = SET; - *pnd = nd = MkLeaf(Xset, &dot); - } - [ - MemberDesignator(nd) - [ %persistent - { nd = nd->nd_right; } - ',' MemberDesignator(nd) - ]* - ]? - ']' -; - -MemberDesignator(struct node *nd;) -{ - struct node *nd1; -} : - Expression(&nd1) - [ UPTO { nd1 = MkNode(Link, nd1, NULLNODE, &dot); } - Expression(&(nd1->nd_right)) - ]? - { nd->nd_right = MkNode(Link, nd1, NULLNODE, &dot); - nd->nd_right->nd_symb = ','; - } -; +MemberDesignator(struct node* nd;) + { + struct node* nd1; + } + : Expression(&nd1) + [ + UPTO + { nd1 = MkNode(Link, nd1, NULLNODE, &dot); } + Expression(&(nd1->nd_right)) + ]? + { + nd->nd_right = MkNode(Link, nd1, NULLNODE, &dot); + nd->nd_right->nd_symb = ','; + } + ; /* ISO section 6.7.2.1, p. 123 */ -BooleanExpression(struct node **pnd;): - Expression(pnd) - { if( ChkExpression(*pnd) && - (*pnd)->nd_type != bool_type ) - node_error(*pnd, "boolean expression expected"); - MarkUsed(*pnd); - } -; +BooleanExpression(struct node** pnd;) + : Expression(pnd) + { + if (ChkExpression(*pnd) && (*pnd)->nd_type != bool_type) + node_error(*pnd, "boolean expression expected"); + MarkUsed(*pnd); + } + ; -ActualParameterList(struct node **pnd;) -{ - register struct node *nd; -} : - '(' - /* ActualParameter substituted inline */ - Expression(pnd) { *pnd = nd = - MkNode(Link, *pnd, NULLNODE, &dot); - nd->nd_symb = ','; - } - [ %persistent - ',' { nd->nd_right = MkLeaf(Link, &dot); - nd = nd->nd_right; - } - Expression(&(nd->nd_left)) - ]* - ')' -; +ActualParameterList(struct node** pnd;) + { + register struct node* nd; + } + : '(' + /* ActualParameter substituted inline */ + Expression(pnd) + { + *pnd = nd = MkNode(Link, *pnd, NULLNODE, &dot); + nd->nd_symb = ','; + } + [ + %persistent + ',' + { + nd->nd_right = MkLeaf(Link, &dot); + nd = nd->nd_right; + } + Expression(&(nd->nd_left)) + ]* + ')' + ; /* ISO section 6.5.1, p. 105 */ -VariableAccess(struct node **pnd;): - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - * - * IDENT is an EntireVariable or - * a FieldDesignatorIdentifier (see also 6.8.3.10, p. 132). - */ - IDENT { *pnd = MkLeaf(Name, &dot); } - VariableAccessTail(pnd) { (void) ChkVariable(*pnd); } -; +VariableAccess(struct node** pnd;) + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + * + * IDENT is an EntireVariable or + * a FieldDesignatorIdentifier (see also 6.8.3.10, p. 132). + */ + IDENT + { *pnd = MkLeaf(Name, &dot); } + VariableAccessTail(pnd) + { (void)ChkVariable(*pnd); } + ; -VariableAccessTail(struct node **pnd;): - /* This is a new rule because the grammar specified by the standard - * is not exactly LL(1). - */ +VariableAccessTail(struct node** pnd;) + : + /* This is a new rule because the grammar specified by the standard + * is not exactly LL(1). + */ - /* empty */ -| - /* PointerVariable or FileVariable - */ + /* empty */ + | + /* PointerVariable or FileVariable + */ - '^' { *pnd = MkNode(Arrow, NULLNODE, *pnd, &dot); } + '^' + { *pnd = MkNode(Arrow, NULLNODE, *pnd, &dot); } - /* At this point the VariableAccess is an IdentifiedVariable - * ISO section 6.5.4, p. 107 (IdentifiedVariable: PointerVariable '^'), - * or - * it is a BufferVariable - * ISO section 6.5.5, p. 107 (BufferVariable: FileVariable '^'). - */ + /* At this point the VariableAccess is an IdentifiedVariable + * ISO section 6.5.4, p. 107 (IdentifiedVariable: PointerVariable '^'), + * or + * it is a BufferVariable + * ISO section 6.5.5, p. 107 (BufferVariable: FileVariable '^'). + */ - VariableAccessTail(pnd) -| - /* ArrayVariable - */ + VariableAccessTail(pnd) + | + /* ArrayVariable + */ - '[' { *pnd = MkNode(Arrsel, *pnd, NULLNODE, &dot); } - /* IndexExpression substituted inline */ - Expression(&((*pnd)->nd_right)) - [ %persistent - ',' { *pnd = MkNode(Arrsel, *pnd, NULLNODE, &dot); - (*pnd)->nd_symb = '['; - } - Expression(&((*pnd)->nd_right)) - ]* - ']' + '[' + { *pnd = MkNode(Arrsel, *pnd, NULLNODE, &dot); } + /* IndexExpression substituted inline */ + Expression(&((*pnd)->nd_right)) + [ + %persistent + ',' + { + *pnd = MkNode(Arrsel, *pnd, NULLNODE, &dot); + (*pnd)->nd_symb = '['; + } + Expression(&((*pnd)->nd_right)) + ]* + ']' - /* At this point the VariableAccess is an IndexedVariable - * ISO section 6.5.3.2, p. 106 - */ + /* At this point the VariableAccess is an IndexedVariable + * ISO section 6.5.3.2, p. 106 + */ - VariableAccessTail(pnd) -| - /* RecordVariable - */ + VariableAccessTail(pnd) + | + /* RecordVariable + */ - '.' { *pnd = MkNode(Link, *pnd, NULLNODE, &dot); } - /* FieldSpecifier & FieldIdentifier substituted inline */ - IDENT { (*pnd)->nd_IDF = dot.TOK_IDF; } + '.' + { *pnd = MkNode(Link, *pnd, NULLNODE, &dot); } + /* FieldSpecifier & FieldIdentifier substituted inline */ + IDENT + { (*pnd)->nd_IDF = dot.TOK_IDF; } - /* At this point the VariableAccess is a FieldDesignator - * ISO section 6.5.3.3, p. 107 - */ + /* At this point the VariableAccess is a FieldDesignator + * ISO section 6.5.3.3, p. 107 + */ - VariableAccessTail(pnd) -; + VariableAccessTail(pnd) + ; diff --git a/lang/pc/comp/program.g b/lang/pc/comp/program.g index 1d17a780a..9c19da9d3 100644 --- a/lang/pc/comp/program.g +++ b/lang/pc/comp/program.g @@ -1,82 +1,91 @@ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/pc/comp/program.g + */ + /* The grammar of ISO-Pascal as given by the specification, BS6192: 1982. */ { -#include "parameters.h" -#include -#include -#include -#include -#include + #include "parameters.h" + #include + #include + #include + #include + #include -#include "LLlex.h" -#include "def.h" -#include "f_info.h" -#include "idf.h" -#include "main.h" -#include "node.h" -#include "scope.h" -#include "enter.h" -#include "progs.h" -#ifdef DBSYMTAB -#include "stab.h" -#endif + #include "LLlex.h" + #include "def.h" + #include "f_info.h" + #include "idf.h" + #include "main.h" + #include "node.h" + #include "scope.h" + #include "enter.h" + #include "progs.h" + #ifdef DBSYMTAB + #include "stab.h" + #endif } %lexical LLlex; - %start LLparse, Program; /* ISO section 6.10, p. 137 */ Program -{ - struct def *df; - arith dummy; -}: - ProgramHeading(&df) - ';' Block(df) '.' - { -#ifdef DBSYMTAB - if (options['g']) { - C_ms_stb_cst(df->df_idf->id_text, N_MAIN, 0, (arith) 0); - stb_string(df, D_END); - } -#endif /* DBSYMTAB */ - } - | { df = new_def(); - df->df_idf = str2idf(FileName, 1); - df->df_kind = D_MODULE; - open_scope(); - GlobalScope = CurrentScope; - df->prc_vis = CurrVis; - } + { + struct def* df; + arith dummy; + } + : ProgramHeading(&df) + ';' + Block(df) + '.' + { + #ifdef DBSYMTAB + if (options['g']) + { + C_ms_stb_cst(df->df_idf->id_text, N_MAIN, 0, (arith)0); + stb_string(df, D_END); + } + #endif /* DBSYMTAB */ + } + | + { + df = new_def(); + df->df_idf = str2idf(FileName, 1); + df->df_kind = D_MODULE; + open_scope(); + GlobalScope = CurrentScope; + df->prc_vis = CurrVis; + } + Module(df, &dummy) + ; - Module(df, &dummy) -; - -ProgramHeading(struct def **df;): - PROGRAM IDENT - { program = *df = new_def(); - (*df)->df_idf = dot.TOK_IDF; - (*df)->df_kind = D_PROGRAM; - open_scope(); - GlobalScope = CurrentScope; - (*df)->prc_vis = CurrVis; -#ifdef DBSYMTAB - if (options['g']) stb_string(*df, D_MODULE); -#endif /* DBSYMTAB */ - } - [ - '(' - ProgramParameters - ')' - { make_extfl(); } - ]? -; +ProgramHeading(struct def** df;) + : PROGRAM IDENT + { + program = *df = new_def(); + (*df)->df_idf = dot.TOK_IDF; + (*df)->df_kind = D_PROGRAM; + open_scope(); + GlobalScope = CurrentScope; + (*df)->prc_vis = CurrVis; + #ifdef DBSYMTAB + if (options['g']) + stb_string(*df, D_MODULE); + #endif /* DBSYMTAB */ + } + [ + '(' ProgramParameters ')' + { make_extfl(); } + ]? + ; ProgramParameters -{ - struct node *Proglist; -}: - IdentifierList(&Proglist) - { EnterProgList(Proglist); } -; + { + struct node* Proglist; + } + : IdentifierList(&Proglist) + { EnterProgList(Proglist); } + ; diff --git a/lang/pc/comp/statement.g b/lang/pc/comp/statement.g index 7f2eef18f..a2dba4ca5 100644 --- a/lang/pc/comp/statement.g +++ b/lang/pc/comp/statement.g @@ -1,483 +1,532 @@ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i lang/pc/comp/statement.g + */ + /* S T A T E M E N T S */ { -#include -#include "parameters.h" -#include -#include -#include - -#include "LLlex.h" -#include "chk_expr.h" -#include "def.h" -#include "desig.h" -#include "f_info.h" -#include "idf.h" -#include "main.h" -#include "misc.h" -#include "node.h" -#include "scope.h" -#include "type.h" -#include "body.h" -#include "code.h" -#include "error.h" -#include "readwrite.h" -#include "casestat.h" -#include "tmpvar.h" -#include "label.h" - -int slevel = 0; /* nesting level of statements */ + #include + #include "parameters.h" + #include + #include + #include + + #include "LLlex.h" + #include "chk_expr.h" + #include "def.h" + #include "desig.h" + #include "f_info.h" + #include "idf.h" + #include "main.h" + #include "misc.h" + #include "node.h" + #include "scope.h" + #include "type.h" + #include "body.h" + #include "code.h" + #include "error.h" + #include "readwrite.h" + #include "casestat.h" + #include "tmpvar.h" + #include "label.h" + + int slevel = 0; /* nesting level of statements */ } /* ISO section 6.8.3.2, p. 128 */ -CompoundStatement: - BEGIN StatementSequence END -; +CompoundStatement + : BEGIN StatementSequence END + ; /* ISO section 6.8.3.1, p. 128 */ -StatementSequence: - Statement - [ %persistent - ';' Statement - ]* - { chk_labels(slevel + 1); } -; +StatementSequence + : Statement + [ + %persistent + ';' Statement + ]* + { chk_labels(slevel + 1); } + ; /* ISO section 6.8.1, p. 126 */ Statement -{ - struct node *nd; -} : - { - slevel++; - } - [ Label(&nd) ':' - { if( nd ) DefLabel(nd, slevel); } - ]? - { if( !options['L'] ) - C_lin((arith) dot.tk_lineno); -#ifdef DBSYMTAB - if (options['g']) { - static int ms_lineno; - - if (ms_lineno != dot.tk_lineno) { - C_ms_std((char *) 0, N_SLINE, (int) dot.tk_lineno); - ms_lineno = dot.tk_lineno; - } - } -#endif /* DBSYMTAB */ - } - [ - SimpleStatement - | - StructuredStatement - ] - { slevel--; } -; + { + struct node* nd; + } + : + { slevel++; } + [ + Label(&nd) + ':' + { if (nd) DefLabel(nd, slevel); } + ]? + { + if (!options['L']) + C_lin((arith)dot.tk_lineno); + #ifdef DBSYMTAB + if (options['g']) + { + static int ms_lineno; + + if (ms_lineno != dot.tk_lineno) + { + C_ms_std((char*)0, N_SLINE, (int)dot.tk_lineno); + ms_lineno = dot.tk_lineno; + } + } + #endif /* DBSYMTAB */ + } + [ + SimpleStatement + | StructuredStatement + ] + { slevel--; } + ; /* ISO section 6.8.2.1, p. 126 */ SimpleStatement -{ - struct node *pnd, *expp; - unsigned short line; -} : - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - * Note : the grammar states : AssignmentStatement | - * ProcedureStatement | ... - * In order to add assertions, there is an extra entry, which gives - * a conflict. This conflict is then resolved using an %if clause. - */ - EmptyStatement -| - GotoStatement -| - /* Evidently this is the beginning of the changed part - */ - %if( !options['s'] && !strcmp(dot.TOK_IDF->id_text, "assert") ) - IDENT { line = LineNumber; } - Expression(&expp) - { AssertStat(expp, line); - FreeNode(expp); - } -| - IDENT { pnd = MkLeaf(Name, &dot); } - [ %default - - /* At this point the IDENT can be a FunctionIdentifier in - * which case the VariableAccessTail must be empty. - */ - VariableAccessTail(&pnd) - [ - %default - BECOMES - | - '=' { error("':=' expected instead of '='"); } - ] - Expression(&expp) - { AssignStat(pnd, expp); } - | - { pnd = MkNode(Call, pnd, NULLNODE, &dot); } - ActualParameterList(&(pnd->nd_right))? - { ProcStat(pnd); - - if( !err_occurred ) - CodeCall(pnd); - - FreeNode(pnd); - } - - ] -| - InputOutputStatement - /* end of changed part - */ -; + { + struct node *pnd, *expp; + unsigned short line; + } + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + * Note : the grammar states : AssignmentStatement | + * ProcedureStatement | ... + * In order to add assertions, there is an extra entry, which gives + * a conflict. This conflict is then resolved using an %if clause. + */ + EmptyStatement + | GotoStatement + | + /* Evidently this is the beginning of the changed part + */ + %if (!options['s'] && !strcmp(dot.TOK_IDF->id_text, "assert")) + IDENT + { line = LineNumber; } + Expression(&expp) + { + AssertStat(expp, line); + FreeNode(expp); + } + | IDENT + { pnd = MkLeaf(Name, &dot); } + [ + %default + + /* At this point the IDENT can be a FunctionIdentifier in + * which case the VariableAccessTail must be empty. + */ + VariableAccessTail(&pnd) + [ + %default + BECOMES + | '=' + { error("':=' expected instead of '='"); } + ] + Expression(&expp) + { AssignStat(pnd, expp); } + | + { pnd = MkNode(Call, pnd, NULLNODE, &dot); } + ActualParameterList(&(pnd->nd_right))? + { + ProcStat(pnd); + + if (!err_occurred) + CodeCall(pnd); + + FreeNode(pnd); + } + ] + | InputOutputStatement + /* end of changed part + */ + ; InputOutputStatement -{ - struct node *nd = NULLNODE; -} : - /* This is a new rule because the grammar specified by the standard - * is not exactly LL(1) (see SimpleStatement). - */ - [ - READ ReadParameterList(&nd) { ChkRead(nd); } - | - READLN ReadParameterList(&nd)? { ChkReadln(nd); } - | - WRITE WriteParameterList(&nd) { ChkWrite(nd); } - | - WRITELN WriteParameterList(&nd)? { ChkWriteln(nd); } - ] - { FreeNode(nd); } -; - -EmptyStatement: - /* empty */ -; + { + struct node* nd = NULLNODE; + } + : + /* This is a new rule because the grammar specified by the standard + * is not exactly LL(1) (see SimpleStatement). + */ + [ + READ + ReadParameterList(&nd) + { ChkRead(nd); } + | READLN + ReadParameterList(&nd)? + { ChkReadln(nd); } + | WRITE + WriteParameterList(&nd) + { ChkWrite(nd); } + | WRITELN + WriteParameterList(&nd)? + { ChkWriteln(nd); } + ] + { FreeNode(nd); } + ; + +EmptyStatement + : + /* empty */ + ; /* ISO section 6.8.3.1, p. 128 */ -StructuredStatement: - CompoundStatement -| - ConditionalStatement -| - RepetitiveStatement -| - WithStatement -; +StructuredStatement + : CompoundStatement + | ConditionalStatement + | RepetitiveStatement + | WithStatement + ; /* ISO section 6.8.2.4, p. 127 */ GotoStatement -{ - struct node *nd; -} : - GOTO Label(&nd) - { if( nd ) TstLabel(nd, slevel); } -; + { + struct node* nd; + } + : GOTO + Label(&nd) + { if (nd) TstLabel(nd, slevel); } + ; /* ISO section 6.8.3.3, p. 128 */ -ConditionalStatement: - %default - CaseStatement -| - IfStatement -; +ConditionalStatement + : %default + CaseStatement + | IfStatement + ; /* ISO section 6.8.3.6, p. 129 */ -RepetitiveStatement: - RepeatStatement -| - WhileStatement -| - ForStatement -; +RepetitiveStatement + : RepeatStatement + | WhileStatement + | ForStatement + ; /* ISO section 6.8.3.10, p. 132 */ WithStatement -{ - struct scopelist *Save = CurrVis; - struct node *nd; -} : - WITH - RecordVariableList(&nd) - DO - Statement { EndWith(Save, nd); - chk_labels(slevel + 1); - } -; - -RecordVariableList(struct node **pnd;) -{ - struct node *nd; -} : - RecordVariable(&nd) - { *pnd = nd = MkNode(Link, nd, NULLNODE, &dot); - nd->nd_symb = ','; - } - [ %persistent - ',' { nd->nd_right = MkLeaf(Link, &dot); - nd = nd->nd_right; - } - RecordVariable(&(nd->nd_left)) - ]* -; - -RecordVariable(struct node **pnd;): - VariableAccess(pnd) - { WithStat(*pnd); } -; + { + struct scopelist* Save = CurrVis; + struct node* nd; + } + : WITH + RecordVariableList(&nd) + DO Statement + { + EndWith(Save, nd); + chk_labels(slevel + 1); + } + ; + +RecordVariableList(struct node** pnd;) + { + struct node* nd; + } + : RecordVariable(&nd) + { + *pnd = nd = MkNode(Link, nd, NULLNODE, &dot); + nd->nd_symb = ','; + } + [ + %persistent + ',' + { + nd->nd_right = MkLeaf(Link, &dot); + nd = nd->nd_right; + } + RecordVariable(&(nd->nd_left)) + ]* + ; + +RecordVariable(struct node** pnd;) + : VariableAccess(pnd) + { WithStat(*pnd); } + ; /* ISO section 6.8.3.4, p. 128 */ IfStatement -{ - struct node *nd; - label l1 = ++text_label; - label l2 = ++text_label; -} : - IF - BooleanExpression(&nd) - { struct desig ds; - - ds = InitDesig; - if( !err_occurred ) - CodeExpr(nd, &ds, l1); - FreeNode(nd); - } - THEN - Statement { chk_labels(slevel + 1); } - [ %prefer /* closest matching */ - ELSE - { C_bra(l2); - C_df_ilb(l1); - } - Statement - { C_df_ilb(l2); - chk_labels(slevel + 1); - } - | - /* empty */ - { C_df_ilb(l1); } - ] -; + { + struct node* nd; + label l1 = ++text_label; + label l2 = ++text_label; + } + : IF + BooleanExpression(&nd) + { + struct desig ds; + + ds = InitDesig; + if (!err_occurred) + CodeExpr(nd, &ds, l1); + FreeNode(nd); + } + THEN Statement + { chk_labels(slevel + 1); } + [ + %prefer + /* closest matching */ + ELSE + { + C_bra(l2); + C_df_ilb(l1); + } + Statement + { + C_df_ilb(l2); + chk_labels(slevel + 1); + } + | + /* empty */ + { C_df_ilb(l1); } + ] + ; /* ISO section 6.8.3.5, p. 128 */ CaseStatement -{ - struct node *casend, *nd; - label exit_label; -} : - /* This is a changed rule, because the grammar as specified in the - * reference states that a semicolon is optional before END, - * and this is not LL(1). - */ - CASE { casend = nd = MkLeaf(Link, &dot); - casend->nd_lab = ++text_label; - exit_label = ++text_label; - } - Expression(&(nd->nd_left)) - { CaseExpr(casend); } - OF - CaseListElement(&(nd->nd_right), exit_label) - { nd = nd->nd_right; } - CaseListElementTail(&(nd->nd_right), exit_label) - END - { CaseEnd(casend, exit_label); } -; - -CaseListElementTail(struct node **pnd; label exit_label;): - /* This is a new rule, all because of a silly semicolon - */ - /* empty */ -| -%default - ';' - [ - /* empty */ - | - CaseListElement(pnd, exit_label) - CaseListElementTail(&((*pnd)->nd_right), exit_label) - ] -; - -CaseListElement(struct node **pnd; label exit_label;): - CaseConstantList(pnd) - ':' - { *pnd = MkNode(Link, *pnd, NULLNODE, &dot); - (*pnd)->nd_lab = ++text_label; - C_df_ilb(text_label); - } - Statement { C_bra(exit_label); - chk_labels(slevel + 1); - } -; + { + struct node *casend, *nd; + label exit_label; + } + : + /* This is a changed rule, because the grammar as specified in the + * reference states that a semicolon is optional before END, + * and this is not LL(1). + */ + CASE + { + casend = nd = MkLeaf(Link, &dot); + casend->nd_lab = ++text_label; + exit_label = ++text_label; + } + Expression(&(nd->nd_left)) + { CaseExpr(casend); } + OF + CaseListElement(&(nd->nd_right), exit_label) + { nd = nd->nd_right; } + CaseListElementTail(&(nd->nd_right), exit_label) + END + { CaseEnd(casend, exit_label); } + ; + +CaseListElementTail(struct node** pnd; label exit_label;) + : + /* This is a new rule, all because of a silly semicolon + */ + /* empty */ + | %default + ';' + [ + /* empty */ + | CaseListElement(pnd, exit_label) + CaseListElementTail(&((*pnd)->nd_right), exit_label) + ] + ; + +CaseListElement(struct node** pnd; label exit_label;) + : CaseConstantList(pnd) + ':' + { + *pnd = MkNode(Link, *pnd, NULLNODE, &dot); + (*pnd)->nd_lab = ++text_label; + C_df_ilb(text_label); + } + Statement + { + C_bra(exit_label); + chk_labels(slevel + 1); + } + ; /* ISO section 6.8.3.7, p. 129 */ RepeatStatement -{ - struct node *nd; - label repeatlb = ++text_label; -} : - REPEAT - { C_df_ilb(repeatlb); } - StatementSequence - UNTIL - BooleanExpression(&nd) - { struct desig ds; - - ds = InitDesig; - if( !err_occurred ) - CodeExpr(nd, &ds, repeatlb); - FreeNode(nd); - } -; + { + struct node* nd; + label repeatlb = ++text_label; + } + : REPEAT + { C_df_ilb(repeatlb); } + StatementSequence UNTIL + BooleanExpression(&nd) + { + struct desig ds; + + ds = InitDesig; + if (!err_occurred) + CodeExpr(nd, &ds, repeatlb); + FreeNode(nd); + } + ; /* ISO section 6.8.3.8, p. 129 */ WhileStatement -{ - struct node *nd; - label whilelb = ++text_label; - label exitlb = ++text_label; - -} : - WHILE - { C_df_ilb(whilelb); } - BooleanExpression(&nd) - { struct desig ds; - - ds = InitDesig; - if( !err_occurred ) - CodeExpr(nd, &ds, exitlb); - FreeNode(nd); - } - DO - Statement - { C_bra(whilelb); - C_df_ilb(exitlb); - chk_labels(slevel + 1); - } -; + { + struct node* nd; + label whilelb = ++text_label; + label exitlb = ++text_label; + } + : WHILE + { C_df_ilb(whilelb); } + BooleanExpression(&nd) + { + struct desig ds; + + ds = InitDesig; + if (!err_occurred) + CodeExpr(nd, &ds, exitlb); + FreeNode(nd); + } + DO Statement + { + C_bra(whilelb); + C_df_ilb(exitlb); + chk_labels(slevel + 1); + } + ; /* ISO section 6.8.3.9, p. 130 */ ForStatement -{ - register struct node *nd; - int stepsize; - label l1 = ++text_label; - label l2 = ++text_label; - arith tmp2 = (arith) 0; -} : - FOR - /* ControlVariable must be an EntireVariable */ - IDENT { nd = MkLeaf(Name, &dot); } - BECOMES - Expression(&(nd->nd_left)) - [ - TO { stepsize = 1; } - | - DOWNTO { stepsize = -1; } - ] - Expression(&(nd->nd_right)) - { ChkForStat(nd); - if( !err_occurred ) { - CodePExpr(nd->nd_left); - C_dup(int_size); - tmp2 = CodeInitFor(nd->nd_right, 2); - CodeFor(nd, stepsize, l1, l2); - } - } - DO - Statement - { if( !err_occurred ) - CodeEndFor(nd, stepsize, l1, l2, tmp2); - EndForStat(nd); - chk_labels(slevel + 1); - FreeNode(nd); - if( tmp2 ) FreeInt(tmp2); - } -; + { + register struct node* nd; + int stepsize; + label l1 = ++text_label; + label l2 = ++text_label; + arith tmp2 = (arith)0; + } + : FOR + /* ControlVariable must be an EntireVariable */ + IDENT + { nd = MkLeaf(Name, &dot); } + BECOMES + Expression(&(nd->nd_left)) + [ + TO + { stepsize = 1; } + | DOWNTO + { stepsize = -1; } + ] + Expression(&(nd->nd_right)) + { + ChkForStat(nd); + if (!err_occurred) + { + CodePExpr(nd->nd_left); + C_dup(int_size); + tmp2 = CodeInitFor(nd->nd_right, 2); + CodeFor(nd, stepsize, l1, l2); + } + } + DO Statement + { + if (!err_occurred) + CodeEndFor(nd, stepsize, l1, l2, tmp2); + EndForStat(nd); + chk_labels(slevel + 1); + FreeNode(nd); + if (tmp2) + FreeInt(tmp2); + } + ; /* SPECIALSPECIALSPECIALSPECIALSPECIALSPECIALSPECIALSPECIALSPECIALSPECIAL */ /* ISO section 6.9, p. 132-136 */ -ReadParameterList(struct node **pnd;) -{ - register struct node *nd; -} : - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - */ - '(' - VariableAccess(pnd) /* possibly a FileVariable */ - { *pnd = nd = - MkNode(Link, *pnd, NULLNODE, &dot); - nd->nd_symb = ','; - } - [ %persistent - ',' { nd->nd_right = MkLeaf(Link, &dot); - nd = nd->nd_right; - } - VariableAccess(&(nd->nd_left)) - ]* - ')' -; - -WriteParameterList(struct node **pnd;) -{ - register struct node *nd; -} : - /* This is a changed rule, because the grammar as specified in the - * reference is not LL(1), and this gives conflicts. - */ - '(' - /* Only the first WriteParameter can be a FileVariable !! - */ - WriteParameter(pnd) - { *pnd = nd = - MkNode(Link, *pnd, NULLNODE, &dot); - nd->nd_symb = ','; - } - [ %persistent - ',' { nd->nd_right = MkLeaf(Link, &dot); - nd = nd->nd_right; - } - WriteParameter(&(nd->nd_left)) - ]* - ')' -; - -WriteParameter(struct node **pnd;) -{ - register struct node *nd; -} : - Expression(pnd) - { if( !ChkExpression(*pnd) ) - (*pnd)->nd_type = error_type; - MarkUsed(*pnd); - *pnd = nd = - MkNode(Link, *pnd, NULLNODE, &dot); - nd->nd_symb = ':'; - } - [ - /* Here the first Expression can't be a FileVariable - */ - ':' { nd->nd_right = MkLeaf(Link, &dot); - nd = nd->nd_right; - } - Expression(&(nd->nd_left)) - { if( !ChkExpression(nd->nd_left) ) - nd->nd_left->nd_type = error_type; - MarkUsed(nd->nd_left); - } - [ - ':' { nd->nd_right = MkLeaf(Link, &dot); - nd = nd->nd_right; - } - Expression(&(nd->nd_left)) - { if( !ChkExpression(nd->nd_left) ) - nd->nd_left->nd_type = error_type; - MarkUsed(nd->nd_left); - } - ]? - ]? -; +ReadParameterList(struct node** pnd;) + { + register struct node* nd; + } + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + */ + '(' + VariableAccess(pnd) + /* possibly a FileVariable */ + { + *pnd = nd = MkNode(Link, *pnd, NULLNODE, &dot); + nd->nd_symb = ','; + } + [ + %persistent + ',' + { + nd->nd_right = MkLeaf(Link, &dot); + nd = nd->nd_right; + } + VariableAccess(&(nd->nd_left)) + ]* + ')' + ; + +WriteParameterList(struct node** pnd;) + { + register struct node* nd; + } + : + /* This is a changed rule, because the grammar as specified in the + * reference is not LL(1), and this gives conflicts. + */ + '(' + /* Only the first WriteParameter can be a FileVariable !! + */ + WriteParameter(pnd) + { + *pnd = nd = MkNode(Link, *pnd, NULLNODE, &dot); + nd->nd_symb = ','; + } + [ + %persistent + ',' + { + nd->nd_right = MkLeaf(Link, &dot); + nd = nd->nd_right; + } + WriteParameter(&(nd->nd_left)) + ]* + ')' + ; + +WriteParameter(struct node** pnd;) + { + register struct node* nd; + } + : Expression(pnd) + { + if (!ChkExpression(*pnd)) + (*pnd)->nd_type = error_type; + MarkUsed(*pnd); + *pnd = nd = MkNode(Link, *pnd, NULLNODE, &dot); + nd->nd_symb = ':'; + } + [ + /* Here the first Expression can't be a FileVariable + */ + ':' + { + nd->nd_right = MkLeaf(Link, &dot); + nd = nd->nd_right; + } + Expression(&(nd->nd_left)) + { + if (!ChkExpression(nd->nd_left)) + nd->nd_left->nd_type = error_type; + MarkUsed(nd->nd_left); + } + [ + ':' + { + nd->nd_right = MkLeaf(Link, &dot); + nd = nd->nd_right; + } + Expression(&(nd->nd_left)) + { + if (!ChkExpression(nd->nd_left)) + nd->nd_left->nd_type = error_type; + MarkUsed(nd->nd_left); + } + ]? + ]? + ; diff --git a/modules/src/em_opt/parser.g b/modules/src/em_opt/parser.g index 77d1de002..698ddce50 100644 --- a/modules/src/em_opt/parser.g +++ b/modules/src/em_opt/parser.g @@ -1,509 +1,519 @@ -/* Parser to read optimization patterns of the form: - op1 op2 ... test : action - or - op1 op2 ... : action - and build a program to recognize then */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i modules/src/em_opt/parser.g + */ -%token SFIT, UFIT, ROTATE, PSIZE, WSIZE, DWSIZE, DEFINED, UNDEFINED, SAMESIGN; -%token SAMEEXT, SAMENAM, OFFSET, LOGAND, LOGOR, BITAND, BITOR, XOR; -%token MINUS, PLUS, TIMES, DIV, MOD, EQ, NE, LT, LE, GT, GE, NOT, COMP; -%token LSHIFT, RSHIFT, COMMA, OPCODE, INT, UPLUS, UMINUS, PATARG; +/* Parser to read optimization patterns of the form: +op1 op2 ... test : action +or +op1 op2 ... : action +and build a program to recognize then */ -%start parser, input; +%token SFIT, UFIT, ROTATE, PSIZE, WSIZE, DWSIZE, DEFINED, UNDEFINED, SAMESIGN; +%token SAMEEXT, SAMENAM, OFFSET, LOGAND, LOGOR, BITAND, BITOR, XOR; +%token MINUS, PLUS, TIMES, DIV, MOD, EQ, NE, LT, LE, GT, GE, NOT, COMP; +%token LSHIFT, RSHIFT, COMMA, OPCODE, INT, UPLUS, UMINUS, PATARG; +%start parser, input; { -#ifndef NORCSID -static char rcsidp1[] = "$Id$"; -#endif - -#include "parser.h" -#include "alloc.h" - -#define MAXPRIO 11 - -struct state *states[MAXSTATES]; -struct action *actions[MAXSTATES]; -struct mnems patterns[MAXSTATES]; -int numpatterns = 0; /* Number of patterns */ -int higheststate = 0; /* Highest state yet allocated */ -struct idf *ops; /* Chained list of all ops */ -int maxpattern = 0; -int maxreplacement = 0; -int nerrors = 0; - -static int lencurrpatt; -static int lenthisrepl; -static int currentstate; /* Current state of dfa */ - -extern void back_token(void); -extern void parser(void); - -/* Forward declarations */ -void addaction(int, int, struct exp_node *,struct exp_node *, - struct mnem_list *); -struct mnem_elem **constructlist(struct mnem_list *, int); -struct mnem_list *addelem(struct mnem_list *, struct idf *, - struct exp_node *); -int dotransition(int, struct idf *, struct mnem_list *, int); -int priority(int); -void LLmessage(int); - + #ifndef NORCSID + static char rcsidp1[] = "$Id$"; + #endif + + #include "parser.h" + #include "alloc.h" + + #define MAXPRIO 11 + + struct state* states[MAXSTATES]; + struct action* actions[MAXSTATES]; + struct mnems patterns[MAXSTATES]; + int numpatterns = 0; /* Number of patterns */ + int higheststate = 0; /* Highest state yet allocated */ + struct idf* ops; /* Chained list of all ops */ + int maxpattern = 0; + int maxreplacement = 0; + int nerrors = 0; + + static int lencurrpatt; + static int lenthisrepl; + static int currentstate; /* Current state of dfa */ + + extern void back_token(void); + extern void parser(void); + + /* Forward declarations */ + void addaction(int, int, struct exp_node*, struct exp_node*, struct mnem_list*); + struct mnem_elem** constructlist(struct mnem_list*, int); + struct mnem_list* addelem(struct mnem_list*, struct idf*, struct exp_node*); + int dotransition(int, struct idf*, struct mnem_list*, int); + int priority(int); + void LLmessage(int); } -input : /* empty */ - | optimization input - ; +input + : + /* empty */ + | optimization input + ; optimization - { - int startline; - struct exp_node *restrictions; - struct exp_node *finaltest; - struct mnem_list *repllist; - } - : - { - startline=linenum; currentstate=0; - lencurrpatt=0; lenthisrepl=0; - } - patterns(&restrictions) - { finaltest = (struct exp_node *)NULL; } - [ - '?' - exp(1,&finaltest) - ]? - ':' - action(&repllist) - { - numpatterns++; - addaction(startline,currentstate,restrictions, - finaltest,repllist); - } - '\n' - ; - -patterns(struct exp_node **tests;) - { - struct mnem_list *list; - struct exp_node *onetest; - } - : - { - list = (struct mnem_list *)NULL; - *tests = (struct exp_node *)NULL; - } - [ - OPCODE - { - if(++lencurrpatt>maxpattern) - maxpattern=lencurrpatt; - list = addelem(list,opval, (struct exp_node *)NULL); - opval->id_used=1; - if(lencurrpatt==1) - opval->id_startpatt=1; - currentstate=dotransition(currentstate,opval,list,lencurrpatt); - } - [ - restriction(opval->id_argfmt,&onetest) - { - *tests = combinetests(*tests,onetest); - } - ]? - ]+ - ; - -restriction(int argtype; struct exp_node **test;) - { - struct exp_node *test1,*test2; - int relop; - int offsetop; - } - : - [ %if(argtype==CSTOPT) - [ optrelop(&relop) exp(1,test) - { - *test = mknode(relop,mkleaf(PATARG,lencurrpatt),*test); - } - | DEFINED - { - *test = mkleaf(DEFINED,lencurrpatt); - } - | UNDEFINED - { - *test = mkleaf(UNDEFINED,lencurrpatt); - } - ] - | %if(argtype==EXT) - patarg(&test1) - { - *test=mknode(SAMEEXT, - mkleaf(PATARG,lencurrpatt), - test1); - } - [ - [ PLUS - { offsetop = PLUS; } - | MINUS - { offsetop = MINUS; } - ] - exp(1,&test2) - { - test2 = mknode(offsetop, test1, test2); - test2 = mknode(EQ, mkleaf(PATARG,lencurrpatt), test2); - *test = combinetests( - mknode(SAMENAM, - mkleaf(PATARG,lencurrpatt), - test1), - test2); - } - ]? - | - optrelop(&relop) exp(1,test) - { - *test = mknode(relop,mkleaf(PATARG,lencurrpatt),*test); - } - ] - ; - -optrelop(int *op;) - : - {*op = EQ;} - [ EQ {*op = EQ;} - | NE {*op = NE;} - | LT {*op = LT;} - | LE {*op = LE;} - | GT {*op = GT;} - | GE {*op = GE;} - ]? - ; -action(struct mnem_list **list;) - { - struct exp_node *test, *test2; - struct idf *keepopval; - int offsetop; - } - : - { *list = (struct mnem_list *)NULL; } - [ - OPCODE - { - if(++lenthisrepl>maxreplacement) - maxreplacement = lenthisrepl; - test= (struct exp_node *)NULL; - keepopval = opval; - } - [ %if(keepopval->id_argfmt==EXT) - patarg(&test) - { - test2 = test; - } - [ - [ PLUS - { offsetop = PLUS; } - | MINUS - { offsetop = MINUS; } - ] - exp(1,&test2) - { - test2 = mknode(offsetop,test,test2); - } - - ]? - { - test = mknode(COMMA,test,test2); - } - | exp(1,&test) - ]? - { - *list = addelem(*list,keepopval,test); - } - ]* - ; - -exp(int level; struct exp_node **result;) - { struct exp_node *res1, *res2; - int operator; } - : - %if(level <= MAXPRIO) - exp(MAXPRIO+1,&res1) - [ %while (priority(LLsymb) >= level) - binop - { - operator=LLsymb; - } - exp(priority(operator)+1,&res2) - { - res1 = mknode(operator,res1,res2); - } - ]* - { - *result = res1; - } - | '(' exp(1,result) ')' - | unaryop(&operator) exp(priority(operator)+1,&res1) - { - *result = mknode(operator,res1,(struct exp_node *)NULL); - } - | SAMESIGN '(' exp(1,&res1) COMMA exp(1,&res2) ')' - { - *result = mknode(SAMESIGN,res1,res2); - } - | SFIT '(' exp(1,&res1) COMMA exp(1,&res2) ')' - { - *result = mknode(SFIT,res1,res2); - } - | UFIT '(' exp(1,&res1) COMMA exp(1,&res2) ')' - { - *result = mknode(UFIT,res1,res2); - } - | ROTATE '(' exp(1,&res1) COMMA exp(1,&res2) ')' - { - *result = mknode(ROTATE,res1,res2); - } - | SAMEEXT '(' patarg(&res1) COMMA patarg(&res2) ')' - { - *result = mknode(SAMEEXT,res1,res2); - } - | SAMENAM '(' patarg(&res1) COMMA patarg(&res2) ')' - { - *result = mknode(SAMENAM,res1,res2); - } - | OFFSET '(' patarg(&res1) ')' - { - *result = res1; - } - | patarg(result) - | PSIZE - { - *result = mkleaf(PSIZE,0); - } - | WSIZE - { - *result = mkleaf(WSIZE,0); - } - | DWSIZE - { - *result = mkleaf(DWSIZE,0); - } - | INT - { - *result = mkleaf(INT,lastintval); - } - ; - -patarg(struct exp_node **result;) - { int intval; } - : PATARG argno(&intval) - { - *result = mkleaf(PATARG,intval); - } - ; - -argno(int *val;) - : INT - { - *val = lastintval; - if(lastintval<0 || (lastintval>lencurrpatt)) { - fprintf(stderr ,"Illegal $%d on line %d\n", - lastintval,linenum); - nerrors++; - } - } - ; - -unaryop(int *operator;) - : PLUS { *operator = UPLUS; } - | MINUS { *operator = UMINUS; } - | NOT { *operator = NOT; } - | COMP { *operator = COMP; } - ; - -binop : LOGAND - | LOGOR - | BITAND - | BITOR - | XOR - | MINUS - | PLUS - | TIMES - | DIV - | MOD - | EQ - | NE - | LT - | LE - | GT - | GE - | LSHIFT - | RSHIFT - ; + { + int startline; + struct exp_node* restrictions; + struct exp_node* finaltest; + struct mnem_list* repllist; + } + : + { + startline = linenum; + currentstate = 0; + lencurrpatt = 0; + lenthisrepl = 0; + } + patterns(&restrictions) + { finaltest = (struct exp_node*)NULL; } + [ + '?' + exp(1, &finaltest) + ]? + ':' + action(&repllist) + { + numpatterns++; + addaction(startline, currentstate, restrictions, finaltest, repllist); + } + '\n' + ; + +patterns(struct exp_node** tests;) + { + struct mnem_list* list; + struct exp_node* onetest; + } + : + { + list = (struct mnem_list*)NULL; + *tests = (struct exp_node*)NULL; + } + [ + OPCODE + { + if (++lencurrpatt > maxpattern) + maxpattern = lencurrpatt; + list = addelem(list, opval, (struct exp_node*)NULL); + opval->id_used = 1; + if (lencurrpatt == 1) + opval->id_startpatt = 1; + currentstate = dotransition(currentstate, opval, list, lencurrpatt); + } + [ + restriction(opval->id_argfmt, &onetest) + { *tests = combinetests(*tests, onetest); } + ]? + ]+ + ; + +restriction(int argtype; struct exp_node** test;) + { + struct exp_node *test1, *test2; + int relop; + int offsetop; + } + : [ + %if (argtype == CSTOPT) + [ + optrelop(&relop) + exp(1, test) + { *test = mknode(relop, mkleaf(PATARG, lencurrpatt), *test); } + | DEFINED + { *test = mkleaf(DEFINED, lencurrpatt); } + | UNDEFINED + { *test = mkleaf(UNDEFINED, lencurrpatt); } + ] + | %if (argtype == EXT) + patarg(&test1) + { *test = mknode(SAMEEXT, mkleaf(PATARG, lencurrpatt), test1); } + [ + [ + PLUS + { offsetop = PLUS; } + | MINUS + { offsetop = MINUS; } + ] + exp(1, &test2) + { + test2 = mknode(offsetop, test1, test2); + test2 = mknode(EQ, mkleaf(PATARG, lencurrpatt), test2); + *test + = combinetests(mknode(SAMENAM, mkleaf(PATARG, lencurrpatt), test1), test2); + } + ]? + | optrelop(&relop) + exp(1, test) + { *test = mknode(relop, mkleaf(PATARG, lencurrpatt), *test); } + ] + ; + +optrelop(int* op;) + : + { *op = EQ; } + [ + EQ + { *op = EQ; } + | NE + { *op = NE; } + | LT + { *op = LT; } + | LE + { *op = LE; } + | GT + { *op = GT; } + | GE + { *op = GE; } + ]? + ; + +action(struct mnem_list** list;) + { + struct exp_node *test, *test2; + struct idf* keepopval; + int offsetop; + } + : + { *list = (struct mnem_list*)NULL; } + [ + OPCODE + { + if (++lenthisrepl > maxreplacement) + maxreplacement = lenthisrepl; + test = (struct exp_node*)NULL; + keepopval = opval; + } + [ + %if (keepopval->id_argfmt == EXT) + patarg(&test) + { test2 = test; } + [ + [ + PLUS + { offsetop = PLUS; } + | MINUS + { offsetop = MINUS; } + ] + exp(1, &test2) + { test2 = mknode(offsetop, test, test2); } + ]? + { test = mknode(COMMA, test, test2); } + | exp(1, &test) + ]? + { *list = addelem(*list, keepopval, test); } + ]* + ; + +exp(int level; struct exp_node** result;) + { + struct exp_node *res1, *res2; + int operator; + } + : %if (level <= MAXPRIO) + exp(MAXPRIO + 1, &res1) + [ + %while (priority(LLsymb) >= level) + binop + { operator= LLsymb; } + exp(priority(operator) + 1, &res2) + { res1 = mknode(operator, res1, res2); } + ]* + { *result = res1; } + | '(' + exp(1, result) + ')' + | unaryop(&operator) + exp(priority(operator) + 1, &res1) + { *result = mknode(operator, res1, (struct exp_node*)NULL); } + | SAMESIGN '(' + exp(1, &res1) + COMMA + exp(1, &res2) + ')' + { *result = mknode(SAMESIGN, res1, res2); } + | SFIT '(' + exp(1, &res1) + COMMA + exp(1, &res2) + ')' + { *result = mknode(SFIT, res1, res2); } + | UFIT '(' + exp(1, &res1) + COMMA + exp(1, &res2) + ')' + { *result = mknode(UFIT, res1, res2); } + | ROTATE '(' + exp(1, &res1) + COMMA + exp(1, &res2) + ')' + { *result = mknode(ROTATE, res1, res2); } + | SAMEEXT '(' + patarg(&res1) + COMMA + patarg(&res2) + ')' + { *result = mknode(SAMEEXT, res1, res2); } + | SAMENAM '(' + patarg(&res1) + COMMA + patarg(&res2) + ')' + { *result = mknode(SAMENAM, res1, res2); } + | OFFSET '(' + patarg(&res1) + ')' + { *result = res1; } + | patarg(result) + | PSIZE + { *result = mkleaf(PSIZE, 0); } + | WSIZE + { *result = mkleaf(WSIZE, 0); } + | DWSIZE + { *result = mkleaf(DWSIZE, 0); } + | INT + { *result = mkleaf(INT, lastintval); } + ; + +patarg(struct exp_node** result;) + { + int intval; + } + : PATARG + argno(&intval) + { *result = mkleaf(PATARG, intval); } + ; + +argno(int* val;) + : INT + { + *val = lastintval; + if (lastintval < 0 || (lastintval > lencurrpatt)) + { + fprintf(stderr, "Illegal $%d on line %d\n", lastintval, linenum); + nerrors++; + } + } + ; + +unaryop(int* operator;) + : PLUS + { *operator= UPLUS; } + | MINUS + { *operator= UMINUS; } + | NOT + { *operator= NOT; } + | COMP + { *operator= COMP; } + ; + +binop + : LOGAND + | LOGOR + | BITAND + | BITOR + | XOR + | MINUS + | PLUS + | TIMES + | DIV + | MOD + | EQ + | NE + | LT + | LE + | GT + | GE + | LSHIFT + | RSHIFT + ; %lexical yylex; { -void addaction(int startline, int state, struct exp_node *restrictions, - struct exp_node *finaltest, struct mnem_list *repllist) -{ - struct action *p, *q; - p=(struct action *)malloc(sizeof(struct action)); - p->next = (struct action *)NULL; - p->linenum = startline; - p->test = combinetests(restrictions,finaltest); - p->replacement.m_len = lenthisrepl; - p->replacement.m_elems = constructlist(repllist,lenthisrepl); - /* chain new action to END of action chain */ - if((q = actions[state])==(struct action *)NULL) - actions[state] = p; - else { - while(q->next != (struct action *)NULL) - q = q->next; - q->next = p; - } -} - -struct mnem_elem **constructlist(struct mnem_list *list, int len) -{ - struct mnem_elem **p; - p = (struct mnem_elem **) - malloc((unsigned)(len*sizeof(struct mnem_elem *))); - while(len--) { - p[len] = list->elem; - list = list->next; - } - return(p); -} - -struct mnem_list *addelem(struct mnem_list *oldlist, - struct idf *mnem, - struct exp_node *test) -{ - struct mnem_list *reslist; - struct mnem_elem *element; - element = (struct mnem_elem *)malloc(sizeof(struct mnem_elem)); - element->op_code = mnem; - element->arg = test; - reslist = (struct mnem_list *)malloc(sizeof(struct mnem_list)); - reslist->elem = element; - reslist->next = oldlist; - return(reslist); -} - -int dotransition( - int state, - struct idf *mnem, - struct mnem_list *mnem_list, - int lenlist) -{ - struct state *p; - /* look for existing transition */ - for(p=states[state]; - (p!=((struct state *)NULL)) && ((p->op)!=mnem); - p = p->next - ); - if(p==(struct state *)NULL) { - /* none found so add a new state to dfa */ - p=(struct state *)malloc(sizeof(struct state)); - p->op=mnem; - if(++higheststate>MAXSTATES) { - fprintf(stderr,"Parser: More than %d states\n",MAXSTATES); - exit(1); - } - p->goto_state= higheststate; - p->next=states[currentstate]; - states[currentstate]=p; - states[higheststate] = (struct state *)NULL; - actions[higheststate] = (struct action *)NULL; - patterns[higheststate].m_len = lencurrpatt; - patterns[higheststate].m_elems = - constructlist(mnem_list,lenlist); - return(higheststate); - } - else return(p->goto_state); /* already exists */ -} - -struct exp_node * -combinetests(test1, test2) - struct exp_node *test1, *test2; -{ - if(test1==(struct exp_node *)NULL) - return(test2); - else if(test2==(struct exp_node *)NULL) - return(test1); - else - return(mknode(LOGAND,test1,test2)); -} - -int priority(int op) { - switch (op) { - case LOGOR: return(1); - case LOGAND: return(2); - case BITOR: return(3); - case XOR: return(4); - case BITAND: return(5); - case EQ: - case NE: return(6); - case LT: - case LE: - case GT: - case GE: return(7); - case LSHIFT: - case RSHIFT: return(8); - case MINUS: - case PLUS: return(9); - case TIMES: - case DIV: - case MOD: return(10); - case NOT: - case COMP: - case UPLUS: - case UMINUS: return(11); - } - fprintf(stderr,"Internal error: priority: - unrecognized operator\n"); - return(0); -} - -struct exp_node *mknode(int op, struct exp_node *left, - struct exp_node *right) -{ - struct exp_node *p; - p = (struct exp_node *)malloc(sizeof(struct exp_node)); - p->node_type = op; - p->exp_left = left; - p->exp_right = right; - return(p); -} - -struct exp_node *mkleaf(int op, int val) -{ - struct exp_node *p; - p = (struct exp_node *)malloc(sizeof(struct exp_node)); - p->node_type = op; - p->leaf_val = val; - return(p); -} - -void LLmessage(int insertedtok) -{ - nerrors++; - fprintf(stderr,"parser: syntax error on line %d: ",linenum); - if(insertedtok) { - fprintf(stderr,"Inserted token %d\n",insertedtok); - back_token(); - } - else fprintf(stderr,"Deleted token %d\n",LLsymb); -} - -int main(int argc, char **argv) -{ - initlex(); - states[0] = (struct state *)NULL; - patterns[0].m_len = 0; - parser(); - if(nerrors) { - fprintf(stderr,"%d errors detected\n",nerrors); - exit(1); - } - outputnopt(); - exit(0); -} + void addaction(int startline, + int state, + struct exp_node* restrictions, + struct exp_node* finaltest, + struct mnem_list* repllist) + { + struct action *p, *q; + p = (struct action*)malloc(sizeof(struct action)); + p->next = (struct action*)NULL; + p->linenum = startline; + p->test = combinetests(restrictions, finaltest); + p->replacement.m_len = lenthisrepl; + p->replacement.m_elems = constructlist(repllist, lenthisrepl); + /* chain new action to END of action chain */ + if ((q = actions[state]) == (struct action*)NULL) + actions[state] = p; + else + { + while (q->next != (struct action*)NULL) + q = q->next; + q->next = p; + } + } + + struct mnem_elem** constructlist(struct mnem_list* list, int len) + { + struct mnem_elem** p; + p = (struct mnem_elem**)malloc((unsigned)(len * sizeof(struct mnem_elem*))); + while (len--) + { + p[len] = list->elem; + list = list->next; + } + return (p); + } + + struct mnem_list* addelem(struct mnem_list* oldlist, struct idf* mnem, struct exp_node* test) + { + struct mnem_list* reslist; + struct mnem_elem* element; + element = (struct mnem_elem*)malloc(sizeof(struct mnem_elem)); + element->op_code = mnem; + element->arg = test; + reslist = (struct mnem_list*)malloc(sizeof(struct mnem_list)); + reslist->elem = element; + reslist->next = oldlist; + return (reslist); + } + + int dotransition(int state, struct idf* mnem, struct mnem_list* mnem_list, int lenlist) + { + struct state* p; + /* look for existing transition */ + for (p = states[state]; (p != ((struct state*)NULL)) && ((p->op) != mnem); p = p->next) + ; + if (p == (struct state*)NULL) + { + /* none found so add a new state to dfa */ + p = (struct state*)malloc(sizeof(struct state)); + p->op = mnem; + if (++higheststate > MAXSTATES) + { + fprintf(stderr, "Parser: More than %d states\n", MAXSTATES); + exit(1); + } + p->goto_state = higheststate; + p->next = states[currentstate]; + states[currentstate] = p; + states[higheststate] = (struct state*)NULL; + actions[higheststate] = (struct action*)NULL; + patterns[higheststate].m_len = lencurrpatt; + patterns[higheststate].m_elems = constructlist(mnem_list, lenlist); + return (higheststate); + } + else + return (p->goto_state); /* already exists */ + } + + struct exp_node *combinetests(test1, test2) struct exp_node *test1, *test2; + { + if (test1 == (struct exp_node*)NULL) + return (test2); + else if (test2 == (struct exp_node*)NULL) + return (test1); + else + return (mknode(LOGAND, test1, test2)); + } + + int priority(int op) + { + switch (op) + { + case LOGOR: + return (1); + case LOGAND: + return (2); + case BITOR: + return (3); + case XOR: + return (4); + case BITAND: + return (5); + case EQ: + case NE: + return (6); + case LT: + case LE: + case GT: + case GE: + return (7); + case LSHIFT: + case RSHIFT: + return (8); + case MINUS: + case PLUS: + return (9); + case TIMES: + case DIV: + case MOD: + return (10); + case NOT: + case COMP: + case UPLUS: + case UMINUS: + return (11); + } + fprintf(stderr, "Internal error: priority: - unrecognized operator\n"); + return (0); + } + + struct exp_node* mknode(int op, struct exp_node* left, struct exp_node* right) + { + struct exp_node* p; + p = (struct exp_node*)malloc(sizeof(struct exp_node)); + p->node_type = op; + p->exp_left = left; + p->exp_right = right; + return (p); + } + + struct exp_node* mkleaf(int op, int val) + { + struct exp_node* p; + p = (struct exp_node*)malloc(sizeof(struct exp_node)); + p->node_type = op; + p->leaf_val = val; + return (p); + } + + void LLmessage(int insertedtok) + { + nerrors++; + fprintf(stderr, "parser: syntax error on line %d: ", linenum); + if (insertedtok) + { + fprintf(stderr, "Inserted token %d\n", insertedtok); + back_token(); + } + else + fprintf(stderr, "Deleted token %d\n", LLsymb); + } + + int main(int argc, char** argv) + { + initlex(); + states[0] = (struct state*)NULL; + patterns[0].m_len = 0; + parser(); + if (nerrors) + { + fprintf(stderr, "%d errors detected\n", nerrors); + exit(1); + } + outputnopt(); + exit(0); + } } diff --git a/util/LLgen/formatter.py b/util/LLgen/formatter.py new file mode 100644 index 000000000..5e770d4c0 --- /dev/null +++ b/util/LLgen/formatter.py @@ -0,0 +1,787 @@ +#!/usr/bin/env python3 +"""LLgen formatter using clang-format for embedded C and grammar comments. + +Run ``python3 util/LLgen/formatter.py file.g [file.g ...]`` to write formatted LLgen to +stdout. Embedded C and grammar comments use the project's .clang-format. +clang-format must be on PATH. +--tree prints the syntax tree +as JSON; --tokens also includes whitespace and grammar comments. +Files are formatted independently in argument order. Use --inplace / -i to +update each input file instead of writing to stdout. + +parse(source) returns a Document with an immutable token stream and a syntax +tree. Token offsets are Python string offsets; node ranges are half-open token +indices. Every source character belongs to a token, including trailing trivia. +C fragments include their delimiters and are deliberately not parsed as C. +""" + +import argparse +from dataclasses import asdict, dataclass +import json +from pathlib import Path +import re +import subprocess +import sys + + +@dataclass(frozen=True) +class Token: + kind: str + text: str + start: int + end: int + + +@dataclass(frozen=True) +class Node: + kind: str + start: int + end: int + children: tuple = () + + +@dataclass(frozen=True) +class Document: + source: str + tokens: tuple + tree: Node + + def text(self, node): + """Return the original spelling of a node, including internal trivia.""" + return ''.join(t.text for t in self.tokens[node.start:node.end]) + + def reconstruct(self): + return ''.join(t.text for t in self.tokens) + + +class ParseError(ValueError): + def __init__(self, source, offset, message): + self.offset = offset + self.line = source.count('\n', 0, offset) + 1 + self.column = offset - source.rfind('\n', 0, offset) + super().__init__(f'{self.line}:{self.column}: {message}') + + +class Lexer: + def __init__(self, source): + self.source = source + self.pos = 0 + + def fail(self, offset, message): + raise ParseError(self.source, offset, message) + + def quoted(self): + start = self.pos + quote = self.source[self.pos] + self.pos += 1 + while self.pos < len(self.source): + ch = self.source[self.pos] + self.pos += 1 + if ch == quote: + return + if ch == '\\': + self.pos += 1 + elif ch in '\r\n': + self.fail(start, 'newline in quoted literal') + self.fail(start, 'unterminated quoted literal') + + def comment(self): + start = self.pos + if self.source.startswith('/*', start): + end = self.source.find('*/', start + 2) + if end < 0: + self.fail(start, 'unterminated comment') + self.pos = end + 2 + else: + # Include continued lines in C // comments. + self.pos += 2 + while self.pos < len(self.source): + if self.source.startswith('\\\r\n', self.pos): + self.pos += 3 + elif self.source.startswith('\\\n', self.pos): + self.pos += 2 + elif self.source[self.pos] in '\r\n': + break + else: + self.pos += 1 + + def c_fragment(self): + """Match nested C delimiters, ignoring those in comments/literals.""" + stack = [] + pairs = {'{': '}', '(': ')', '[': ']'} + while self.pos < len(self.source): + ch = self.source[self.pos] + if self.source.startswith(('/*', '//'), self.pos): + self.comment() + continue + if ch in "\"'": + self.quoted() + continue + if ch in pairs: + stack.append((pairs[ch], self.pos)) + elif ch in '})]': + if ch != stack[-1][0]: + self.fail(self.pos, f'expected {stack[-1][0]!r}, found {ch!r}') + stack.pop() + if not stack: + self.pos += 1 + return + self.pos += 1 + expected, start = stack[-1] + self.fail(start, f'unterminated C fragment; expected {expected!r}') + + def scan(self): + tokens = [] + while self.pos < len(self.source): + start = self.pos + ch = self.source[start] + if ch.isspace(): + kind = 'whitespace' + while self.pos < len(self.source) and self.source[self.pos].isspace(): + self.pos += 1 + elif self.source.startswith(('/*', '//'), start): + kind = 'comment' + self.comment() + elif ch in '{(': + kind = 'c_block' if ch == '{' else 'c_parens' + self.c_fragment() + elif ch == "'": + kind = 'literal' + self.quoted() + elif ch == '#' and not self.source[self.source.rfind('\n', 0, start) + 1:start].strip(): + kind = 'line_directive' + end = self.source.find('\n', start) + self.pos = len(self.source) if end < 0 else end + else: + match = re.match(r'%?[A-Za-z_][A-Za-z_0-9]*|[0-9]+', self.source[start:]) + if match: + text = match.group() + kind = 'directive' if text.startswith('%') else 'number' if text.isdigit() else 'identifier' + self.pos += len(text) + elif ch in ':;|[]*+?,': + kind = ch + self.pos += 1 + else: + self.fail(start, f'unexpected character {ch!r}') + tokens.append(Token(kind, self.source[start:self.pos], start, self.pos)) + return tuple(tokens) + + +class Parser: + TRIVIA = {'whitespace', 'comment', 'line_directive'} + + def __init__(self, source): + self.source = source + self.tokens = Lexer(source).scan() + self.pos = 0 + + def peek(self): + while self.pos < len(self.tokens) and self.tokens[self.pos].kind in self.TRIVIA: + self.pos += 1 + return self.tokens[self.pos] if self.pos < len(self.tokens) else Token('eof', '', len(self.source), len(self.source)) + + def at(self, value): + t = self.peek() + return t.kind == value or (value.startswith('%') and t.text.lower() == value) + + def take(self, value): + t = self.peek() + if not self.at(value): + raise ParseError(self.source, t.start, f'expected {value}, found {t.text!r}' if t.text else f'expected {value}, found end of file') + start = self.pos + self.pos += 1 + return Node(t.kind, start, self.pos) + + def c(self, role, kind): + token = self.take(kind) + return Node(role, token.start, token.end) + + def declaration(self): + start = self.pos + directive = self.peek().text.lower() + self.take('directive') + children = [self.take('identifier')] + if directive in {'%start', '%first'}: + self.take(',') + children.append(self.take('identifier')) + elif directive == '%token': + while self.at(','): + self.take(',') + children.append(self.take('identifier')) + elif directive not in {'%lexical', '%prefix', '%onerror'}: + raise ParseError(self.source, self.tokens[start].start, f'unknown declaration {directive}') + self.take(';') + return Node('declaration', start, self.pos, tuple(children)) + + def rule(self): + start = self.pos + children = [self.take('identifier')] + if self.at('c_parens'): + children.append(self.c('c_parameters', 'c_parens')) + if self.at('c_block'): + children.append(self.c('c_locals', 'c_block')) + self.take(':') + children.append(self.productions()) + self.take(';') + return Node('rule', start, self.pos, tuple(children)) + + def productions(self): + start = self.pos + children = [self.alternative()] + while self.at('|'): + self.take('|') + children.append(self.alternative()) + return Node('alternatives', start, self.pos, tuple(children)) + + def alternative(self): + self.peek() + start = self.pos + children = [] + if self.at('%default'): + children.append(self.take('%default')) + if self.at('%if'): + children.append(self.take('%if')) + children.append(self.c('c_condition', 'c_parens')) + elif self.at('%prefer') or self.at('%avoid'): + children.append(self.take('directive')) + if self.at('%illegal'): + children.append(self.take('%illegal')) + while not any(self.at(k) for k in ('|', ']', ';', 'eof')): + children.append(self.element()) + return Node('alternative', start, self.pos, tuple(children)) + + def element(self): + self.peek() + start = self.pos + children = [] + if self.at('['): + self.take('[') + if self.at('%while'): + children.append(self.take('%while')) + children.append(self.c('c_condition', 'c_parens')) + if self.at('%persistent'): + children.append(self.take('%persistent')) + children.append(self.productions()) + self.take(']') + kind = 'group' + elif self.at('identifier') or self.at('literal') or self.at('%erroneous'): + if self.at('%erroneous'): + children.append(self.take('%erroneous')) + children.append(self.take('literal' if self.at('literal') else 'identifier')) + if self.at('c_parens') and children[-1].kind == 'identifier': + children.append(self.c('c_arguments', 'c_parens')) + kind = 'symbol' + else: + if self.at('%substart'): + children.append(self.take('%substart')) + children.append(self.take('identifier')) + while self.at(','): + self.take(',') + children.append(self.take('identifier')) + self.take(';') + children.append(self.c('c_action', 'c_block')) + kind = 'action' + node = Node(kind, start, self.pos, tuple(children)) + if any(self.at(k) for k in ('*', '+', '?', 'number')): + suffix = self.take(self.peek().kind) + suffixes = [suffix] + if self.tokens[suffix.start].kind in {'*', '+'} and self.at('number'): + suffixes.append(self.take('number')) + node = Node('repeat', start, self.pos, (node, *suffixes)) + return node + + def parse(self): + children = [] + while not self.at('eof'): + if self.at('c_block'): + children.append(self.c('c_global', 'c_block')) + elif self.at('directive'): + children.append(self.declaration()) + else: + children.append(self.rule()) + return Document(self.source, self.tokens, Node('document', 0, len(self.tokens), tuple(children))) + + +def parse(source): + """Parse LLgen syntax without discarding comments or changing C text.""" + return Parser(source).parse() + + +class FormatError(ValueError): + pass + + +def clang_format(source, extra_style=''): + root = Path(__file__).resolve().parents[2] + style = ('{BasedOnStyle: InheritParentConfig, NamespaceIndentation: All, ' + 'IndentPPDirectives: BeforeHash, PPIndentWidth: 4, UseTab: Never, ' + 'FixNamespaceComments: false' + extra_style + '}') + try: + result = subprocess.run( + ['clang-format', f'--style={style}', + f'--assume-filename={root / "llgen-global.cpp"}'], + input=source.encode('utf-8', 'surrogateescape'), + capture_output=True, check=True) + except FileNotFoundError as error: + raise FormatError('clang-format executable not found on PATH') from error + except subprocess.CalledProcessError as error: + message = error.stderr.decode('utf-8', 'replace').strip() + raise FormatError(f'clang-format failed: {message}') from error + return result.stdout.decode('utf-8', 'surrogateescape') + + +def format_global_c(text): + """Use a temporary namespace and conditional to indent code and directives. + + Both wrappers are removed after formatting. clang-format sees the final + indentation while making line-wrapping decisions, including for macros. + """ + wrapped = '#if 1\nnamespace LLgenGlobal\n{\n' + text[1:-1] + '\n}\n#endif\n' + formatted = clang_format(wrapped) + lines = formatted.splitlines(keepends=True) + if ([line.rstrip('\r\n') for line in lines[:3]] != + ['#if 1', 'namespace LLgenGlobal', '{'] or + [line.rstrip('\r\n') for line in lines[-2:]] != ['}', '#endif']): + raise FormatError('clang-format did not preserve the global block wrapper') + content = ''.join(lines[3:-2]).strip('\r\n') + return '{\n' + (content + '\n' if content else '') + '}' + + +def single_c_statement(text): + """Recognize a complete single statement for compact action layout. + + This counts statement boundaries, not semicolons inside delimiters. Unknown + or incomplete constructs stay multiline. Line comments, multiline comments, + continued literals and directives stay multiline to preserve their meaning. + """ + lexer = Lexer(text) + tokens = [] + while lexer.pos < len(text): + ch = text[lexer.pos] + if text.startswith(('//', '\\\n', '\\\r'), lexer.pos) or ch == '#': + return False + if text.startswith('/*', lexer.pos): + start = lexer.pos + lexer.comment() + if '\n' in text[start:lexer.pos] or '\r' in text[start:lexer.pos]: + return False + elif ch.isspace(): + lexer.pos += 1 + elif ch in "\"'": + start = lexer.pos + lexer.quoted() + if '\n' in text[start:lexer.pos] or '\r' in text[start:lexer.pos]: + return False + tokens.append(text[start:lexer.pos]) + else: + match = re.match(r'[A-Za-z_][A-Za-z_0-9]*', text[lexer.pos:]) + token = match.group() if match else ch + tokens.append(token) + lexer.pos += len(token) + + def balanced(pos): + close = {'(': ')', '[': ']', '{': '}'}[tokens[pos]] + pos += 1 + while pos < len(tokens) and tokens[pos] != close: + pos = balanced(pos) if tokens[pos] in {'(', '[', '{'} else pos + 1 + if pos == len(tokens): + raise ValueError('unclosed delimiter') + return pos + 1 + + def statement(pos): + head = tokens[pos] + if head == '{': + return balanced(pos) + if head in {'if', 'for', 'while', 'switch'}: + if tokens[pos + 1] != '(': + raise ValueError('expected condition') + end = statement(balanced(pos + 1)) + if head == 'if' and end < len(tokens) and tokens[end] == 'else': + end = statement(end + 1) + return end + if head == 'do': + end = statement(pos + 1) + if tokens[end:end + 2] != ['while', '(']: + raise ValueError('expected while') + end = balanced(end + 1) + if tokens[end] != ';': + raise ValueError('expected semicolon') + return end + 1 + while pos < len(tokens): + if tokens[pos] == ';': + return pos + 1 + pos = balanced(pos) if tokens[pos] in {'(', '[', '{'} else pos + 1 + raise ValueError('expected statement terminator') + + try: + return bool(tokens) and statement(0) == len(tokens) + except (ValueError, IndexError): + return False + + +def format_actions(actions, *, multiline=()): + """Batch function-scope blocks; indices in multiline keep expanded layout.""" + if not actions: + return {} + wrappers = [] + for index, text, level in actions: + wrappers.append('#if 1\n' + + ''.join(f'namespace LLgenAction{index}_{n}\n{{\n' + for n in range(level)) + + f'void LLgenActionBody{index}()\n{{\n' + + ' ' * (level + 1) + text[1:-1].strip() + '\n}\n' + + '}\n' * level + '#endif\n') + formatted = clang_format(''.join(wrappers)) + result = {} + for index, text, level in actions: + match = re.search(rf'\bvoid LLgenActionBody{index}\(\)\s*\{{', formatted) + if not match: + raise FormatError('clang-format did not preserve the action wrapper') + start = match.end() - 1 + lexer = Lexer(formatted) + lexer.pos = start + lexer.c_fragment() + block = formatted[start:lexer.pos] + if not text[1:-1].strip(): + block = '{}' + elif index not in multiline and single_c_statement(text[1:-1]): + compact = ' '.join(line.strip() for line in block.splitlines()) + if len(compact) + 4 * level <= 100: + block = compact + result[index] = block + return result + + +def format_comments(comments): + """Batch grammar comments at their output indentation, preserving boundaries.""" + if not comments: + return {} + wrappers = [] + for index, text, level in comments: + if text.startswith('/*'): + # Historical comment indentation is unreliable. Give every line + # the surrounding grammar's baseline; clang-format aligns stars. + text = ('\n' + ' ' * level).join( + line.lstrip(' \t') for line in text.splitlines()) + wrappers.append( + ''.join(f'namespace LLgenComment{index}_{n}\n{{\n' for n in range(level)) + + f'int LLgenCommentStart{index};\n\n' + ' ' * level + text + + f'\n\nint LLgenCommentEnd{index};\n' + '}\n' * level) + formatted = clang_format(''.join(wrappers)) + result = {} + for index, _, _ in comments: + match = re.search( + rf'^[ \t]*int LLgenCommentStart{index};\r?\n(.*?)' + rf'^[ \t]*int LLgenCommentEnd{index};', formatted, re.MULTILINE | re.DOTALL) + if not match: + raise FormatError('clang-format did not preserve the comment wrapper') + result[index] = match.group(1).strip('\r\n') + return result + + +def c_top_level(text): + """Yield nontrivia C tokens, treating nested delimiters as opaque tokens.""" + lexer = Lexer(text) + while lexer.pos < len(text): + start = lexer.pos + ch = text[start] + if ch.isspace(): + lexer.pos += 1 + continue + if text.startswith(('/*', '//'), start): + lexer.comment() + continue + if ch in "\"'": + lexer.quoted() + elif ch in '({[': + lexer.c_fragment() + else: + lexer.pos += 1 + yield text[start:lexer.pos], start, lexer.pos + + +def format_parentheses(fragments): + """Batch conditions, actual arguments and LLgen formal parameter lists. + + Dummy names match the emitted prefix width, so clang-format sees the final + opening-parenthesis column. Formal parameters temporarily use C separators. + """ + if not fragments: + return {} + wrappers = [] + metadata = {} + for index, text, role, level, width in fragments: + name = 'P' * max(1, width) + content = text[1:-1] + separators = [] + trailing = False + if role == 'c_parameters': + tokens = list(c_top_level(content)) + trailing = bool(tokens and tokens[-1][0] == ';') + trailing_pos = tokens[-1][1] if trailing else -1 + replacements = [] + for token, start, end in tokens: + if token in {';', ','}: + if start == trailing_pos: + replacements.append((start, end, '')) + else: + separators.append(token) + replacements.append((start, end, ',')) + for start, end, replacement in reversed(replacements): + content = content[:start] + replacement + content[end:] + depth = level if role == 'c_parameters' else max(0, level - 1) + namespaces = ''.join(f'namespace LLgenParen{index}_{n}\n{{\n' + for n in range(depth)) + if role == 'c_parameters': + code = f'void\n{name}({content});\n' + else: + code = f'void LLgenParenBody{index}()\n{{\n{name}({content});\n}}\n' + wrappers.append(f'// LLGEN_PARENS_{index}\n' + namespaces + code + '}\n' * depth) + metadata[index] = (name, separators, trailing) + formatted = clang_format(''.join(wrappers), ', AlwaysBreakAfterReturnType: All') + result = {} + for index, _, role, _, _ in fragments: + name, separators, trailing = metadata[index] + marker = re.search(rf'^\s*// LLGEN_PARENS_{index}\s*$', formatted, re.MULTILINE) + if not marker: + raise FormatError('clang-format did not preserve the parameter wrapper') + match = re.search(rf'\b{name}\s*\(', formatted[marker.end():]) + if not match: + raise FormatError('clang-format did not preserve the parameter wrapper') + start = marker.end() + match.end() - 1 + lexer = Lexer(formatted) + lexer.pos = start + lexer.c_fragment() + content = formatted[start + 1:lexer.pos - 1] + if role == 'c_parameters': + commas = [(a, b) for token, a, b in c_top_level(content) if token == ','] + if len(commas) != len(separators): + raise FormatError('clang-format changed the parameter separators') + for (a, b), separator in reversed(list(zip(commas, separators))): + content = content[:a] + separator + content[b:] + if trailing: + tokens = list(c_top_level(content)) + end = tokens[-1][2] if tokens else 0 + content = content[:end] + ';' + content[end:] + result[index] = '(' + content + ')' + return result + + +class Formatter: + """Lay out grammar tokens using the tree and format C blocks and comments. + + Layout is attached to token indices so comments between syntax nodes are + never lost. Embedded C is represented by a single token; global, local and + action blocks are reformatted. The input Document remains unchanged. + """ + + def __init__(self, document): + self.document = document + self.tokens = document.tokens + self.breaks = {} + self.roles = {} + self.lines = [] + self.line = '' + self.level = 0 + + def significant(self, node): + return [i for i in range(node.start, node.end) + if self.tokens[i].kind not in Parser.TRIVIA] + + def mark(self, index, level, blank=False): + self.breaks[index] = (level, blank) + + def layout(self, node, level=0): + kind = node.kind + indices = self.significant(node) + if kind.startswith('c_'): + self.roles[node.start] = kind + if kind == 'c_action': + self.mark(node.start, level + 1) + if kind == 'document': + previous = None + for child in node.children: + self.layout(child, 0) + self.mark(child.start, 0, previous is not None and + (previous != 'declaration' or child.kind != 'declaration')) + previous = child.kind + return + if kind == 'rule': + colon = next(i for i in indices if self.tokens[i].kind == ':') + self.mark(colon, level + 1) + self.mark(indices[-1], level + 1) + for child in node.children: + self.layout(child, level + 1 if child.kind in {'alternatives', 'c_locals'} else level) + if child.kind == 'c_locals': + self.mark(child.start, level + 1) + return + if kind == 'alternatives': + for i in indices: + if self.tokens[i].kind == '|': + # Nested alternatives will override their own separators. + self.mark(i, level) + for child in node.children: + self.layout(child, level) + return + if kind == 'alternative': + previous_plain = False + for child in node.children: + plain = (child.kind == 'symbol' and len(child.children) == 1 + and child.children[0].kind in {'identifier', 'literal'}) + if child.kind != 'c_condition' and not (plain and previous_plain): + self.mark(child.start, level) + self.layout(child, level) + previous_plain = plain + return + if kind == 'group': + self.mark(indices[-1], level) + for child in node.children: + self.layout(child, level + 1) + if child.kind not in {'alternatives', 'c_condition'}: + self.mark(child.start, level + 1) + return + for child in node.children: + self.layout(child, level) + + def flush(self): + if self.line: + self.lines.append(self.line) + self.line = '' + + def write(self, text, space=True): + if not self.line: + self.line = ' ' * self.level + text + else: + self.line += (' ' if space else '') + text + + def comment_gaps(self): + """Map token boundaries adjoining comments to their blank-line counts.""" + indices = [-1] + [i for i, token in enumerate(self.tokens) + if token.kind != 'whitespace'] + [len(self.tokens)] + gaps = {} + for left, right in zip(indices, indices[1:]): + if not ((left >= 0 and self.tokens[left].kind == 'comment') or + (right < len(self.tokens) and self.tokens[right].kind == 'comment')): + continue + whitespace = ''.join(t.text for t in self.tokens[left + 1:right]) + newlines = len(re.findall(r'\r\n|\r|\n', whitespace)) + gaps[right] = max(0, newlines - (left >= 0)) + return gaps + + def comment_levels(self): + """Assign comments to grammar scopes instead of the previous output line.""" + levels = {i: 0 for i, token in enumerate(self.tokens) if token.kind == 'comment'} + + def visit(node, level): + if node.kind in {'rule', 'group'}: + level += 1 + for i in range(node.start, node.end): + if i in levels: + levels[i] = level + for child in node.children: + visit(child, level) + + visit(self.document.tree, 0) + return levels + + def format(self): + self.layout(self.document.tree) + blocks = format_actions( + [(i, self.tokens[i].text, self.breaks[i][0]) + for i, role in self.roles.items() if role in {'c_action', 'c_locals'}], + multiline={i for i, role in self.roles.items() if role == 'c_locals'}) + comments = format_comments([(i, self.tokens[i].text, level) + for i, level in self.comment_levels().items()]) + comment_gaps = self.comment_gaps() + parentheses = [] + previous = None + for i, token in enumerate(self.tokens): + if token.kind == 'whitespace': + continue + if i in self.breaks: + # Start an alternative beside its introducer. Comments flush + # the line themselves, so none are moved across grammar tokens. + if (self.line.strip() not in {':', '|'} or token.kind in {'|', ']', ';'} + or self.roles.get(i) == 'c_action'): + self.flush() + self.level, blank = self.breaks[i] + if blank and i not in comment_gaps and self.lines and self.lines[-1]: + self.lines.append('') + if i in comment_gaps: + self.flush() + self.lines.extend([''] * comment_gaps[i]) + if token.kind in {'comment', 'line_directive'}: + self.flush() + # Comments are already indented by clang-format. Line directives + # stay at column 1; surrounding blank lines are handled separately. + self.line = comments[i] if token.kind == 'comment' else token.text + self.flush() + previous = None + continue + role = self.roles.get(i) + if role: + if role in {'c_condition', 'c_parameters', 'c_arguments'}: + space = role == 'c_condition' + prefix = self.line.rsplit('\n', 1)[-1].lstrip(' ') + parentheses.append((i, token.text, role, self.level, len(prefix) + space)) + text = f'@@LLGEN_PARENS_{i}@@' + else: + text = (format_global_c(token.text) if role == 'c_global' else blocks[i]) + self.write(text, space=role not in {'c_parameters', 'c_arguments'}) + else: + attach = token.kind in {',', ';', '*', '+', '?'} or ( + token.kind == 'number' and previous in {']', '*', '+', 'identifier', 'literal', 'c_block', 'c_parens'}) + self.write(token.text, space=not attach) + previous = token.kind + self.flush() + self.lines.extend([''] * comment_gaps.get(len(self.tokens), 0)) + output = '\n'.join(self.lines) + ('\n' if self.lines else '') + for index, text in format_parentheses(parentheses).items(): + output = output.replace(f'@@LLGEN_PARENS_{index}@@', text, 1) + return output + + +def format_document(document): + """Format LLgen, grammar comments and all embedded C fragments.""" + return Formatter(document).format() + + +def format_source(source): + return format_document(parse(source)) + + +def main(): + ap = argparse.ArgumentParser(description=__doc__) + ap.add_argument('files', type=Path, nargs='+', metavar='file') + ap.add_argument('--inplace', '-i', action='store_true', help='format each input file in place') + ap.add_argument('--tree', action='store_true', help='print syntax tree instead of source') + ap.add_argument('--tokens', action='store_true', help='include lossless token stream') + args = ap.parse_args() + if args.inplace and (args.tree or args.tokens): + ap.error('--inplace cannot be combined with --tree or --tokens') + status = 0 + for path in args.files: + try: + with path.open(encoding='utf-8', errors='surrogateescape', newline='') as stream: + document = parse(stream.read()) + if not (args.tree or args.tokens): + formatted = format_document(document) + if args.inplace: + if formatted != document.source: + with path.open('w', encoding='utf-8', errors='surrogateescape', newline='') as stream: + stream.write(formatted) + else: + print(formatted, end='') + else: + result = {'tree': asdict(document.tree)} + if args.tokens: + result['tokens'] = [asdict(t) for t in document.tokens] + print(json.dumps(result, indent=2, ensure_ascii=True)) + except (OSError, ParseError, FormatError) as error: + print(f'{path}:{error}', file=sys.stderr) + status = 1 + return status + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/util/LLgen/src/LLgen.g b/util/LLgen/src/LLgen.g index 63bde8902..b96ff5550 100644 --- a/util/LLgen/src/LLgen.g +++ b/util/LLgen/src/LLgen.g @@ -3,6 +3,12 @@ * level of the LLgen tree. */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i util/LLgen/src/LLgen.g + */ + /* * L L G E N * @@ -18,641 +24,759 @@ */ { -#include -#include -#include "types.h" -#include "fileio.h" -#include "extern.h" -#include "assert.h" -#include "cclass.h" - -# ifndef NORCSID -static string rcsid = "$Id$"; -# endif -static int acount; /* count #of global actions */ -static p_term t_list; -static int t_cnt; -static p_gram alt_table; -static int n_alts; -static int max_alts; -#define ALTINCR 32 - -static p_gram rule_table; -static int n_rules; -static int max_rules; -#define RULEINCR 32 - -/* Here are defined : */ -static void newnorder(int index); -static void newtorder(int index); -static void mkalt(p_gram prod, int condition,int lc,register p_gram res); -static void mkterm(p_gram prod, int flags,int lc,register p_gram result); -static p_gram copyrule(p_gram p,int length); -/* and of course LLparse() */ - -static void newnorder(int index) { - static int porder; - - if (norder != -1) { - nonterms[porder].n_next = index; - } - else norder = index; - porder = index; - nonterms[porder].n_next = -1; -} - -static void newtorder(int index) { - static int porder; - - if (torder != -1) { - tokens[porder].t_next = index; - } - else torder = index; - porder = index; - tokens[porder].t_next = -1; -} - -void p_init(void) -{ - alt_table = (p_gram )alloc(ALTINCR*sizeof(t_gram)); - n_alts = 0; - max_alts = ALTINCR; - rule_table = (p_gram )alloc(RULEINCR*sizeof(t_gram)); - n_rules = 0; - max_rules = RULEINCR; + #include + #include + #include "types.h" + #include "fileio.h" + #include "extern.h" + #include "assert.h" + #include "cclass.h" + + #ifndef NORCSID + static string rcsid = "$Id$"; + #endif + static int acount; /* count #of global actions */ + static p_term t_list; + static int t_cnt; + static p_gram alt_table; + static int n_alts; + static int max_alts; + #define ALTINCR 32 + + static p_gram rule_table; + static int n_rules; + static int max_rules; + #define RULEINCR 32 + + /* Here are defined : */ + static void newnorder(int index); + static void newtorder(int index); + static void mkalt(p_gram prod, int condition, int lc, register p_gram res); + static void mkterm(p_gram prod, int flags, int lc, register p_gram result); + static p_gram copyrule(p_gram p, int length); + /* and of course LLparse() */ + + static void newnorder(int index) + { + static int porder; + + if (norder != -1) + { + nonterms[porder].n_next = index; + } + else + norder = index; + porder = index; + nonterms[porder].n_next = -1; + } + + static void newtorder(int index) + { + static int porder; + + if (torder != -1) + { + tokens[porder].t_next = index; + } + else + torder = index; + porder = index; + tokens[porder].t_next = -1; + } + + void p_init(void) + { + alt_table = (p_gram)alloc(ALTINCR * sizeof(t_gram)); + n_alts = 0; + max_alts = ALTINCR; + rule_table = (p_gram)alloc(RULEINCR * sizeof(t_gram)); + n_rules = 0; + max_rules = RULEINCR; + } } -} +%start LLparse, spec; + +spec + : + { + acount = 0; + p_init(); + } + [ + %persistent + def + ]* + { + /* + * Put an endmarker in temporary file + */ + putc('\0', fact); + putc('\0', fact); + free((p_mem)rule_table); + free((p_mem)alt_table); + } + ; + +def + { + register string p; + } + : rule + /* + * A grammar rule + */ + | C_TOKEN listel + [ + ',' listel + ]* + ';' + /* + * A token declaration + */ + | C_START C_IDENT + { p = store(lextoken.t_string); } + ',' C_IDENT + /* + * A start symbol declaration + */ + { + /* + * Put the declaration in the list + * of start symbols + */ + register p_gram temp; + register p_start ff; + + temp = search(NONTERM, lextoken.t_string, BOTH); + ff = (p_start)alloc(sizeof(t_start)); + ff->ff_nont = g_getcont(temp); + ff->ff_name = p; + ff->ff_next = start; + start = ff; + while ((ff = ff->ff_next)) + { + if (!strcmp(p, ff->ff_name)) + { + error(linecount, "\"%s\" already used in a %%start", p); + break; + } + } + } + ';' + | C_LEXICAL C_IDENT + /* + * Declaration of a name for the lexical analyser. + * May appear only once + */ + { + if (!lexical) + { + lexical = store(lextoken.t_string); + } + else + error(linecount, "Duplicate %%lexical", NULL); + } + ';' + | C_PREFIX C_IDENT + /* + * Prefix of external names (default: LL) + */ + { + if (!prefix) + { + prefix = store(lextoken.t_string); + if (strlen(prefix) > 6) + { + error(linecount, "%%prefix too long", NULL); + prefix[6] = 0; + } + } + else + error(linecount, "Duplicate %%prefix", NULL); + } + ';' + | C_ONERROR C_IDENT + { + #ifdef NON_CORRECTING + if (non_corr) + { + warning(linecount, "%%onerror conflicts with -n option", NULL); + } + else + #endif + if (!onerror) + { + onerror = store(lextoken.t_string); + } + else + error(linecount, "Duplicate %%onerror", NULL); + } + ';' + | C_ACTION + { acount++; } + /* + * A global C-declaration + */ + | firsts + /* + * declarations for macros + */ + ; + +listel + : C_IDENT + { + p_gram temp = search(TERMINAL, lextoken.t_string, ENTERING); + newtorder(g_getcont(temp)); + tokens[g_getcont(temp)].t_lineno = linecount; + } + ; + +rule + { + register p_nont p; + p_gram rr; + register p_gram temp; + } + : + /* + * grammar for a production rule + */ + C_IDENT + { + temp = search(NONTERM, lextoken.t_string, BOTH); + p = &nonterms[g_getcont(temp)]; + if (p->n_rule) + { + error(linecount, "Nonterminal %s already defined", lextoken.t_string); + } + /* + * Remember the order in which the nonterminals + * were defined. Code must be generated in that + * order to keep track with the actions on the + * temporary file + */ + newnorder(p - nonterms); + p->n_count = acount; + acount = 0; + p->n_lineno = linecount; + p->n_off = ftell(fact); + } + [ + C_PARAMS + { + if (lextoken.t_num > 0) + { + p->n_flags |= PARAMS; + if (lextoken.t_num > 15) + { + error(linecount, "Too many parameters", NULL); + } + else + setntparams(p, lextoken.t_num); + } + } + ]? + [ + C_ACTION + { p->n_flags |= LOCALS; } + ]? + ':' + { in_production = 1; } + productions(&rr) + ';' + { in_production = 0; } + /* + * Do not use p->n_rule now! The nonterms array + * might have been re-allocated. + */ + { nonterms[g_getcont(temp)].n_rule = rr; } + ; + +productions(p_gram* p;) + /* + * One or more alternatives + */ + { + p_gram prod; + int conflres = 0; + int t = 0; + int haddefault = 0; + int altcnt = 0; + int o_lc, n_lc; + } + : + { o_lc = linecount; } + simpleproduction(p, &conflres) + { if (conflres & DEF) haddefault = 1; } + [ + [ + '|' + { n_lc = linecount; } + simpleproduction(&prod, &t) + { + if (n_alts >= max_alts - 2) + { + alt_table = (p_gram)ralloc((p_mem)alt_table, + (max_alts += ALTINCR) * sizeof(t_gram)); + } + if (t & DEF) + { + if (haddefault) + { + error(n_lc, "More than one %%default in alternation", NULL); + } + haddefault = 1; + } + mkalt(*p, conflres, o_lc, &alt_table[n_alts++]); + altcnt++; + o_lc = n_lc; + conflres = t; + t = 0; + *p = prod; + } + ]+ + { + if (conflres & (COND | PREFERING | AVOIDING)) + { + error(n_lc, "Resolver on last alternative not allowed", NULL); + } + mkalt(*p, conflres, n_lc, &alt_table[n_alts++]); + altcnt++; + g_settype((&alt_table[n_alts]), EORULE); + *p = copyrule(&alt_table[n_alts - altcnt], altcnt + 1); + } + | + { + if (conflres & (COND | PREFERING | AVOIDING)) + { + error(o_lc, "No alternation conflict resolver allowed here", NULL); + } + /* + if (conflres & DEF) { + error(o_lc, + "No %%default allowed here", NULL); + } + */ + } + ] + { n_alts -= altcnt; } + ; -%start LLparse, spec; - -spec : { acount = 0; p_init(); } - [ %persistent def ]* - { /* - * Put an endmarker in temporary file - */ - putc('\0', fact); - putc('\0', fact); - free((p_mem) rule_table); - free((p_mem) alt_table); - } - ; - -def { register string p; } - : rule - /* - * A grammar rule - */ - | C_TOKEN listel [ ',' listel ]* ';' - /* - * A token declaration - */ - | C_START C_IDENT - { p = store(lextoken.t_string); } - ',' C_IDENT - /* - * A start symbol declaration - */ - { /* - * Put the declaration in the list - * of start symbols - */ - register p_gram temp; - register p_start ff; - - temp = search(NONTERM,lextoken.t_string,BOTH); - ff = (p_start) alloc(sizeof(t_start)); - ff->ff_nont = g_getcont(temp); - ff->ff_name = p; - ff->ff_next = start; - start = ff; - while ((ff = ff->ff_next)) { - if (! strcmp(p, ff->ff_name)) { - error(linecount, "\"%s\" already used in a %%start", p); - break; - } - } - } - ';' - | C_LEXICAL C_IDENT - /* - * Declaration of a name for the lexical analyser. - * May appear only once - */ - { if (!lexical) { - lexical = store(lextoken.t_string); - } - else error(linecount,"Duplicate %%lexical", NULL); - } - ';' - | C_PREFIX C_IDENT - /* - * Prefix of external names (default: LL) - */ - { if (!prefix) { - prefix = store(lextoken.t_string); - if (strlen(prefix) > 6) { - error(linecount, - "%%prefix too long",NULL); - prefix[6] = 0; - } - } - else error(linecount,"Duplicate %%prefix", NULL); - } - ';' - | C_ONERROR C_IDENT - { -#ifdef NON_CORRECTING - if (non_corr) { - warning(linecount, "%%onerror conflicts with -n option", NULL); - } - else -#endif - if (! onerror) { - onerror = store(lextoken.t_string); - } - else error(linecount,"Duplicate %%onerror", NULL); - } - ';' - | C_ACTION { acount++; } - /* - * A global C-declaration - */ - | firsts - /* - * declarations for macros - */ - ; - -listel : C_IDENT { p_gram temp = search(TERMINAL,lextoken.t_string,ENTERING); - newtorder(g_getcont(temp)); - tokens[g_getcont(temp)].t_lineno = linecount; - } - ; - -rule { register p_nont p; - p_gram rr; - register p_gram temp; - } - : /* - * grammar for a production rule - */ - C_IDENT { temp = search(NONTERM,lextoken.t_string,BOTH); - p = &nonterms[g_getcont(temp)]; - if (p->n_rule) { - error(linecount, -"Nonterminal %s already defined", lextoken.t_string); - } - /* - * Remember the order in which the nonterminals - * were defined. Code must be generated in that - * order to keep track with the actions on the - * temporary file - */ - newnorder(p - nonterms); - p->n_count = acount; - acount = 0; - p->n_lineno = linecount; - p->n_off = ftell(fact); - } - [ C_PARAMS { if (lextoken.t_num > 0) { - p->n_flags |= PARAMS; - if (lextoken.t_num > 15) { - error(linecount,"Too many parameters", NULL); - } - else setntparams(p,lextoken.t_num); - } - } - ]? - [ C_ACTION { p->n_flags |= LOCALS; } - ]? - ':' { in_production = 1; } - productions(&rr) ';' - { in_production = 0; } - /* - * Do not use p->n_rule now! The nonterms array - * might have been re-allocated. - */ - { nonterms[g_getcont(temp)].n_rule = rr;} - ; - -productions(p_gram *p;) - /* - * One or more alternatives - */ - { p_gram prod; - int conflres = 0; - int t = 0; - int haddefault = 0; - int altcnt = 0; - int o_lc, n_lc; - } : - { o_lc = linecount; } - simpleproduction(p,&conflres) - { if (conflres & DEF) haddefault = 1; } - [ - [ '|' { n_lc = linecount; } - simpleproduction(&prod,&t) - { if (n_alts >= max_alts-2) { - alt_table = (p_gram ) ralloc( - (p_mem) alt_table, - (max_alts+=ALTINCR)*sizeof(t_gram)); - } - if (t & DEF) { - if (haddefault) { - error(n_lc, - "More than one %%default in alternation", NULL); - } - haddefault = 1; - } - mkalt(*p,conflres,o_lc,&alt_table[n_alts++]); - altcnt++; - o_lc = n_lc; - conflres = t; - t = 0; - *p = prod; - } - ]+ { if (conflres & (COND|PREFERING|AVOIDING)) { - error(n_lc, - "Resolver on last alternative not allowed", NULL); - } - mkalt(*p,conflres,n_lc,&alt_table[n_alts++]); - altcnt++; - g_settype((&alt_table[n_alts]),EORULE); - *p = copyrule(&alt_table[n_alts-altcnt],altcnt+1); - } - | - { if (conflres & (COND|PREFERING|AVOIDING)) { - error(o_lc, - "No alternation conflict resolver allowed here", NULL); - } - /* - if (conflres & DEF) { - error(o_lc, - "No %%default allowed here", NULL); - } - */ - } - ] - { n_alts -= altcnt; } - ; { - -static void mkalt(p_gram prod, int condition,int lc,register p_gram res) -{ - /* - * Create an alternation and initialise it. - */ - register p_link l; - static p_link list; - static int cnt; - - if (! cnt) { - cnt = 50; - list = (p_link) alloc(50 * sizeof(t_link)); - } - cnt--; - l = list++; - l->l_rule = prod; - l->l_flag = condition; - g_setlink(res,l); - g_settype(res,ALTERNATION); - res->g_lineno = lc; - nalts++; -} + static void mkalt(p_gram prod, int condition, int lc, register p_gram res) + { + /* + * Create an alternation and initialise it. + */ + register p_link l; + static p_link list; + static int cnt; + + if (!cnt) + { + cnt = 50; + list = (p_link)alloc(50 * sizeof(t_link)); + } + cnt--; + l = list++; + l->l_rule = prod; + l->l_flag = condition; + g_setlink(res, l); + g_settype(res, ALTERNATION); + res->g_lineno = lc; + nalts++; + } } -simpleproduction(p_gram *p; register int *conflres;) - { t_gram elem; - int elmcnt = 0; - int cnt, kind; - int termdeleted = 0; - } : - [ C_DEFAULT { *conflres |= DEF; } - ]? - [ - /* - * Optional conflict reslover - */ - C_IF C_EXPR { *conflres |= COND; } - | C_PREFER { *conflres |= PREFERING; } - | C_AVOID { *conflres |= AVOIDING; } - ]? - [ C_ILLEGAL { -#ifdef NON_CORRECTING - if (n_rules >= max_rules-2) { - rule_table = (p_gram) ralloc( - (p_mem) rule_table, - (max_rules+=RULEINCR)*sizeof(t_gram)); - } - elmcnt++; - rule_table[n_rules++] = - *search(TERMINAL, "LLILLEGAL", BOTH); - if (*conflres & DEF) { - error(linecount, "%%illegal not allowed in %%default rule", NULL); - } -#endif - } - ]? - [ %persistent elem(&elem) - { if (n_rules >= max_rules-2) { - rule_table = (p_gram) ralloc( - (p_mem) rule_table, - (max_rules+=RULEINCR)*sizeof(t_gram)); - } - kind = FIXED; - cnt = 0; - } - [ repeats(&kind, &cnt) - { if (g_gettype(&elem) != TERM) { - rule_table[n_rules] = elem; - g_settype((&rule_table[n_rules+1]),EORULE); - mkterm(copyrule(&rule_table[n_rules],2), - 0, - elem.g_lineno, - &elem); - } - } - | - { if (g_gettype(&elem) == TERM) { - register p_term q = g_getterm(&elem); - - if (! (q->t_flags & RESOLVER) && - g_gettype(q->t_rule) != ALTERNATION && - g_gettype(q->t_rule) != EORULE) { - while (g_gettype(q->t_rule) != EORULE) { - rule_table[n_rules++] = *q->t_rule++; - elmcnt++; - if (n_rules >= max_rules-2) { - rule_table = (p_gram) ralloc( - (p_mem) rule_table, - (max_rules+=RULEINCR)*sizeof(t_gram)); - } - } - elem = *--(q->t_rule); - n_rules--; - elmcnt--; - if (q == t_list - 1) { - t_list--; - nterms--; - t_cnt++; - } - termdeleted = 1; - } - } - } - ] { if (!termdeleted && g_gettype(&elem) == TERM) { - register p_term q; - - q = g_getterm(&elem); - r_setkind(q,kind); - r_setnum(q,cnt); - if ((q->t_flags & RESOLVER) && - (kind == PLUS || kind == FIXED)) { - error(linecount, - "%%while not allowed in this term", NULL); - } - /* - * A persistent fixed term is the same - * as a non-persistent fixed term. - * Should we complain? - if ((q->t_flags & PERSISTENT) && - kind == FIXED) { - error(linecount, - "Illegal %%persistent", NULL); - } - */ - } - termdeleted = 0; - elmcnt++; - rule_table[n_rules++] = elem; - } - ]* { register p_term q; - - g_settype((&rule_table[n_rules]),EORULE); - *p = 0; - n_rules -= elmcnt; - if (g_gettype(&rule_table[n_rules]) == TERM && - elmcnt == 1) { - q = g_getterm(&rule_table[n_rules]); - if (r_getkind(q) == FIXED && - r_getnum(q) == 0) { - *p = q->t_rule; - } - } - if (!*p) *p = copyrule(&rule_table[n_rules], - elmcnt+1); - } - ; -{ +simpleproduction(p_gram* p; register int* conflres;) + { + t_gram elem; + int elmcnt = 0; + int cnt, kind; + int termdeleted = 0; + } + : [ + C_DEFAULT + { *conflres |= DEF; } + ]? + [ + /* + * Optional conflict reslover + */ + C_IF C_EXPR + { *conflres |= COND; } + | C_PREFER + { *conflres |= PREFERING; } + | C_AVOID + { *conflres |= AVOIDING; } + ]? + [ + C_ILLEGAL + { + #ifdef NON_CORRECTING + if (n_rules >= max_rules - 2) + { + rule_table = (p_gram)ralloc((p_mem)rule_table, + (max_rules += RULEINCR) * sizeof(t_gram)); + } + elmcnt++; + rule_table[n_rules++] = *search(TERMINAL, "LLILLEGAL", BOTH); + if (*conflres & DEF) + { + error(linecount, "%%illegal not allowed in %%default rule", NULL); + } + #endif + } + ]? + [ + %persistent + elem(&elem) + { + if (n_rules >= max_rules - 2) + { + rule_table = (p_gram)ralloc((p_mem)rule_table, + (max_rules += RULEINCR) * sizeof(t_gram)); + } + kind = FIXED; + cnt = 0; + } + [ + repeats(&kind, &cnt) + { + if (g_gettype(&elem) != TERM) + { + rule_table[n_rules] = elem; + g_settype((&rule_table[n_rules + 1]), EORULE); + mkterm(copyrule(&rule_table[n_rules], 2), 0, elem.g_lineno, &elem); + } + } + | + { + if (g_gettype(&elem) == TERM) + { + register p_term q = g_getterm(&elem); + + if (!(q->t_flags & RESOLVER) && g_gettype(q->t_rule) != ALTERNATION + && g_gettype(q->t_rule) != EORULE) + { + while (g_gettype(q->t_rule) != EORULE) + { + rule_table[n_rules++] = *q->t_rule++; + elmcnt++; + if (n_rules >= max_rules - 2) + { + rule_table + = (p_gram)ralloc((p_mem)rule_table, + (max_rules += RULEINCR) * sizeof(t_gram)); + } + } + elem = *--(q->t_rule); + n_rules--; + elmcnt--; + if (q == t_list - 1) + { + t_list--; + nterms--; + t_cnt++; + } + termdeleted = 1; + } + } + } + ] + { + if (!termdeleted && g_gettype(&elem) == TERM) + { + register p_term q; + + q = g_getterm(&elem); + r_setkind(q, kind); + r_setnum(q, cnt); + if ((q->t_flags & RESOLVER) && (kind == PLUS || kind == FIXED)) + { + error(linecount, "%%while not allowed in this term", NULL); + } + /* + * A persistent fixed term is the same + * as a non-persistent fixed term. + * Should we complain? + if ((q->t_flags & PERSISTENT) && + kind == FIXED) { + error(linecount, + "Illegal %%persistent", NULL); + } + */ + } + termdeleted = 0; + elmcnt++; + rule_table[n_rules++] = elem; + } + ]* + { + register p_term q; + + g_settype((&rule_table[n_rules]), EORULE); + *p = 0; + n_rules -= elmcnt; + if (g_gettype(&rule_table[n_rules]) == TERM && elmcnt == 1) + { + q = g_getterm(&rule_table[n_rules]); + if (r_getkind(q) == FIXED && r_getnum(q) == 0) + { + *p = q->t_rule; + } + } + if (!*p) + *p = copyrule(&rule_table[n_rules], elmcnt + 1); + } + ; -static void mkterm(p_gram prod, int flags,int lc,register p_gram result) { - /* - * Create a term, initialise it and return - * a grammar element containing it - */ - register p_term q; - - if (! t_cnt) { - t_cnt = 50; - t_list = (p_term) alloc(50 * sizeof(t_term)); - } - t_cnt--; - q = t_list++; - q->t_rule = prod; - q->t_contains = 0; - q->t_flags = flags; - g_settype(result,TERM); - g_setterm(result,q); - result->g_lineno = lc; - nterms++; -} + static void mkterm(p_gram prod, int flags, int lc, register p_gram result) + { + /* + * Create a term, initialise it and return + * a grammar element containing it + */ + register p_term q; + + if (!t_cnt) + { + t_cnt = 50; + t_list = (p_term)alloc(50 * sizeof(t_term)); + } + t_cnt--; + q = t_list++; + q->t_rule = prod; + q->t_contains = 0; + q->t_flags = flags; + g_settype(result, TERM); + g_setterm(result, q); + result->g_lineno = lc; + nterms++; + } } -elem (p_gram pres;) - { register int t = 0; - p_gram p1; - int ln; - p_gram pe; -#ifdef NON_CORRECTING - int erroneous = 0; -#endif - } : - '[' { ln = linecount; } - [ C_WHILE C_EXPR { t |= RESOLVER; } - ]? - [ C_PERSISTENT { t |= PERSISTENT; } - ]? - productions(&p1) - ']' { - mkterm(p1,t,ln,pres); - } - | - [ C_ERRONEOUS { -#ifdef NON_CORRECTING - erroneous = 1; -#endif - } - ]? - - [ - C_IDENT { pe = search(UNKNOWN,lextoken.t_string,BOTH); - *pres = *pe; -#ifdef NON_CORRECTING - if (erroneous) { - if (g_gettype(pres) != TERMINAL){ - warning(linecount, - "Erroneous only allowed on terminal", NULL); - erroneous = 0; - } - else - pres->g_erroneous = 1; - } -#endif - - } - [ C_PARAMS { if (lextoken.t_num > 15) { - error(linecount,"Too many parameters", NULL); - } else g_setnpar(pres,lextoken.t_num); - if (g_gettype(pres) == TERMINAL) { - error(linecount, - "Terminal with parameters", NULL); - } - } - ]? - | C_LITERAL { pe = search(LITERAL,lextoken.t_string,BOTH); - *pres = *pe; -#ifdef NON_CORRECTING - if (erroneous) - pres->g_erroneous = 1; -#endif - } - ] - | { g_settype(pres,ACTION); - pres->g_lineno = linecount; -#ifdef NON_CORRECTING - g_setsubparse(pres, (p_start) 0); -#endif - } - - [ C_SUBSTART - - { -#ifdef NON_CORRECTING - nsubstarts++; -#endif - } - - C_IDENT - { -#ifdef NON_CORRECTING - register p_gram temp; - register p_start subp; - - temp = search(NONTERM,lextoken.t_string,BOTH); - subp = (p_start) alloc (sizeof(t_start)); - - subp->ff_nont = g_getcont(temp); - subp->ff_name = (string) 0; - subp->ff_next = (p_start) 0; - g_setsubparse(pres, subp); -#endif - } - - [ ',' C_IDENT - { -#ifdef NON_CORRECTING - register p_gram temp; - register p_start ff; - - temp = search(NONTERM,lextoken.t_string,BOTH); - - ff = g_getsubparse(pres); - while (ff) { - if (ff->ff_nont == g_getcont(temp)) { - warning(linecount, "\"%s\" used twice in %%substart", lextoken.t_string); - break; - } - ff = ff->ff_next; - - } - - ff = (p_start) alloc(sizeof(t_start)); - ff->ff_nont = g_getcont(temp); - ff->ff_name = (string) 0; - ff->ff_next = g_getsubparse(pres); - g_setsubparse(pres, ff); -#endif - } - - ]* ';' - ]? - - C_ACTION - ; - -repeats(int *kind; int *cnt;) { int t1 = 0; } : - [ - '?' { *kind = OPT; } - | [ '*' { *kind = STAR; } - | '+' { *kind = PLUS; } - ] - number(&t1)? - { if (t1 == 1) { - t1 = 0; - if (*kind == STAR) *kind = OPT; - if (*kind == PLUS) *kind = FIXED; - } - } - | number(&t1) - ] { *cnt = t1; } - ; - -number(int *t;) - : C_NUMBER - { *t = lextoken.t_num; - if (*t <= 0 || *t >= 8192) { - error(linecount,"Illegal number", NULL); - } - } - ; - -firsts { register string p; } - : C_FIRST C_IDENT - { p = store(lextoken.t_string); } - ',' C_IDENT ';' - { /* - * Store this %first in the list belonging - * to this input file - */ - p_gram temp; - register p_first ff; - - temp = search(NONTERM,lextoken.t_string,BOTH); - ff = (p_first) alloc(sizeof(t_first)); - ff->ff_nont = g_getcont(temp); - ff->ff_name = p; - ff->ff_next = pfile->f_firsts; - pfile->f_firsts = ff; - } - ; -{ +elem(p_gram pres;) + { + register int t = 0; + p_gram p1; + int ln; + p_gram pe; + #ifdef NON_CORRECTING + int erroneous = 0; + #endif + } + : '[' + { ln = linecount; } + [ + C_WHILE C_EXPR + { t |= RESOLVER; } + ]? + [ + C_PERSISTENT + { t |= PERSISTENT; } + ]? + productions(&p1) + ']' + { mkterm(p1, t, ln, pres); } + | [ + C_ERRONEOUS + { + #ifdef NON_CORRECTING + erroneous = 1; + #endif + } + ]? + [ + C_IDENT + { + pe = search(UNKNOWN, lextoken.t_string, BOTH); + *pres = *pe; + #ifdef NON_CORRECTING + if (erroneous) + { + if (g_gettype(pres) != TERMINAL) + { + warning(linecount, "Erroneous only allowed on terminal", NULL); + erroneous = 0; + } + else + pres->g_erroneous = 1; + } + #endif + } + [ + C_PARAMS + { + if (lextoken.t_num > 15) + { + error(linecount, "Too many parameters", NULL); + } + else + g_setnpar(pres, lextoken.t_num); + if (g_gettype(pres) == TERMINAL) + { + error(linecount, "Terminal with parameters", NULL); + } + } + ]? + | C_LITERAL + { + pe = search(LITERAL, lextoken.t_string, BOTH); + *pres = *pe; + #ifdef NON_CORRECTING + if (erroneous) + pres->g_erroneous = 1; + #endif + } + ] + | + { + g_settype(pres, ACTION); + pres->g_lineno = linecount; + #ifdef NON_CORRECTING + g_setsubparse(pres, (p_start)0); + #endif + } + [ + C_SUBSTART + { + #ifdef NON_CORRECTING + nsubstarts++; + #endif + } + C_IDENT + { + #ifdef NON_CORRECTING + register p_gram temp; + register p_start subp; + + temp = search(NONTERM, lextoken.t_string, BOTH); + subp = (p_start)alloc(sizeof(t_start)); + + subp->ff_nont = g_getcont(temp); + subp->ff_name = (string)0; + subp->ff_next = (p_start)0; + g_setsubparse(pres, subp); + #endif + } + [ + ',' C_IDENT + { + #ifdef NON_CORRECTING + register p_gram temp; + register p_start ff; + + temp = search(NONTERM, lextoken.t_string, BOTH); + + ff = g_getsubparse(pres); + while (ff) + { + if (ff->ff_nont == g_getcont(temp)) + { + warning(linecount, "\"%s\" used twice in %%substart", + lextoken.t_string); + break; + } + ff = ff->ff_next; + } + + ff = (p_start)alloc(sizeof(t_start)); + ff->ff_nont = g_getcont(temp); + ff->ff_name = (string)0; + ff->ff_next = g_getsubparse(pres); + g_setsubparse(pres, ff); + #endif + } + ]* + ';' + ]? + C_ACTION + ; + +repeats(int* kind; int* cnt;) + { + int t1 = 0; + } + : [ + '?' + { *kind = OPT; } + | [ + '*' + { *kind = STAR; } + | '+' + { *kind = PLUS; } + ] + number(&t1)? + { + if (t1 == 1) + { + t1 = 0; + if (*kind == STAR) + *kind = OPT; + if (*kind == PLUS) + *kind = FIXED; + } + } + | number(&t1) + ] + { *cnt = t1; } + ; + +number(int* t;) + : C_NUMBER + { + *t = lextoken.t_num; + if (*t <= 0 || *t >= 8192) + { + error(linecount, "Illegal number", NULL); + } + } + ; + +firsts + { + register string p; + } + : C_FIRST C_IDENT + { p = store(lextoken.t_string); } + ',' C_IDENT ';' + { + /* + * Store this %first in the list belonging + * to this input file + */ + p_gram temp; + register p_first ff; + + temp = search(NONTERM, lextoken.t_string, BOTH); + ff = (p_first)alloc(sizeof(t_first)); + ff->ff_nont = g_getcont(temp); + ff->ff_name = p; + ff->ff_next = pfile->f_firsts; + pfile->f_firsts = ff; + } + ; -static p_gram copyrule(p_gram p,int length) { - /* - * Returns a pointer to a grammar rule that was created in - * p. The space pointed to by p can now be reused - */ - register p_gram t; - p_gram rule; - - t = (p_gram) alloc(length * sizeof(t_gram)); - rule = t; - while (length--) { - *t++ = *p++; - } - return rule; -} + static p_gram copyrule(p_gram p, int length) + { + /* + * Returns a pointer to a grammar rule that was created in + * p. The space pointed to by p can now be reused + */ + register p_gram t; + p_gram rule; + + t = (p_gram)alloc(length * sizeof(t_gram)); + rule = t; + while (length--) + { + *t++ = *p++; + } + return rule; + } } diff --git a/util/LLgen/src/tokens.g b/util/LLgen/src/tokens.g index db3c59007..74e6e9b7e 100644 --- a/util/LLgen/src/tokens.g +++ b/util/LLgen/src/tokens.g @@ -3,6 +3,12 @@ * level of the LLgen tree. */ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i util/LLgen/src/tokens.g + */ + /* * L L G E N * @@ -18,592 +24,695 @@ */ { -#include -#include "types.h" -# include "fileio.h" -# include "extern.h" -# include "assert.h" -# include "cclass.h" - -# ifndef NORCSID -static string rcsidc = "$Id$"; -# endif - -/* Here are defined : */ -int scanner(void); -void LLmessage(int d); -int input(void); -void unput(int c); -void skipcomment(int flag); -# ifdef LINE_DIRECTIVE -static void linedirective(void); -# endif -static string cpy(int s,register string p,int inserted); -static string vallookup(int s); -static void copyact(char ch1,char ch2,int flag,int level); - -static int nparams; + #include + #include "types.h" + #include "fileio.h" + #include "extern.h" + #include "assert.h" + #include "cclass.h" + + #ifndef NORCSID + static string rcsidc = "$Id$"; + #endif + + /* Here are defined : */ + int scanner(void); + void LLmessage(int d); + int input(void); + void unput(int c); + void skipcomment(int flag); + #ifdef LINE_DIRECTIVE + static void linedirective(void); + #endif + static string cpy(int s, register string p, int inserted); + static string vallookup(int s); + static void copyact(char ch1, char ch2, int flag, int level); + + static int nparams; } /* Classes */ -%token C_IDENT ; /* lextoken.t_string contains the identifier read */ -%token C_NUMBER ; /* lextoken.t_num contains the number read */ -%token C_LITERAL ; /* lextoken.t_string contains the literal read */ -%token C_EXPR ; /* A C expression (%if or %while) */ -%token C_PARAMS ; /* formal or actual parameters */ -%token C_ACTION ; /* a C action */ +%token C_IDENT; +/* lextoken.t_string contains the identifier read */ +%token C_NUMBER; +/* lextoken.t_num contains the number read */ +%token C_LITERAL; +/* lextoken.t_string contains the literal read */ +%token C_EXPR; +/* A C expression (%if or %while) */ +%token C_PARAMS; +/* formal or actual parameters */ +%token C_ACTION; +/* a C action */ /* Keywords */ -%token C_TOKEN ; -%token C_START ; -%token C_IF ; -%token C_WHILE ; -%token C_PERSISTENT ; -%token C_FIRST ; -%token C_LEXICAL ; -%token C_PREFIX ; -%token C_ONERROR ; -%token C_AVOID ; -%token C_PREFER ; -%token C_DEFAULT ; -%token C_SUBSTART ; -%token C_ERRONEOUS ; -%token C_ILLEGAL ; - -%lexical scanner ; - -{ - -/* - * Structure for a keyword - */ - -typedef struct keyword { - string w_word; - int w_value; -} t_keyw, *p_keyw; - -/* - * The list of keywords, the most often used keywords come first. - * Linear search is used, as there are not many keywords - */ - -static t_keyw resword[] = { - { "token", C_TOKEN }, - { "avoid", C_AVOID }, - { "prefer", C_PREFER }, - { "persistent", C_PERSISTENT }, - { "default", C_DEFAULT }, - { "if", C_IF }, - { "while", C_WHILE }, - { "first", C_FIRST }, - { "start", C_START }, - { "lexical", C_LEXICAL }, - { "onerror", C_ONERROR }, - { "prefix", C_PREFIX }, -#ifdef NON_CORRECTING - { "substart", C_SUBSTART }, - { "erroneous", C_ERRONEOUS }, - { "illegal", C_ILLEGAL }, -#endif - { 0, 0 } -}; - -static t_token savedtok; /* to save lextoken in case of an insertion */ -# ifdef LINE_DIRECTIVE -static int nostartline; /* = 0 if at the start of a line */ -# endif - -static void copyact(char ch1,char ch2,int flag,int level) -{ - /* - * Copy an action to file f. Opening bracket is ch1, closing bracket - * is ch2. - * If flag & 1, copy opening and closing parameters too. - * If flag & 2, don't allow ','. - */ - static int text_seen = 0; - register FILE *f; - register int ch; /* Current char */ - register int match; /* used to read strings */ - int saved = linecount; - /* save linecount */ - int sav_strip = strip_grammar; - - f = fact; - if (ch1 == '{' || flag != 1) strip_grammar = 0; - if (!level) { - text_seen = 0; - nparams = 0; /* count comma's */ - putc('\0',f); - fprintf(f,"# line %d \"%s\"\n", linecount,f_input); - } - if (level || (flag & 1)) putc(ch1,f); - for (;;) { - ch = input(); - if (ch == ch2) { - if (!level) { - if (text_seen) nparams++; - } - if (level || (flag & 1)) putc(ch,f); - if (strip_grammar != sav_strip) { - if (ch1 == '{' || flag != 1) putchar(ch); - } - strip_grammar = sav_strip; - return; - } - switch(ch) { - case ')': - case '}': - case ']': - error(linecount,"Parentheses mismatch", NULL); - break; - case '(': - text_seen = 1; - copyact('(',')',flag,level+1); - continue; - case '{': - text_seen = 1; - copyact('{','}',flag,level+1); - continue; - case '[': - text_seen = 1; - copyact('[',']',flag,level+1); - continue; - case '/': - ch = input(); - unput(ch); - if (ch == '*') { - putc('/', f); - skipcomment(1); - continue; - } - ch = '/'; - text_seen = 1; - break; - case ';': - case ',': - if (! level && text_seen) { - text_seen = 0; - nparams++; - if (ch == ',' && (flag & 2)) { - warning(linecount, "Parameters may not be separated with a ','",NULL); - ch = ';'; - } - } - break; - case '\'': - case '"' : - /* - * watch out for brackets in strings, they do not - * count ! - */ - text_seen = 1; - match = ch; - putc(ch,f); - while((ch = input())) { - if (ch == match) break; - if (ch == '\\') { - putc(ch,f); - ch = input(); - } - if (ch == '\n') { - error(linecount,"Newline in string", NULL); - unput(match); - } - putc(ch,f); - } - if (ch == match) break; - /* Fall through */ - case EOF : - if (!level) error(saved,"Action does not terminate", NULL); - strip_grammar = sav_strip; - return; - default: - if (c_class[ch] != ISSPA) text_seen = 1; - } - putc(ch,f); - } -} - -int scanner(void) -{ - /* - * Lexical analyser, what else - */ - register int ch; /* Current char */ - register char *p = ltext; - int reserved = 0; /* reserved word? */ - char *max = <ext[LTEXTSZ - 1]; - static int nextexpr; - int expect_expr = nextexpr; - long off; - - nextexpr = 0; - if (savedtok.t_tokno) { - /* A token has been inserted. - * Now deliver the last lextoken again - */ - lextoken = savedtok; - savedtok.t_tokno = 0; - return lextoken.t_tokno; - } - for (;;) { - ch = input(); - if (ch == EOF) return ch; -# ifdef LINE_DIRECTIVE - if (ch == '#' && !nostartline) { - linedirective(); - continue; - } -# endif - switch(c_class[ch]) { - case ISACT : - if (ch == '{') { - copyact('{', '}', in_production, 0); - return C_ACTION; - } - assert(ch == '('); - if (expect_expr) { - copyact('(', ')', 1, 0); - return C_EXPR; - } - off = ftell(fact); - copyact('(', ')', in_production != 0 ? 0 : 2, 0); - if (nparams == 0) fseek(fact, off, 0); - lextoken.t_num = nparams; - return C_PARAMS; - case ISLIT : - for (;;) { - ch = input(); - if (ch == '\n' || ch == EOF) { - error(linecount,"Missing '", NULL); - break; - } - if (ch == '\'') break; - if (ch == '\\') { - *p++ = ch; - ch = input(); - } - *p++ = ch; - if (p > max) p--; - } - *p = '\0'; - lextoken.t_string = ltext; - return C_LITERAL; - case ISCOM : - skipcomment(0); - /* Fall through */ - case ISSPA : - continue; - case ISDIG : { - register int i = 0; - do { - i = 10 * i + (ch - '0'); - ch= input(); - } while (c_class[ch] == ISDIG); - lextoken.t_num = i; - unput(ch); - return C_NUMBER; } - default: - return ch; - case ISKEY : - reserved = 1; - ch = input(); - /* Fall through */ - case ISLET : - do { - if (reserved && ch >= 'A' && ch <= 'Z') { - ch += 'a' - 'A'; - } - *p++ = ch; - if (p > max) p--; - ch = input(); - } while (c_class[ch] == ISDIG || c_class[ch] == ISLET); - unput(ch); - *p = '\0'; - if (reserved) { /* - * Now search for the keyword - */ - register p_keyw w; - - w = resword; - while (w->w_word) { - if (! strcmp(ltext,w->w_word)) { - /* - * Return token number. - */ - if (w->w_value == C_IF || - w->w_value == C_WHILE) { - nextexpr = 1; - } - return w->w_value; - } - w++; - } - error(linecount,"Illegal reserved word",NULL); - } - lextoken.t_string = ltext; - return C_IDENT; - } - } -} - -static int backupc; /* for unput() */ -static int nonline; /* = 1 if last char read was a newline */ +%token C_TOKEN; +%token C_START; +%token C_IF; +%token C_WHILE; +%token C_PERSISTENT; +%token C_FIRST; +%token C_LEXICAL; +%token C_PREFIX; +%token C_ONERROR; +%token C_AVOID; +%token C_PREFER; +%token C_DEFAULT; +%token C_SUBSTART; +%token C_ERRONEOUS; +%token C_ILLEGAL; +%lexical scanner; -int input(void) { - /* - * Low level input routine, used by all other input routines - */ - register int c; - - if ((c = backupc)) { - /* Last char was "unput()". Deliver it again - */ - backupc = 0; - return c; - } - if ((c = getc(finput)) == EOF) { - nonline = 0; - return c; - } -# ifdef LINE_DIRECTIVE - nostartline = 1; -# endif - if (!nonline) { - linecount++; -# ifdef LINE_DIRECTIVE - nostartline = 0; -# endif - nonline = 1; - } - if (c == '\n') nonline = 0; - if (strip_grammar) putchar(c); - return c; -} - -void unput(int c) -{ - /* - * "unread" c - */ - backupc = c; -} - -void skipcomment(int flag) -{ - /* - * Skip comment. If flag != 0, the comment is inside a fragment - * of C-code, so keep it. - */ - register int ch; - int saved; /* line count on which comment starts */ - - saved = linecount; - if (input() != '*') error(linecount,"Illegal comment",NULL); - if (flag) putc('*', fact); - do { - ch = input(); - if (flag) putc(ch, fact); - while (ch == '*') { - ch = input(); - if (flag) putc(ch, fact); - if (ch == '/') return; - } - } while (ch != EOF); - error(saved,"Comment does not terminate", NULL); -} - -# ifdef LINE_DIRECTIVE -static void linedirective(void) -{ - /* - * Read a line directive - */ - register int ch; - register int i; - string s_error = "Illegal line directive"; - string store(); - register string c; - - do { /* - * Skip to next digit - * Do not skip newlines - */ - ch = input(); - } while (ch != '\n' && c_class[ch] != ISDIG); - if (ch == '\n') { - error(linecount,s_error, NULL); - return; - } - i = 0; - do { - i = i*10 + (ch - '0'); - ch = input(); - } while (c_class[ch] == ISDIG); - while (ch != '\n' && ch != '"') ch = input(); - if (ch == '"') { - c = ltext; - do { - *c++ = ch = input(); - } while (ch != '"' && ch != '\n'); - if (ch == '\n') { - error(linecount,s_error, NULL); - return; - } - *--c = '\0'; - do { - ch = input(); - } while (ch != '\n'); - /* - * Remember the file name - */ - if (strcmp(f_input,ltext)) f_input = store(ltext); - } - linecount = i; -} -# endif - -static string vallookup(int s) -{ - /* - * Look up the keyword that has token number s - */ - register p_keyw p = resword; - - while (p->w_value) { - if (p->w_value == s) return p->w_word; - p++; - } - return 0; -} - -static string cpy(int s,register string p,int inserted) -{ - /* - * Create a piece of error message for token s and put it at p. - * inserted = 0 if the token s was deleted (in which case we have - * attributes), else it was inserted - */ - register string t = 0; - - switch(s) { - case C_IDENT : - if (!inserted) t = lextoken.t_string; - else t = "identifier"; - break; - case C_NUMBER : - t = "number"; - break; - case C_LITERAL : - if (!inserted) { - *p++ = '\''; - t = lextoken.t_string; - break; - } - t = "literal"; - break; - case C_ACTION: - t = "C action"; - break; - case C_PARAMS: - t = "C parameter section"; - break; - case C_EXPR: - t = "C expression"; - break; - case EOFILE : - t = "end-of-file"; - break; - } - if (!t && (t = vallookup(s))) { - *p++ = '%'; - } - if (t) { /* - * We have a string for the token. Copy it - */ - while (*t) *p++ = *t++; - if (s == C_LITERAL && !inserted) { - *p++ = '\''; - } - return p; - } - /* - * The token is a literal - */ - *p++ = '\''; - if (s >= 040 && s <= 0176) *p++ = s; - else { - *p++ = '\\'; - switch(s) { - case '\b' : *p++ = 'b'; break; - case '\f' : *p++ = 'f'; break; - case '\n' : *p++ = 'n'; break; - case '\r' : *p++ = 'r'; break; - case '\t' : *p++ = 't'; break; - default : *p++='0'+((s&0377)>>6); *p++='0'+((s>>3)&07); - *p++='0'+(s&07); - } - } - *p++ = '\''; - return p; -} - - -void LLmessage(int d) -{ - /* - * d is either 0, in which case the current token has been deleted, - * or non-zero, in which case it represents a token that is inserted - * before the current token - */ - register string s,t; - char buf[128]; - - nerrors++; - s = buf; - if (d < 0) { - strcpy(buf, "end-of-file expected"); - } - else if (d == 0) { -#ifdef LLNONCORR - t = " unexpected"; -#else - t = " deleted"; -#endif - s = cpy(LLsymb,s,0); - do *s++ = *t; while (*t++); - } else { - s = cpy(d,s,1); - t = " inserted in front of "; - do *s++ = *t++; while (*t); - s = cpy(LLsymb,s,0); - *s = '\0'; - } - if (d > 0) { /* - * Save the current token and make up some - * attributes for the inserted token - */ - savedtok = lextoken; - savedtok.t_tokno = LLsymb; - if (d == C_IDENT) lextoken.t_string = "dummy_identifier"; - else if (d == C_LITERAL) lextoken.t_string = "dummy_literal"; - else if (d == C_NUMBER) lextoken.t_num = 1; - } -#ifdef LLNONCORR - else -#endif - error(linecount, "%s", buf); - /* Don't change this line to - * error(linecount, buf). - * The string in "buf" might contain '%' ... - */ -#ifdef LLNONCORR - in_production = 1; - /* To prevent warnings from copyact */ -#endif -} + /* + * Structure for a keyword + */ + + typedef struct keyword + { + string w_word; + int w_value; + } t_keyw, *p_keyw; + + /* + * The list of keywords, the most often used keywords come first. + * Linear search is used, as there are not many keywords + */ + + static t_keyw resword[] = { { "token", C_TOKEN }, + { "avoid", C_AVOID }, + { "prefer", C_PREFER }, + { "persistent", C_PERSISTENT }, + { "default", C_DEFAULT }, + { "if", C_IF }, + { "while", C_WHILE }, + { "first", C_FIRST }, + { "start", C_START }, + { "lexical", C_LEXICAL }, + { "onerror", C_ONERROR }, + { "prefix", C_PREFIX }, + #ifdef NON_CORRECTING + { "substart", C_SUBSTART }, + { "erroneous", C_ERRONEOUS }, + { "illegal", C_ILLEGAL }, + #endif + { 0, 0 } }; + + static t_token savedtok; /* to save lextoken in case of an insertion */ + #ifdef LINE_DIRECTIVE + static int nostartline; /* = 0 if at the start of a line */ + #endif + + static void copyact(char ch1, char ch2, int flag, int level) + { + /* + * Copy an action to file f. Opening bracket is ch1, closing bracket + * is ch2. + * If flag & 1, copy opening and closing parameters too. + * If flag & 2, don't allow ','. + */ + static int text_seen = 0; + register FILE* f; + register int ch; /* Current char */ + register int match; /* used to read strings */ + int saved = linecount; + /* save linecount */ + int sav_strip = strip_grammar; + + f = fact; + if (ch1 == '{' || flag != 1) + strip_grammar = 0; + if (!level) + { + text_seen = 0; + nparams = 0; /* count comma's */ + putc('\0', f); + fprintf(f, "# line %d \"%s\"\n", linecount, f_input); + } + if (level || (flag & 1)) + putc(ch1, f); + for (;;) + { + ch = input(); + if (ch == ch2) + { + if (!level) + { + if (text_seen) + nparams++; + } + if (level || (flag & 1)) + putc(ch, f); + if (strip_grammar != sav_strip) + { + if (ch1 == '{' || flag != 1) + putchar(ch); + } + strip_grammar = sav_strip; + return; + } + switch (ch) + { + case ')': + case '}': + case ']': + error(linecount, "Parentheses mismatch", NULL); + break; + case '(': + text_seen = 1; + copyact('(', ')', flag, level + 1); + continue; + case '{': + text_seen = 1; + copyact('{', '}', flag, level + 1); + continue; + case '[': + text_seen = 1; + copyact('[', ']', flag, level + 1); + continue; + case '/': + ch = input(); + unput(ch); + if (ch == '*') + { + putc('/', f); + skipcomment(1); + continue; + } + ch = '/'; + text_seen = 1; + break; + case ';': + case ',': + if (!level && text_seen) + { + text_seen = 0; + nparams++; + if (ch == ',' && (flag & 2)) + { + warning(linecount, "Parameters may not be separated with a ','", NULL); + ch = ';'; + } + } + break; + case '\'': + case '"': + /* + * watch out for brackets in strings, they do not + * count ! + */ + text_seen = 1; + match = ch; + putc(ch, f); + while ((ch = input())) + { + if (ch == match) + break; + if (ch == '\\') + { + putc(ch, f); + ch = input(); + } + if (ch == '\n') + { + error(linecount, "Newline in string", NULL); + unput(match); + } + putc(ch, f); + } + if (ch == match) + break; + /* Fall through */ + case EOF: + if (!level) + error(saved, "Action does not terminate", NULL); + strip_grammar = sav_strip; + return; + default: + if (c_class[ch] != ISSPA) + text_seen = 1; + } + putc(ch, f); + } + } + + int scanner(void) + { + /* + * Lexical analyser, what else + */ + register int ch; /* Current char */ + register char* p = ltext; + int reserved = 0; /* reserved word? */ + char* max = <ext[LTEXTSZ - 1]; + static int nextexpr; + int expect_expr = nextexpr; + long off; + + nextexpr = 0; + if (savedtok.t_tokno) + { + /* A token has been inserted. + * Now deliver the last lextoken again + */ + lextoken = savedtok; + savedtok.t_tokno = 0; + return lextoken.t_tokno; + } + for (;;) + { + ch = input(); + if (ch == EOF) + return ch; + #ifdef LINE_DIRECTIVE + if (ch == '#' && !nostartline) + { + linedirective(); + continue; + } + #endif + switch (c_class[ch]) + { + case ISACT: + if (ch == '{') + { + copyact('{', '}', in_production, 0); + return C_ACTION; + } + assert(ch == '('); + if (expect_expr) + { + copyact('(', ')', 1, 0); + return C_EXPR; + } + off = ftell(fact); + copyact('(', ')', in_production != 0 ? 0 : 2, 0); + if (nparams == 0) + fseek(fact, off, 0); + lextoken.t_num = nparams; + return C_PARAMS; + case ISLIT: + for (;;) + { + ch = input(); + if (ch == '\n' || ch == EOF) + { + error(linecount, "Missing '", NULL); + break; + } + if (ch == '\'') + break; + if (ch == '\\') + { + *p++ = ch; + ch = input(); + } + *p++ = ch; + if (p > max) + p--; + } + *p = '\0'; + lextoken.t_string = ltext; + return C_LITERAL; + case ISCOM: + skipcomment(0); + /* Fall through */ + case ISSPA: + continue; + case ISDIG: + { + register int i = 0; + do + { + i = 10 * i + (ch - '0'); + ch = input(); + } while (c_class[ch] == ISDIG); + lextoken.t_num = i; + unput(ch); + return C_NUMBER; + } + default: + return ch; + case ISKEY: + reserved = 1; + ch = input(); + /* Fall through */ + case ISLET: + do + { + if (reserved && ch >= 'A' && ch <= 'Z') + { + ch += 'a' - 'A'; + } + *p++ = ch; + if (p > max) + p--; + ch = input(); + } while (c_class[ch] == ISDIG || c_class[ch] == ISLET); + unput(ch); + *p = '\0'; + if (reserved) + { /* + * Now search for the keyword + */ + register p_keyw w; + + w = resword; + while (w->w_word) + { + if (!strcmp(ltext, w->w_word)) + { + /* + * Return token number. + */ + if (w->w_value == C_IF || w->w_value == C_WHILE) + { + nextexpr = 1; + } + return w->w_value; + } + w++; + } + error(linecount, "Illegal reserved word", NULL); + } + lextoken.t_string = ltext; + return C_IDENT; + } + } + } + + static int backupc; /* for unput() */ + static int nonline; /* = 1 if last char read was a newline */ + + int input(void) + { + /* + * Low level input routine, used by all other input routines + */ + register int c; + + if ((c = backupc)) + { + /* Last char was "unput()". Deliver it again + */ + backupc = 0; + return c; + } + if ((c = getc(finput)) == EOF) + { + nonline = 0; + return c; + } + #ifdef LINE_DIRECTIVE + nostartline = 1; + #endif + if (!nonline) + { + linecount++; + #ifdef LINE_DIRECTIVE + nostartline = 0; + #endif + nonline = 1; + } + if (c == '\n') + nonline = 0; + if (strip_grammar) + putchar(c); + return c; + } + + void unput(int c) + { + /* + * "unread" c + */ + backupc = c; + } + + void skipcomment(int flag) + { + /* + * Skip comment. If flag != 0, the comment is inside a fragment + * of C-code, so keep it. + */ + register int ch; + int saved; /* line count on which comment starts */ + + saved = linecount; + if (input() != '*') + error(linecount, "Illegal comment", NULL); + if (flag) + putc('*', fact); + do + { + ch = input(); + if (flag) + putc(ch, fact); + while (ch == '*') + { + ch = input(); + if (flag) + putc(ch, fact); + if (ch == '/') + return; + } + } while (ch != EOF); + error(saved, "Comment does not terminate", NULL); + } + + #ifdef LINE_DIRECTIVE + static void linedirective(void) + { + /* + * Read a line directive + */ + register int ch; + register int i; + string s_error = "Illegal line directive"; + string store(); + register string c; + + do + { /* + * Skip to next digit + * Do not skip newlines + */ + ch = input(); + } while (ch != '\n' && c_class[ch] != ISDIG); + if (ch == '\n') + { + error(linecount, s_error, NULL); + return; + } + i = 0; + do + { + i = i * 10 + (ch - '0'); + ch = input(); + } while (c_class[ch] == ISDIG); + while (ch != '\n' && ch != '"') + ch = input(); + if (ch == '"') + { + c = ltext; + do + { + *c++ = ch = input(); + } while (ch != '"' && ch != '\n'); + if (ch == '\n') + { + error(linecount, s_error, NULL); + return; + } + *--c = '\0'; + do + { + ch = input(); + } while (ch != '\n'); + /* + * Remember the file name + */ + if (strcmp(f_input, ltext)) + f_input = store(ltext); + } + linecount = i; + } + #endif + + static string vallookup(int s) + { + /* + * Look up the keyword that has token number s + */ + register p_keyw p = resword; + + while (p->w_value) + { + if (p->w_value == s) + return p->w_word; + p++; + } + return 0; + } + + static string cpy(int s, register string p, int inserted) + { + /* + * Create a piece of error message for token s and put it at p. + * inserted = 0 if the token s was deleted (in which case we have + * attributes), else it was inserted + */ + register string t = 0; + + switch (s) + { + case C_IDENT: + if (!inserted) + t = lextoken.t_string; + else + t = "identifier"; + break; + case C_NUMBER: + t = "number"; + break; + case C_LITERAL: + if (!inserted) + { + *p++ = '\''; + t = lextoken.t_string; + break; + } + t = "literal"; + break; + case C_ACTION: + t = "C action"; + break; + case C_PARAMS: + t = "C parameter section"; + break; + case C_EXPR: + t = "C expression"; + break; + case EOFILE: + t = "end-of-file"; + break; + } + if (!t && (t = vallookup(s))) + { + *p++ = '%'; + } + if (t) + { /* + * We have a string for the token. Copy it + */ + while (*t) + *p++ = *t++; + if (s == C_LITERAL && !inserted) + { + *p++ = '\''; + } + return p; + } + /* + * The token is a literal + */ + *p++ = '\''; + if (s >= 040 && s <= 0176) + *p++ = s; + else + { + *p++ = '\\'; + switch (s) + { + case '\b': + *p++ = 'b'; + break; + case '\f': + *p++ = 'f'; + break; + case '\n': + *p++ = 'n'; + break; + case '\r': + *p++ = 'r'; + break; + case '\t': + *p++ = 't'; + break; + default: + *p++ = '0' + ((s & 0377) >> 6); + *p++ = '0' + ((s >> 3) & 07); + *p++ = '0' + (s & 07); + } + } + *p++ = '\''; + return p; + } + + void LLmessage(int d) + { + /* + * d is either 0, in which case the current token has been deleted, + * or non-zero, in which case it represents a token that is inserted + * before the current token + */ + register string s, t; + char buf[128]; + + nerrors++; + s = buf; + if (d < 0) + { + strcpy(buf, "end-of-file expected"); + } + else if (d == 0) + { + #ifdef LLNONCORR + t = " unexpected"; + #else + t = " deleted"; + #endif + s = cpy(LLsymb, s, 0); + do + *s++ = *t; + while (*t++); + } + else + { + s = cpy(d, s, 1); + t = " inserted in front of "; + do + *s++ = *t++; + while (*t); + s = cpy(LLsymb, s, 0); + *s = '\0'; + } + if (d > 0) + { /* + * Save the current token and make up some + * attributes for the inserted token + */ + savedtok = lextoken; + savedtok.t_tokno = LLsymb; + if (d == C_IDENT) + lextoken.t_string = "dummy_identifier"; + else if (d == C_LITERAL) + lextoken.t_string = "dummy_literal"; + else if (d == C_NUMBER) + lextoken.t_num = 1; + } + #ifdef LLNONCORR + else + #endif + error(linecount, "%s", buf); + /* Don't change this line to + * error(linecount, buf). + * The string in "buf" might contain '%' ... + */ + #ifdef LLNONCORR + in_production = 1; + /* To prevent warnings from copyact */ + #endif + } } diff --git a/util/LLgen/test_formatter.py b/util/LLgen/test_formatter.py new file mode 100644 index 000000000..0879f90e1 --- /dev/null +++ b/util/LLgen/test_formatter.py @@ -0,0 +1,462 @@ +"""Run with: python3 -m unittest discover -s util/LLgen -p 'test_*.py'.""" + +import unittest +from unittest.mock import patch +from pathlib import Path +import subprocess +import sys +import tempfile + +from formatter import (FormatError, ParseError, c_top_level, format_global_c, + format_actions, format_source, parse) + + +def walk(node): + yield node + for child in node.children: + yield from walk(child) + + +class ParserTests(unittest.TestCase): + def test_lossless_comments_and_roles(self): + source = '''/* header */\r +%start parser, rule; /* declaration */ +{ int global; /* C comment */ } +rule(int n; char *s;) /* parameters */ +{ int local; } +: + /* alternative */ %default %if (n && f(")")) + [ %while (n > 0) %persistent + symbol(n, (int[]){1, 2}) /* symbol */ + { if (n) { puts("}"); } /* } */ n--; } + | ']' /* empty action follows */ {} + ]*3 +| /* empty alternative */ +; +/* trailer */ +''' + doc = parse(source) + self.assertEqual(doc.reconstruct(), source) + comments = [t.text for t in doc.tokens if t.kind == 'comment'] + self.assertIn('/* alternative */', comments) + self.assertIn('/* trailer */', comments) + self.assertNotIn('/* C comment */', comments) + kinds = {n.kind for n in walk(doc.tree)} + self.assertTrue({'c_global', 'c_locals', 'c_parameters', 'c_arguments', + 'c_action', 'c_condition', 'group', 'repeat'} <= kinds) + # Tokens cover the entire source with neither gaps nor overlap. + offset = 0 + for token in doc.tokens: + self.assertEqual(token.start, offset) + self.assertEqual(source[token.start:token.end], token.text) + offset = token.end + self.assertEqual(offset, len(source)) + + def test_identifiers_named_like_token_kinds(self): + parse('number: number(x) | identifier | literal;') + + def test_extensions_and_repeats(self): + parse("r: %illegal %erroneous TOKEN? | %substart a, b; {}+2 | 'x'4;") + + def test_line_directive_and_c_line_comment(self): + doc = parse('# 10 "input.g"\nr: { // }\\\n still a comment }\n f(); };') + self.assertEqual(doc.tokens[0].kind, 'line_directive') + self.assertEqual(len([n for n in walk(doc.tree) if n.kind == 'c_action']), 1) + + def test_errors(self): + for source in ('r: {', 'r: { f(]; };', 'r: /* unfinished', + "r: 'unfinished", 'r: [ x;', 'r: x', + '%unknown x;', 'r: %while (x) y;'): + with self.subTest(source=source), self.assertRaises(ParseError): + parse(source) + with self.assertRaises(ParseError) as error: + parse('\nrule: @;') + self.assertEqual((error.exception.line, error.exception.column), (2, 7)) + + +class FormatterTests(unittest.TestCase): + def test_formal_parameter_separators_and_nested_declarators(self): + source = ('r(int *x; void (*callback)(int,char); char *s;) : ' + 'symbol(f( 1 , 2 ), ";,", (int[]){1,2}); ' + 's(int *x; char *s) : TOKEN;') + output = format_source(source) + self.assertIn('r(int* x; void (*callback)(int, char); char* s;)', output) + self.assertIn('s(int* x; char* s)', output) + self.assertIn('symbol(f(1, 2), ";,", (int[]) { 1, 2 })', output) + self.assertEqual(format_source(output), output) + + def test_parameter_comments_and_optional_trailing_semicolons(self): + source = ('r(int *x; // parameter comment\n int y; /* tail */) : ' + 'symbol(";", f(1,2)); empty(): symbol();') + output = format_source(source) + for doc in (parse(source), parse(output)): + params = [t for t in doc.tokens if t.kind == 'c_parens'][0] + separators = [t for t, _, _ in c_top_level(params.text[1:-1]) if t in {';', ','}] + self.assertEqual(separators, [';', ';']) + self.assertIn('// parameter comment', output) + self.assertIn('/* tail */', output) + self.assertIn('empty()', output) + self.assertIn('symbol()', output) + self.assertEqual(format_source(output), output) + + def test_parenthesized_fragments_are_batched(self): + source = 'r(int *x;): %if(a&&b) symbol( x+1 ) [%while(n>0) next( x )];' + with patch('formatter.subprocess.run', wraps=subprocess.run) as run: + output = format_source(source) + self.assertEqual(run.call_count, 1) + self.assertIn('r(int* x;)', output) + self.assertIn('%if (a && b)', output) + self.assertIn('%while (n > 0)', output) + self.assertIn('symbol(x + 1)', output) + self.assertNotIn('LLGEN_PARENS', output) + self.assertEqual(format_source(output), output) + + def test_parenthesized_fragment_wrapping_uses_output_columns(self): + source = ('very_long_rule_name(' + '; '.join(['int parameter_name_' + str(i) + for i in range(6)]) + ';) : %if (' + + ' && '.join(['long_condition_' + str(i) for i in range(8)]) + + ') long_nonterminal_name(' + ', '.join(['long_argument_' + str(i) + for i in range(9)]) + ');') + output = format_source(source) + self.assertTrue(all(len(line) <= 100 for line in output.splitlines())) + self.assertIn('int parameter_name_5;', output) + self.assertEqual(format_source(output), output) + + def test_comment_indentation_comes_from_grammar_scope(self): + source = ('r: A;\n\n /*\n global comment\n' + ' */\n\ns: A [\n' + '/*\n nested comment\n */\n B] ;') + output = format_source(source) + self.assertIn(';\n\n/*\nglobal comment\n*/\n\ns', output) + self.assertIn(' /*\n nested comment\n */', output) + self.assertEqual(format_source(output), output) + + def test_old_block_comment_indentation_is_ignored(self): + first = 'r: A /*\n * text\n * more\n */ B;' + second = 'r: A /*\n* text\n * more\n */ B;' + output = format_source(first) + self.assertEqual(output, format_source(second)) + self.assertIn(' /*\n * text\n * more\n */', output) + self.assertEqual(format_source(output), output) + + def test_grammar_comments_are_reflowed_with_surrounding_blank_lines(self): + sentence = 'A long explanatory comment with useful words.' + source = 'r: A\n\n/* ' + (sentence + ' ') * 7 + '*/\n\nB;' + output = format_source(source) + self.assertIn(': A\n\n /* ', output) + self.assertIn(' */\n\n B', output) + self.assertIn('\n * ', output) + self.assertTrue(all(len(line) <= 100 for line in output.splitlines())) + words = ' '.join(line.strip().lstrip('/*').rstrip('*/').strip() + for line in output.splitlines() if '/*' in line or line.lstrip().startswith('*')) + self.assertEqual(words, ' '.join([sentence] * 7)) + self.assertEqual(format_source(output), output) + + def test_grammar_comment_alignment_and_batching(self): + source = '/* header */\nr: A\n/*\n * first\n * second\n*/\nB; // end' + with patch('formatter.subprocess.run', wraps=subprocess.run) as run: + output = format_source(source) + self.assertEqual(run.call_count, 1) + self.assertIn(' /*\n * first\n * second\n */', output) + self.assertIn('\n// end', output) + self.assertNotIn('LLgenComment', output) + self.assertEqual(format_source(output), output) + + def test_reflowed_line_comment_stays_stable(self): + output = format_source('r: A;\n\n// ' + 'explanatory words ' * 20 + '\n\n') + self.assertGreater(output.count('//'), 1) + self.assertTrue(output.endswith('\n\n')) + self.assertEqual(format_source(output), output) + + def test_local_declarations_are_expanded_and_batched_with_actions(self): + source = ('r(int* p;) {int * q; int values[]={1,2};} : A {f();}; ' + 's {char * name;} : B;') + with patch('formatter.subprocess.run', wraps=subprocess.run) as run: + output = format_source(source) + self.assertEqual(run.call_count, 2) + self.assertIn('r(int* p;)\n {\n int* q;\n' + ' int values[] = { 1, 2 };\n }\n', output) + self.assertIn('s\n {\n char* name;\n }\n', output) + self.assertIn(' { f(); }', output) + self.assertEqual(format_source(output), output) + + def test_single_and_multiple_statement_actions(self): + output = format_source('r: A {x=1;} B {x=1;y=2;} [C {f();g();}];') + self.assertIn(' { x = 1; }\n', output) + self.assertIn(' {\n x = 1;\n y = 2;\n }', output) + self.assertIn(' {\n f();\n g();\n }', output) + self.assertEqual(format_source(output), output) + + def test_single_control_statement_and_delimiters(self): + output = format_source( + 'r: {for(i=0;i<3;i++){f();}} {if(x) f(); else g();} ' + '{puts("; // }");} {int a[]={1,2};} {for(;;) f(); g();};') + self.assertIn('{ for (i = 0; i < 3; i++) { f(); } }', output) + self.assertIn('{ if (x) f(); else g(); }', output) + self.assertIn('{ puts("; // }"); }', output) + self.assertIn('{ int a[] = { 1, 2 }; }', output) + self.assertIn(' {\n for (;;)', output) + self.assertEqual(format_source(output), output) + + def test_action_comments_and_long_statements_keep_multiline_layout(self): + long_call = 'f(' + ', '.join(['very_long_argument'] * 10) + ');' + output = format_source('r: { // keep\nf(); } {' + long_call + '};') + self.assertIn(' {\n // keep\n f();\n }', output) + self.assertTrue(all(len(line) <= 100 for line in output.splitlines())) + self.assertEqual(format_source(output), output) + + def test_actions_are_batched_in_one_clang_format_call(self): + with patch('formatter.subprocess.run', wraps=subprocess.run) as run: + output = format_source('r: {f();} {g();h();} [A {k();}];') + self.assertEqual(run.call_count, 1) + self.assertNotIn('LLgenAction', output) + self.assertNotIn('#if 1', output) + + def test_action_comments_and_leading_whitespace_are_stable(self): + source = ('r: {f(); /* keep */} { \n f();g(); } ' + '{ /* explains code */\n#ifdef FEATURE\nf();\n#endif\ng(); };') + output = format_source(source) + self.assertIn('{ f(); /* keep */ }', output) + self.assertIn(' /* explains code */', output) + self.assertEqual(format_source(output), output) + + def test_layout(self): + self.assertEqual( + format_source('%token A,B; r(int x;) {int y;}: [%while(x) %persistent A(x)| B]*3 { f(); }|;'), + "%token A, B;\n\nr(int x;)\n" + " {\n int y;\n }\n : [\n" + " %while (x)\n %persistent\n" + " A(x)\n | B\n ]*3\n" + " { f(); }\n |\n ;\n") + + def test_alternative_introducers_share_first_symbol(self): + output = format_source('r: first second | third | [nested | other];') + self.assertEqual(output, 'r\n : first second\n | third\n | [\n' + ' nested\n | other\n ]\n ;\n') + self.assertEqual(format_source(output), output) + + def test_conditions_are_formatted(self): + condition = '(x && f(")", /* keep */ (int[]){1, 2})\n || y)' + source = ('r: %if ' + condition + ' A {hidden();} | ' + '[%while (n-- > 0) B];') + output = format_source(source) + self.assertIn('%if (x && f(")", /* keep */ (int[]) { 1, 2 }) || y)', output) + self.assertIn('%while (n-- > 0)', output) + self.assertIn('{ hidden(); }', output) + self.assertEqual(format_source(output), output) + + def test_plain_symbols_group_and_parameterised_symbols_stand_alone(self): + source = "r: A B call(x) C D other(y) | '#' INTVALUE STRVALUE EOLN;" + output = format_source(source) + self.assertEqual(output, + "r\n : A B\n call(x)\n" + " C D\n other(y)\n" + " | '#' INTVALUE STRVALUE EOLN\n ;\n") + self.assertEqual(format_source(output), output) + + def test_operators_comments_and_actions_separate_symbol_runs(self): + source = 'r: A B? C D /* keep */ E F { f(); } G H [I J | K L]+ M N;' + output = format_source(source) + self.assertIn(': A\n B?\n C D\n', output) + self.assertIn('/* keep */\n E F\n { f(); }\n G H\n', output) + self.assertIn(' I J\n | K L\n ]+\n M N\n', output) + self.assertEqual(format_source(output), output) + + def test_comments_and_c_preserved_in_order(self): + source = ("/* header */ { int secret; /* inside C */ }\n" + "r /* before params */ (int n;) /* locals */ {int x;} :\n" + "/* first */ x /* arguments */ (n) [/* group */ 'x'\n" + "| /* empty */ ] /* suffix */ +2 // trailing\n" + "{secret();} ; /* end */") + output = format_source(source) + before = parse(source) + after = parse(output) + globals_ = {n.start for n in before.tree.children if n.kind == 'c_global'} + actions = {n.start for n in walk(before.tree) if n.kind == 'c_action'} + locals_ = {n.start for n in walk(before.tree) if n.kind == 'c_locals'} + for kind in ('comment', 'line_directive', 'c_block', 'c_parens'): + self.assertEqual([format_global_c(t.text) if i in globals_ else + format_actions([(i, t.text, 2)])[i] if i in actions else + format_actions([(i, t.text, 1)], multiline={i})[i] + if i in locals_ else t.text + for i, t in enumerate(before.tokens) if t.kind == kind], + [t.text for t in after.tokens if t.kind == kind]) + self.assertIn('secret', output) + self.assertIn('inside C', output) + self.assertEqual(format_source(output), output) + + def test_extensions_literals_and_directives(self): + source = ('# 1 "test.g"\n%start parser, r;\n' + "r: %illegal %erroneous TOKEN? | %substart a,b; {}+2 | ';'4;") + output = format_source(source) + self.assertTrue(output.startswith('# 1 "test.g"\n')) + self.assertIn('%substart a, b;\n {}+2', output) + self.assertEqual(format_source(output), output) + + def test_actions_have_one_extra_indent_at_every_grammar_depth(self): + output = format_source('{int global;} r {int local;}: {} | [A {} [B {}]];') + actions = [line for line in output.splitlines() if line.strip() == '{}'] + self.assertEqual(actions, [' ' * depth + '{}' + for depth in (2, 3, 4)]) + self.assertTrue(output.startswith('{\n int global;\n}\n')) + self.assertIn('\n {\n int local;\n }\n', output) + self.assertEqual(format_source(output), output) + + def test_c_fragments_use_project_style(self): + source = ('{int * p; void f(){if(1){g();}}} ' + 'r(int * p;) {int * q;} : symbol( p ) {if(1){g();}}; ' + '{int another;}') + output = format_source(source) + self.assertTrue(output.startswith('{\n int* p;\n void f()\n {\n')) + self.assertIn('\n if (1)\n {\n g();\n', output) + self.assertIn('r(int* p;)', output) + self.assertIn(' {\n int* q;\n }', output) + self.assertIn('symbol(p)', output) + self.assertIn(' { if (1) { g(); } }', output) + self.assertIn('{\n int another;\n}', output) + self.assertEqual(format_source(output), output) + + def test_clang_format_failures_and_no_global_blocks(self): + with patch('formatter.subprocess.run', side_effect=FileNotFoundError): + self.assertEqual(format_source('r: A;'), 'r\n : A\n ;\n') + with self.assertRaisesRegex(FormatError, 'not found'): + format_source('{int x;}') + error = subprocess.CalledProcessError(1, 'clang-format', stderr=b'bad config') + with patch('formatter.subprocess.run', side_effect=error): + with self.assertRaisesRegex(FormatError, 'bad config'): + format_source('{int x;}') + + def test_global_directives_and_wrapping_include_indentation(self): + source = ('{\n#include "header.h"\n#define LONG_MACRO ' + + ' + '.join(['a_very_long_identifier'] * 6) + + '\n#if ENABLED\nint *p;\n#endif\n}') + output = format_global_c(source) + for directive in ('#include "header.h"', '#define LONG_MACRO', + '#if ENABLED', '#endif'): + self.assertIn('\n ' + directive, output) + self.assertIn('\\\n', output) + self.assertTrue(all(len(line) <= 100 for line in output.splitlines())) + self.assertNotIn('\t', output) + self.assertNotIn('namespace LLgenGlobal', output) + self.assertNotIn('#if 1\n', output) + self.assertEqual(format_global_c(output), output) + + def test_global_empty_block_and_wrapper_validation(self): + self.assertEqual(format_global_c('{}'), '{\n}') + result = subprocess.CompletedProcess('clang-format', 0, b'broken wrapper\n') + with patch('formatter.subprocess.run', return_value=result): + with self.assertRaisesRegex(FormatError, 'wrapper'): + format_global_c('{int x;}') + + def test_empty_and_comments_only(self): + self.assertEqual(format_source(''), '') + self.assertEqual(format_source(' /* retained */ '), '/* retained */\n') + + def test_blank_lines_surrounding_comments_are_preserved(self): + source = ('\n\n/* header */\n\n\nr: A\n\n/* middle */\n\n\nB;\n' + '/* between rules */\ns: C;\n\n// trailer\n\n\n') + output = format_source(source) + self.assertTrue(output.startswith('\n\n/* header */\n\n\nr\n')) + self.assertIn(': A\n\n /* middle */\n\n\n B', output) + self.assertIn(';\n/* between rules */\ns\n', output) + self.assertTrue(output.endswith(';\n\n// trailer\n\n\n')) + self.assertEqual(format_source(output), output) + + def test_blank_lines_between_comments_and_crlf_input(self): + source = '/* first */\r\n \t\r\n\r\n/* second */\r\n\r\nr: A;' + output = format_source(source) + self.assertTrue(output.startswith('/* first */\n\n\n/* second */\n\nr\n')) + self.assertEqual(format_source(output), output) + + def test_inline_comments_do_not_gain_blank_lines(self): + output = format_source('r: A /* one *//* two */ B;/* end */') + self.assertNotIn('\n\n', output) + self.assertEqual(format_source(output), output) + + def test_parameters_and_arguments_are_formatted(self): + source = ('r(int x;\n char *s;) {\n\tint local;\n} :\n' + 'call(x,\n s) {\n#if ENABLED\n\tf("}"); // keep\n#endif\n};') + output = format_source(source) + self.assertIn('r(int x; char* s;)', output) + self.assertIn(' {\n int local;\n }', output) + self.assertIn('call(x, s)', output) + self.assertIn(' f("}"); // keep', output) + self.assertIn('#if ENABLED', output) + self.assertEqual(format_source(output), output) + + +class CommandLineTests(unittest.TestCase): + def run_formatter(self, path, *options): + return subprocess.run( + [sys.executable, str(Path(__file__).with_name('formatter.py')), *options, str(path)], + capture_output=True, text=True) + + def test_multiple_files_stdout_and_inplace(self): + with tempfile.TemporaryDirectory() as directory: + first = Path(directory) / 'first.g' + second = Path(directory) / 'second.g' + first.write_text('first: A;') + second.write_text('second: B C;') + result = self.run_formatter(second, str(first)) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stdout, format_source('first: A;') + + format_source('second: B C;')) + self.assertEqual(first.read_text(), 'first: A;') + self.assertEqual(second.read_text(), 'second: B C;') + result = self.run_formatter(second, '-i', str(first)) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stdout, '') + self.assertEqual(first.read_text(), format_source('first: A;')) + self.assertEqual(second.read_text(), format_source('second: B C;')) + + def test_file_errors_do_not_prevent_other_files_being_formatted(self): + with tempfile.TemporaryDirectory() as directory: + good = Path(directory) / 'good.g' + bad = Path(directory) / 'bad.g' + missing = Path(directory) / 'missing.g' + good.write_text('good: A;') + bad.write_text('bad: [;') + result = self.run_formatter(good, '-i', str(bad), str(missing)) + self.assertEqual(result.returncode, 1) + self.assertIn(str(bad), result.stderr) + self.assertIn(str(missing), result.stderr) + self.assertEqual(good.read_text(), format_source('good: A;')) + self.assertEqual(bad.read_text(), 'bad: [;') + + def test_inplace_aliases_and_default_stdout(self): + with tempfile.TemporaryDirectory() as directory: + path = Path(directory) / 'input.g' + source = b'/* comment */\n\nr: A B { puts("\xff"); };' + expected = format_source(source.decode('utf-8', 'surrogateescape')).encode( + 'utf-8', 'surrogateescape') + for option in ('--inplace', '-i'): + path.write_bytes(source) + result = self.run_formatter(path, option) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stdout, '') + self.assertEqual(path.read_bytes(), expected) + result = self.run_formatter(path, option) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(path.read_bytes(), expected) + path.write_text('r: A;') + result = self.run_formatter(path) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stdout, format_source('r: A;')) + self.assertEqual(path.read_text(), 'r: A;') + + def test_errors_leave_input_unchanged(self): + with tempfile.TemporaryDirectory() as directory: + path = Path(directory) / 'input.g' + path.write_text('r: [ unfinished;') + result = self.run_formatter(path, '-i') + self.assertNotEqual(result.returncode, 0) + self.assertEqual(path.read_text(), 'r: [ unfinished;') + for option in ('--tree', '--tokens'): + result = self.run_formatter(path, '-i', option) + self.assertEqual(result.returncode, 2) + self.assertIn('cannot be combined', result.stderr) + self.assertEqual(path.read_text(), 'r: [ unfinished;') + + +if __name__ == '__main__': + unittest.main() diff --git a/util/ceg/EM_parser/common/pars.g b/util/ceg/EM_parser/common/pars.g index e3c0b024a..04983b763 100644 --- a/util/ceg/EM_parser/common/pars.g +++ b/util/ceg/EM_parser/common/pars.g @@ -1,3 +1,9 @@ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i util/ceg/EM_parser/common/pars.g + */ + /* This file contains the parser for the 'EM_table'. * Every row in the table is converted to a C-function. * The parser is a fairly simple program, for each row it prints a function- @@ -7,7 +13,7 @@ * How this should be done is expressed in the 'as_table'. * * There are however some complicating factors: - * - A row in the 'EM_table' may contain CONDITION's. + * - A row in the 'EM_table' may contain CONDITION's. * The parser supports this by outptutting some "if" and "else"'s. * * - The user is allowed to use some abbreviation in the 'EM_table', (s)he @@ -24,126 +30,171 @@ * function. This function should return the number of bytes between * the current instruction and a labelled one, both forward and backward * references must be handled. - * This requires the saving of the generated function, and + * This requires the saving of the generated function, and * backpatching in a second phase. */ { - -#include -#include "decl.h" -#include "em.h" - -extern char yytext[]; -extern int yylineno; -extern int first_action, last_action, token; - -t_token tok, stok; -int no_conversions = FALSE, library, segment = UNKNOWN; -FILE* outfile; -char *to_change; - + #include + #include "decl.h" + #include "em.h" + + extern char yytext[]; + extern int yylineno; + extern int first_action, last_action, token; + + t_token tok, stok; + int no_conversions = FALSE, library, segment = UNKNOWN; + FILE* outfile; + char* to_change; } -%token C_INSTR, DEF_C_INSTR, CONDITION, ARROW, - CALL, ASSEM_INSTR, DEFAULT, ERROR; -%start table, table; -%start def_row, def_row; -%start c_table, c_table; -%lexical lex_analyzer ; - - -table : row* - ; - -row : C_INSTR { set_outfile( yytext); header( yytext); - set_segment(segment); - } - [ special | simple] { out( "}\n\n");} - - | DEF_C_INSTR { init_defaults( yytext);} - [ Dspecial | Dsimple] { handle_defaults();} - ; - -special : - { out( "if( 0 ) ;\n"); } - - [ CONDITION { out( "else "); question( &yytext[0]);} - simple { out( "}\n");} - ]* - - DEFAULT { out( "else {\n");} - simple { out( "}\n");} - ; - -simple : ARROW { save_output();} - actionlist { back_patch();} - ; - - -actionlist : { first_action = TRUE;} - [ action { first_action = FALSE;} - [ ';' action]* - ]? - '.' - ; - -action : CALL { print_call( &yytext[0]);} - - | as_block { last_action = ( token == '.'); - do_block_assemble();} - - ; - -as_block : { init_as_block();} - ASSEM_INSTR { save_as( &yytext[0]);} - more_as - ; - -more_as : - %if ( next_token() == ASSEM_INSTR) - ';' - ASSEM_INSTR { save_as( &yytext[0]);} - more_as - | - ; +%token C_INSTR, DEF_C_INSTR, CONDITION, ARROW, CALL, ASSEM_INSTR, DEFAULT, ERROR; +%start table, table; +%start def_row, def_row; +%start c_table, c_table; +%lexical lex_analyzer; + +table + : row* + ; + +row + : C_INSTR + { + set_outfile(yytext); + header(yytext); + set_segment(segment); + } + [ + special + | simple + ] + { out("}\n\n"); } + | DEF_C_INSTR + { init_defaults(yytext); } + [ + Dspecial + | Dsimple + ] + { handle_defaults(); } + ; + +special + : + { out("if( 0 ) ;\n"); } + [ + CONDITION + { + out("else "); + question(&yytext[0]); + } + simple + { out("}\n"); } + ]* + DEFAULT + { out("else {\n"); } + simple + { out("}\n"); } + ; + +simple + : ARROW + { save_output(); } + actionlist + { back_patch(); } + ; + +actionlist + : + { first_action = TRUE; } + [ + action + { first_action = FALSE; } + [ + ';' action + ]* + ]? + '.' + ; + +action + : CALL + { print_call(&yytext[0]); } + | as_block + { + last_action = (token == '.'); + do_block_assemble(); + } + ; + +as_block + : + { init_as_block(); } + ASSEM_INSTR + { save_as(&yytext[0]); } + more_as + ; + +more_as + : %if (next_token() == ASSEM_INSTR) + ';' ASSEM_INSTR + { save_as(&yytext[0]); } + more_as + | + ; /* Grammar rules for a default-instruction, just copy to a temporary file. */ -Dspecial: CONDITION { out( " %s ", yytext);} - Dsimple - - [ CONDITION { out( " %s ", yytext);} - Dsimple - ]* - - DEFAULT { out( " %s ", yytext);} - Dsimple - ; - -Dsimple : ARROW { out( "%s", yytext);} - Dactionlist - - ; - -Dactionlist : - [ Daction - [ ';' { out( ";\n");} - Daction - ]* - ]? - '.' { out( ".\n");} - ; - -Daction : CALL { out( "%s", yytext);} - - | ASSEM_INSTR { out( "\"%s\"", yytext);} - - ; - -def_row : { set_segment(segment);} - [ special | simple] { out( "}\n\n");} - ; +Dspecial + : CONDITION + { out(" %s ", yytext); } + Dsimple + [ + CONDITION + { out(" %s ", yytext); } + Dsimple + ]* + DEFAULT + { out(" %s ", yytext); } + Dsimple + ; + +Dsimple + : ARROW + { out("%s", yytext); } + Dactionlist + ; + +Dactionlist + : [ + Daction + [ + ';' + { out(";\n"); } + Daction + ]* + ]? + '.' + { out(".\n"); } + ; + +Daction + : CALL + { out("%s", yytext); } + | ASSEM_INSTR + { out("\"%s\"", yytext); } + ; + +def_row + : + { set_segment(segment); } + [ + special + | simple + ] + { out("}\n\n"); } + ; @@ -152,178 +203,209 @@ def_row : { set_segment(segment);} * use the grammar rules for the normal case above. */ -c_table : c_row* - ; - -c_row : %if ( to_change && strcmp( yytext, to_change) == 0) - C_INSTR { set_outfile( yytext); header( yytext); - set_segment(segment); - } - [ special | simple] { out( "}\n\n"); to_change = 0; } - - | C_INSTR - [ c_special | c_simple] - - | %if ( to_change && strcmp( yytext, to_change) == 0) - DEF_C_INSTR { init_defaults( yytext);} - [ Dspecial | Dsimple] { handle_defaults(); to_change = 0; } - - | DEF_C_INSTR - [ c_special | c_simple] - ; - -c_special : CONDITION - c_simple +c_table + : c_row* + ; + +c_row + : %if (to_change && strcmp(yytext, to_change) == 0) + C_INSTR + { + set_outfile(yytext); + header(yytext); + set_segment(segment); + } + [ + special + | simple + ] + { + out("}\n\n"); + to_change = 0; + } + | C_INSTR + [ + c_special + | c_simple + ] + | %if (to_change && strcmp(yytext, to_change) == 0) + DEF_C_INSTR + { init_defaults(yytext); } + [ + Dspecial + | Dsimple + ] + { + handle_defaults(); + to_change = 0; + } + | DEF_C_INSTR + [ + c_special + | c_simple + ] + ; + +c_special + : CONDITION c_simple + [ + CONDITION c_simple + ]* + DEFAULT c_simple + ; + +c_simple + : ARROW c_actionlist + ; + +c_actionlist + : [ + c_action + [ + ';' c_action + ]* + ]? + '.' + ; + +c_action + : CALL + | ASSEM_INSTR + ; - [ CONDITION - c_simple - ]* - - DEFAULT - c_simple - ; - -c_simple: ARROW - c_actionlist - - ; - -c_actionlist : - [ c_action [ ';' c_action]* ]? '.' - ; - -c_action: CALL - | ASSEM_INSTR - ; - - - - - -{ - -int saved = 0, token; -int nerrors = 0; - - -LLmessage( inserted_token) -int inserted_token; { - nerrors++; - if ( inserted_token == 0) { - fprintf( stderr, "EM_table : syntax error in line %d, >>", - yylineno); - print_token( LLsymb); - fprintf( stderr, "<< will be deleted!!\n"); - } - else if ( inserted_token < 0) { - fprintf(stderr,"EM_table : syntax error in line %d, garbage at end of table\n", - yylineno); - } - else { - fprintf( stderr, "EM_table : syntax error in line %d, >>", - yylineno); - print_token( inserted_token); - fprintf( stderr, "<< will be inserted!!\n"); - token = LLsymb; - saved = 1; - } -} - -print_token( token) -int token; -{ - switch ( token) { - case C_INSTR : fprintf( stderr, "C_INSTR %s", yytext); - break; - case ASSEM_INSTR : fprintf( stderr, "STRING %s", yytext); - break; - case CALL : fprintf( stderr, "CALL %s", yytext); - break; - case ARROW : fprintf( stderr, "==> "); - break; - case CONDITION: fprintf( stderr, "CONDITION %s", yytext); - break; - case DEFAULT : fprintf( stderr, "default "); - break; - case ERROR : fprintf( stderr, "unmatched %s", yytext); - break; - default : fprintf( stderr, " %c", token); - break; - } -} - - -/* The lexical analyzer. - * It uses mylex() to get the tokens. - * It supports the buffering of one token. - * If the curent token is a C_INSTR it will set the global variable - * 'C_instr_info' to point to the correct information ( arguments, header, - * etc.). - */ - -int lex_analyzer() -{ - extern char *next; - - if ( saved) { - saved = 0; - } - else { - token = mylex(); - *next = '\0'; - } - if ( token == C_INSTR) - set_C_instr_info( yytext); - return( token); -} - -int next_token() -{ - extern char *next; - - if ( !saved) { - token = mylex(); - *next = '\0'; - saved = 1; - } - return( token); -} - - -/******************************************************************************/ - -/* Handle arguments : - * -l : Library, generate one function per file. - * -c : Change, only update the file. - */ - -main( argc, argv) -int argc; -char **argv; -{ - outfile = stdout; - if ( argc > 1) { - if ( strcmp( argv[1], "-l") == 0) - library = TRUE; - else if( strcmp( argv[1], "-c") == 0) { - library = TRUE; - to_change = argv[2]; - c_table(); - if (to_change) { - fprintf( stderr, "No rule for %s\n", to_change); - exit( 1); - } - exit(nerrors); - } - } - else { - library = FALSE; - file_header(); - } - - table(); - exit(nerrors); -} - + int saved = 0, token; + int nerrors = 0; + + LLmessage(inserted_token) int inserted_token; + { + nerrors++; + if (inserted_token == 0) + { + fprintf(stderr, "EM_table : syntax error in line %d, >>", yylineno); + print_token(LLsymb); + fprintf(stderr, "<< will be deleted!!\n"); + } + else if (inserted_token < 0) + { + fprintf(stderr, "EM_table : syntax error in line %d, garbage at end of table\n", + yylineno); + } + else + { + fprintf(stderr, "EM_table : syntax error in line %d, >>", yylineno); + print_token(inserted_token); + fprintf(stderr, "<< will be inserted!!\n"); + token = LLsymb; + saved = 1; + } + } + + print_token(token) int token; + { + switch (token) + { + case C_INSTR: + fprintf(stderr, "C_INSTR %s", yytext); + break; + case ASSEM_INSTR: + fprintf(stderr, "STRING %s", yytext); + break; + case CALL: + fprintf(stderr, "CALL %s", yytext); + break; + case ARROW: + fprintf(stderr, "==> "); + break; + case CONDITION: + fprintf(stderr, "CONDITION %s", yytext); + break; + case DEFAULT: + fprintf(stderr, "default "); + break; + case ERROR: + fprintf(stderr, "unmatched %s", yytext); + break; + default: + fprintf(stderr, " %c", token); + break; + } + } + + /* The lexical analyzer. + * It uses mylex() to get the tokens. + * It supports the buffering of one token. + * If the curent token is a C_INSTR it will set the global variable + * 'C_instr_info' to point to the correct information ( arguments, header, + * etc.). + */ + + int lex_analyzer() + { + extern char* next; + + if (saved) + { + saved = 0; + } + else + { + token = mylex(); + *next = '\0'; + } + if (token == C_INSTR) + set_C_instr_info(yytext); + return (token); + } + + int next_token() + { + extern char* next; + + if (!saved) + { + token = mylex(); + *next = '\0'; + saved = 1; + } + return (token); + } + + /******************************************************************************/ + + /* Handle arguments : + * -l : Library, generate one function per file. + * -c : Change, only update the file. + */ + + main(argc, argv) int argc; + char** argv; + { + outfile = stdout; + if (argc > 1) + { + if (strcmp(argv[1], "-l") == 0) + library = TRUE; + else if (strcmp(argv[1], "-c") == 0) + { + library = TRUE; + to_change = argv[2]; + c_table(); + if (to_change) + { + fprintf(stderr, "No rule for %s\n", to_change); + exit(1); + } + exit(nerrors); + } + } + else + { + library = FALSE; + file_header(); + } + + table(); + exit(nerrors); + } } diff --git a/util/ceg/as_parser/pars.g b/util/ceg/as_parser/pars.g index 427b2b0e7..6f502ceb1 100644 --- a/util/ceg/as_parser/pars.g +++ b/util/ceg/as_parser/pars.g @@ -1,3 +1,9 @@ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i util/ceg/as_parser/pars.g + */ + /* This file contains the description of the 'as_table' parser. * It transforms every entry into a C-funtion, for example : * @@ -32,186 +38,258 @@ * else * error( "No match for and"); * } - * + * * At the end of the table a list is generated enumerating all the assembler * mnemonics and their corresponding function names. */ { -#include -#include - -#include "decl.h" -extern int lineno, yyleng; -#ifdef FLEX -extern char *yytext; -#else -extern char yytext[]; -#endif + #include + #include + #include "decl.h" + extern int lineno, yyleng; + #ifdef FLEX + extern char* yytext; + #else + extern char yytext[]; + #endif } %token IDENTIFIER, CALL, CONDITION, IF, ELSIF, ELSE, FI, ARROW, MORE; -%start table, table; -%lexical lex_analyzer ; - - -table : { init_table();} - instruction* { end_table();} - ; - -instruction : { clean();} - first_row - [ { operand_clean();} - extra_row - ]* { pr_warning(); out( "}\n\n");} - ; - -first_row : mnemonic { save_instr( yytext, yyleng);} - [ decl_list]? - ARROW { pr_header(); pr_restriction();} - action_list - ; - -extra_row : MORE - [ decl_list]? - ARROW { out( "else "); pr_restriction();} - action_list - ; - -mnemonic : IDENTIFIER - ; - -decl_list : { clear_restriction();} - declaration - [ ',' declaration] *7 - ; - -declaration : IDENTIFIER { save_name( yytext, yyleng);} - [ ':' - IDENTIFIER { save_type( yytext, yyleng);} - ]? { inc_ops();} - ; - -action_list : { out( "{\n");} - [ action [ ';' action]* ]? '.' { out( "}\n");} - ; - -action : if_statement - | call - | subroutine - ; +%start table, table; +%lexical lex_analyzer; + +table + : + { init_table(); } + instruction* + { end_table(); } + ; + +instruction + : + { clean(); } + first_row + [ + { operand_clean(); } + extra_row + ]* + { + pr_warning(); + out("}\n\n"); + } + ; + +first_row + : mnemonic + { save_instr(yytext, yyleng); } + [ + decl_list + ]? + ARROW + { + pr_header(); + pr_restriction(); + } + action_list + ; + +extra_row + : MORE + [ + decl_list + ]? + ARROW + { + out("else "); + pr_restriction(); + } + action_list + ; + +mnemonic + : IDENTIFIER + ; + +decl_list + : + { clear_restriction(); } + declaration + [ + ',' declaration + ]*7 + ; + +declaration + : IDENTIFIER + { save_name(yytext, yyleng); } + [ + ':' IDENTIFIER + { save_type(yytext, yyleng); } + ]? + { inc_ops(); } + ; + +action_list + : + { out("{\n"); } + [ + action + [ + ';' action + ]* + ]? + '.' + { out("}\n"); } + ; + +action + : if_statement + | call + | subroutine + ; /* A function call is just an identifier followed by an expression surrounded * by '(' and ')'. CONDITION is a token that matches this construct; */ subroutine - { char *s; } : IDENTIFIER { s = Salloc(yytext, yyleng+1); } - CONDITION { s = realloc(s, strlen(s)+yyleng+1); - strcat(s, yytext); - pr_subroutine( s); - free(s); - } - ; + { + char* s; + } + : IDENTIFIER + { s = Salloc(yytext, yyleng + 1); } + CONDITION + { + s = realloc(s, strlen(s) + yyleng + 1); + strcat(s, yytext); + pr_subroutine(s); + free(s); + } + ; call - { char *s; } : '@' - IDENTIFIER { s = Salloc(yytext, yyleng+1); } - CONDITION { s = realloc(s, strlen(s)+yyleng+1); - strcat(s, yytext); - pr_call( s); - free(s); - } - ; - -if_statement : IF - CONDITION { pr_question( yytext);} - action_list { pr_end();} - [ ELSIF { pr_els();} - CONDITION { pr_question( yytext);} - action_list { pr_end();} - ]* - [ ELSE { pr_else();} - action_list { pr_end();} - ]? - FI - ; - -{ + { + char* s; + } + : '@' IDENTIFIER + { s = Salloc(yytext, yyleng + 1); } + CONDITION + { + s = realloc(s, strlen(s) + yyleng + 1); + strcat(s, yytext); + pr_call(s); + free(s); + } + ; -int nerrors; -static int saved = 0, token; +if_statement + : IF CONDITION + { pr_question(yytext); } + action_list + { pr_end(); } + [ + ELSIF + { pr_els(); } + CONDITION + { pr_question(yytext); } + action_list + { pr_end(); } + ]* + [ + ELSE + { pr_else(); } + action_list + { pr_end(); } + ]? + FI + ; - -LLmessage( inserted_token) -int inserted_token; { - nerrors++; - if ( inserted_token == 0) { - fprintf( stderr, "Sytax error in line %d, ", lineno); - print_token( LLsymb); - fprintf( stderr, " will be deleted!!\n"); - } - else if ( inserted_token < 0) { - fprintf( stderr, "Garbage at end, line %d!!\n", - lineno); - } - else { - fprintf( stderr, "Sytax error in line %d, ", lineno); - print_token( inserted_token); - fprintf( stderr, " will be inserted!!\n"); - token = LLsymb; - saved = 1; - } -} + int nerrors; + static int saved = 0, token; -print_token( token) -int token; -{ - switch ( token) { - case IDENTIFIER : fprintf( stderr, "IDENTIFIER %s", yytext); - break; - case CALL : fprintf( stderr, "CALL %s", yytext); - break; - case CONDITION: fprintf( stderr, "CONDITION %s", yytext); - break; - case IF : fprintf( stderr, "@if "); - break; - case ELSIF : fprintf( stderr, "@elsif "); - break; - case ELSE : fprintf( stderr, "@else "); - break; - case FI : fprintf( stderr, "@fi "); - break; - case ARROW : fprintf( stderr, "==> "); - break; - case MORE : fprintf( stderr, "... "); - break; - default : fprintf( stderr, "%c ", token); - break; - } -} + LLmessage(inserted_token) int inserted_token; + { + nerrors++; + if (inserted_token == 0) + { + fprintf(stderr, "Sytax error in line %d, ", lineno); + print_token(LLsymb); + fprintf(stderr, " will be deleted!!\n"); + } + else if (inserted_token < 0) + { + fprintf(stderr, "Garbage at end, line %d!!\n", lineno); + } + else + { + fprintf(stderr, "Sytax error in line %d, ", lineno); + print_token(inserted_token); + fprintf(stderr, " will be inserted!!\n"); + token = LLsymb; + saved = 1; + } + } -int lex_analyzer() -{ - int tok; - - if ( saved) { - saved = 0; - return( token); - } - else { - tok = yylex(); - yytext[yyleng] = '\0'; /* strings must end with '\0' */ - return( tok); - } -} + print_token(token) int token; + { + switch (token) + { + case IDENTIFIER: + fprintf(stderr, "IDENTIFIER %s", yytext); + break; + case CALL: + fprintf(stderr, "CALL %s", yytext); + break; + case CONDITION: + fprintf(stderr, "CONDITION %s", yytext); + break; + case IF: + fprintf(stderr, "@if "); + break; + case ELSIF: + fprintf(stderr, "@elsif "); + break; + case ELSE: + fprintf(stderr, "@else "); + break; + case FI: + fprintf(stderr, "@fi "); + break; + case ARROW: + fprintf(stderr, "==> "); + break; + case MORE: + fprintf(stderr, "... "); + break; + default: + fprintf(stderr, "%c ", token); + break; + } + } -main() -{ - table(); - exit(nerrors); -} + int lex_analyzer() + { + int tok; + + if (saved) + { + saved = 0; + return (token); + } + else + { + tok = yylex(); + yytext[yyleng] = '\0'; /* strings must end with '\0' */ + return (tok); + } + } + main() + { + table(); + exit(nerrors); + } } diff --git a/util/grind/commands.g b/util/grind/commands.g index 7169017f5..f225735f9 100644 --- a/util/grind/commands.g +++ b/util/grind/commands.g @@ -1,738 +1,892 @@ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i util/grind/commands.g + */ + /* $Id$ */ /* Command grammar */ { -#include -#include -#include - -#include "ops.h" -#include "class.h" -#include "position.h" -#include "file.h" -#include "idf.h" -#include "symbol.h" -#include "tree.h" -#include "langdep.h" -#include "token.h" -#include "expr.h" -#include "misc.h" - -extern char *Salloc(); -extern char *strchr(); -extern char *strcpy(); -extern void signal_child(); -extern FILE *db_in; -extern int disable_intr; -extern p_tree run_command, print_command; - -struct token tok, aside; -int errorgiven = 0; -int child_interrupted = 0; -int interrupted = 0; -int eof_seen = 0; - -static int shellescape(); - -static int extended_charset = 0; -static int in_expression = 0; - -#define binprio(op) ((*(currlang->binop_prio))(op)) -#define unprio(op) ((*(currlang->unop_prio))(op)) + #include + #include + #include + + #include "ops.h" + #include "class.h" + #include "position.h" + #include "file.h" + #include "idf.h" + #include "symbol.h" + #include "tree.h" + #include "langdep.h" + #include "token.h" + #include "expr.h" + #include "misc.h" + + extern char* Salloc(); + extern char* strchr(); + extern char* strcpy(); + extern void signal_child(); + extern FILE* db_in; + extern int disable_intr; + extern p_tree run_command, print_command; + + struct token tok, aside; + int errorgiven = 0; + int child_interrupted = 0; + int interrupted = 0; + int eof_seen = 0; + + static int shellescape(); + + static int extended_charset = 0; + static int in_expression = 0; + + #define binprio(op) ((*(currlang->binop_prio))(op)) + #define unprio(op) ((*(currlang->unop_prio))(op)) } -%start Commands, commands; +%start Commands, commands; %lexical LLlex; commands - { p_tree com, lastcom = 0; - int give_prompt; - } -: - { errorgiven = 0; } - [ %persistent command_line(&com) - [ '\n' { give_prompt = 1; } - | %default ';' { give_prompt = 0; } + { + p_tree com, lastcom = 0; + int give_prompt; + } + : + { errorgiven = 0; } + [ + %persistent + command_line(&com) + [ + '\n' + { give_prompt = 1; } + | %default + ';' + { give_prompt = 0; } + ] + { + if (com) + { + if (lastcom) + { + freenode(lastcom); + lastcom = 0; + } + if (errorgiven) + { + if (com != run_command) + freenode(com); + com = 0; + } + else + { + enterlog(com); + eval(com); + if (repeatable(com)) + { + lastcom = com; + } + else if (!in_status(com) && com != run_command && com != print_command) + { + freenode(com); + com = 0; + } + } + } + else if (lastcom && !errorgiven) + { + enterlog(lastcom); + eval(lastcom); + } + if (give_prompt) + { + errorgiven = 0; + interrupted = 0; + prompt(); + } + } + ]* + ; + +command_line(p_tree* p;) + : + { *p = 0; } + [ + list_command(p) + | file_command(p) + | run_command(p) + | stop_command(p) + | when_command(p) + | continue_command(p) + | step_command(p) + | next_command(p) + | regs_command(p) + | where_command(p) + | STATUS + { *p = mknode(OP_STATUS); } + | DUMP + { *p = mknode(OP_DUMP); } + | RESTORE + opt_num(p) + { *p = mknode(OP_RESTORE, *p); } + | delete_command(p) + | print_command(p) + | display_command(p) + | trace_command(p) + | set_command(p) + | help_command(p) + | FIND + qualified_name(p) + { *p = mknode(OP_FIND, *p); } + | WHICH + qualified_name(p) + { *p = mknode(OP_WHICH, *p); } + | able_command(p) + | '!' + { + (void)shellescape(); + *p = mknode(OP_SHELL); + } + | source_command(p) + | log_command(p) + | frame_command(p) + | + ] + ; + +frame_command(p_tree* p;) + : FRAME + [ + { *p = mknode(OP_FRAME, (p_tree)0); } + | count(p) + { *p = mknode(OP_FRAME, *p); } + | '-' + count(p) + { *p = mknode(OP_DOWN, *p); } + | '+' + count(p) + { *p = mknode(OP_UP, *p); } + ] + ; + +source_command(p_tree* p;) + : SOURCE + { extended_charset = 1; } + name(p) + { (*p)->t_idf = str2idf((*p)->t_str, 0); } + { + *p = mknode(OP_SOURCE, *p); + extended_charset = 0; + } + ; + +log_command(p_tree* p;) + : LOG + { extended_charset = 1; } + [ + name(p) + { (*p)->t_idf = str2idf((*p)->t_str, 0); } + | + { *p = 0; } + ] + { + *p = mknode(OP_LOG, *p); + extended_charset = 0; + } + ; + +where_command(p_tree* p;) + : WHERE + opt_num(p) + { *p = mknode(OP_WHERE, *p); } + ; + +list_command(p_tree* p;) + { + p_tree t1 = 0, t2 = 0; + } + : LIST + [ + | position(&t1) + | qualified_name(&t1) + ] + [ + ',' + count(&t2) + | '-' + [ + count(&t2) + { t2->t_ival = -t2->t_ival; } + | + { t2 = mknode(OP_INTEGER, -100000000L); } + ] + | + ] + { *p = mknode(OP_LIST, t1, t2); } + ; + +file_command(p_tree* p;) + : XFILE + { extended_charset = 1; } + [ + { *p = 0; } + | name(p) + { (*p)->t_idf = str2idf((*p)->t_str, 0); } + ] + { + *p = mknode(OP_FILE, *p); + extended_charset = 0; + } + ; + +help_command(p_tree* p;) + : [ + HELP + | '?' + ] + { *p = mknode(OP_HELP, (p_tree)0); } + [ + name(&(*p)->t_args[0])? + | '?' + { (*p)->t_args[0] = mknode(OP_NAME, str2idf("help", 0), (char*)0); } + | '!' + { (*p)->t_args[0] = mknode(OP_NAME, (struct idf*)0, "!"); } ] - { if (com) { - if (lastcom) { - freenode(lastcom); - lastcom = 0; - } - if (errorgiven) { - if (com != run_command) freenode(com); - com = 0; - } - else { - enterlog(com); - eval(com); - if (repeatable(com)) { - lastcom = com; - } - else if (! in_status(com) && - com != run_command && - com != print_command) { - freenode(com); - com = 0; - } - } - } else if (lastcom && ! errorgiven) { - enterlog(lastcom); - eval(lastcom); - } - if (give_prompt) { - errorgiven = 0; - interrupted = 0; - prompt(); - } - } - ]* -; - -command_line(p_tree *p;) -: - { *p = 0; } -[ - list_command(p) -| file_command(p) -| run_command(p) -| stop_command(p) -| when_command(p) -| continue_command(p) -| step_command(p) -| next_command(p) -| regs_command(p) -| where_command(p) -| STATUS { *p = mknode(OP_STATUS); } -| DUMP { *p = mknode(OP_DUMP); } -| RESTORE opt_num(p) { *p = mknode(OP_RESTORE, *p); } -| delete_command(p) -| print_command(p) -| display_command(p) -| trace_command(p) -| set_command(p) -| help_command(p) -| FIND qualified_name(p){ *p = mknode(OP_FIND, *p); } -| WHICH qualified_name(p){ *p = mknode(OP_WHICH, *p); } -| able_command(p) -| '!' { (void) shellescape(); - *p = mknode(OP_SHELL); - } -| source_command(p) -| log_command(p) -| frame_command(p) -| -] -; - -frame_command(p_tree *p;) -: - FRAME - [ { *p = mknode(OP_FRAME, (p_tree) 0); } - | count(p) { *p = mknode(OP_FRAME, *p); } - | '-' count(p) { *p = mknode(OP_DOWN, *p); } - | '+' count(p) { *p = mknode(OP_UP, *p); } - ] -; - -source_command(p_tree *p;) -: - SOURCE { extended_charset = 1; } - name(p) { (*p)->t_idf = str2idf((*p)->t_str, 0); } - { *p = mknode(OP_SOURCE, *p); - extended_charset = 0; - } -; - -log_command(p_tree *p;) -: - LOG { extended_charset = 1; } - [ name(p) { (*p)->t_idf = str2idf((*p)->t_str, 0); } - | { *p = 0; } - ] - { *p = mknode(OP_LOG, *p); - extended_charset = 0; - } -; - -where_command(p_tree *p;) -: - WHERE opt_num(p) { *p = mknode(OP_WHERE, *p); } -; - -list_command(p_tree *p;) - { p_tree t1 = 0, t2 = 0; } -: - LIST - [ - | position(&t1) - | qualified_name(&t1) - ] - [ ',' count(&t2) - | '-' - [ count(&t2) { t2->t_ival = - t2->t_ival; } - | { t2 = mknode(OP_INTEGER, -100000000L); } + ; + +run_command(p_tree* p;) + : RUN + { extended_charset = 1; } + args(p) + { + *p = mknode(OP_RUN, *p); + extended_charset = 0; + } + | RERUN + { if (!run_command) { error("no run command given yet"); } else *p = run_command; } + [ + '?' + { *p = mknode(OP_PRCOMM, *p); } + | ] - | - ] - { *p = mknode(OP_LIST, t1, t2); } -; - -file_command(p_tree *p;) -: - XFILE { extended_charset = 1; } - [ { *p = 0; } - | name(p) { (*p)->t_idf = str2idf((*p)->t_str, 0); } - ] { *p = mknode(OP_FILE, *p); - extended_charset = 0; - } -; - -help_command(p_tree *p;) -: - [ HELP | '?' ] - { *p = mknode(OP_HELP, (p_tree) 0); } - [ name(&(*p)->t_args[0])? - | '?' { (*p)->t_args[0] = mknode(OP_NAME, str2idf("help",0), (char *) 0); } - | '!' { (*p)->t_args[0] = mknode(OP_NAME, (struct idf *) 0, "!"); } - ] -; - -run_command(p_tree *p;) -: - RUN { extended_charset = 1; } - args(p) { *p = mknode(OP_RUN, *p); - extended_charset = 0; - } -| RERUN { if (! run_command) { - error("no run command given yet"); - } - else *p = run_command; - } - [ '?' { *p = mknode(OP_PRCOMM, *p); } - | - ] -; - -stop_command(p_tree *p;) - { p_tree whr = 0, cond = 0; } -: - STOP - where(&whr)? - condition(&cond)? { if (! whr && ! cond) { - error("no position or condition"); - *p = 0; - } - else *p = mknode(OP_STOP, whr, cond); - } -; - -trace_command(p_tree *p;) - { p_tree whr = 0, cond = 0, exp = 0; } -: - TRACE - [ ON format_expression(&exp) ]? - where(&whr)? - condition(&cond)? { *p = mknode(OP_TRACE, whr, cond, exp); } -; - -continue_command(p_tree *p;) - { long l; p_tree pos = 0; } -: - CONT - [ INTEGER { l = tok.ival; } - | { l = 1; } - ] - [ AT position(&pos) ]? - { *p = mknode(OP_CONT, mknode(OP_INTEGER, l), pos); } -; - -when_command(p_tree *p;) - { p_tree whr = 0, cond = 0; } -: - WHEN - where(&whr)? - condition(&cond)? { *p = mknode(OP_WHEN, whr, cond, (p_tree) 0); - p = &(*p)->t_args[2]; - } - '{' - command_line(p) - [ ';' { if (*p) { - *p = mknode(OP_LINK, *p, (p_tree) 0); - p = &((*p)->t_args[1]); - } - } + ; + +stop_command(p_tree* p;) + { + p_tree whr = 0, cond = 0; + } + : STOP + where(&whr)? + condition(&cond)? + { + if (!whr && !cond) + { + error("no position or condition"); + *p = 0; + } + else + *p = mknode(OP_STOP, whr, cond); + } + ; + +trace_command(p_tree* p;) + { + p_tree whr = 0, cond = 0, exp = 0; + } + : TRACE + [ + ON + format_expression(&exp) + ]? + where(&whr)? + condition(&cond)? + { *p = mknode(OP_TRACE, whr, cond, exp); } + ; + +continue_command(p_tree* p;) + { + long l; + p_tree pos = 0; + } + : CONT + [ + INTEGER + { l = tok.ival; } + | + { l = 1; } + ] + [ + AT + position(&pos) + ]? + { *p = mknode(OP_CONT, mknode(OP_INTEGER, l), pos); } + ; + +when_command(p_tree* p;) + { + p_tree whr = 0, cond = 0; + } + : WHEN + where(&whr)? + condition(&cond)? + { + *p = mknode(OP_WHEN, whr, cond, (p_tree)0); + p = &(*p)->t_args[2]; + } + '{' command_line(p) - ]* - '}' - { if (! whr && ! cond) { - error("no position or condition"); - } - else if (! *p) { - error("no commands given"); - } - } -; - -step_command(p_tree *p;) -: - STEP { *p = mknode(OP_STEP, (p_tree) 0); } - count(&(*p)->t_args[0])? -; - -next_command(p_tree *p;) -: - NEXT { *p = mknode(OP_NEXT, (p_tree) 0); } - count(&(*p)->t_args[0])? -; - -regs_command(p_tree *p;) -: - REGS { *p = mknode(OP_REGS, (p_tree) 0); } - count(&(*p)->t_args[0])? -; - -delete_command(p_tree *p;) -: - DELETE num_list(p)? { *p = mknode(OP_DELETE, *p); } -; - -print_command(p_tree *p;) -: - PRINT - [ format_expression_list(p) - { *p = mknode(OP_PRINT, *p); } - | - { *p = mknode(OP_PRINT, (p_tree) 0); } - ] -; - -display_command(p_tree *p;) -: - DISPLAY format_expression_list(p) - { *p = mknode(OP_DISPLAY, *p); } -; - -format_expression_list(p_tree *p;) -: - format_expression(p) - [ ',' { *p = mknode(OP_LINK, *p, (p_tree) 0); - p = &((*p)->t_args[1]); - } - format_expression(p) - ]* -; - -format_expression(p_tree *p;) - { p_tree p1; } -: - expression(p, 0) - [ '\\' name(&p1) { register char *c = p1->t_str; - while (*c) { - if (! strchr("doshcax", *c)) { - error("illegal format: %c", *c); - break; - } - c++; - } - *p = mknode(OP_FORMAT, *p, p1); - } - | - ] -; - -set_command(p_tree *p;) -: - SET expression(p, 0) { *p = mknode(OP_SET, *p, (p_tree) 0); } - TO expression(&((*p)->t_args[1]), 0) -; - -able_command(p_tree *p;) -: - [ ENABLE { *p = mknode(OP_ENABLE, (p_tree) 0); } - | DISABLE { *p = mknode(OP_DISABLE, (p_tree) 0); } - ] - num_list(&(*p)->t_args[0])? -; - -num_list(p_tree *p;) -: - num(p) - [ ',' { *p = mknode(OP_LINK, *p, (p_tree) 0); } - num(&(*p)->t_args[1]) - ]* -; - -condition(p_tree *p;) -: - IF expression(p, 0) -; - -where(p_tree *p;) -: - IN qualified_name(p) { *p = mknode(OP_IN, *p, (p_tree) 0); } - [ AT position(&((*p)->t_args[1])) ]? -| - AT position(p) -; - -expression(p_tree *p; int level;) - { int currprio, currop; } -: { in_expression++; } - factor(p) - [ %while ((currprio = binprio(currop = (int) tok.ival)) > level) - [ BIN_OP | PREF_OR_BIN_OP ] - { *p = mknode(OP_BINOP, *p, (p_tree) 0); - (*p)->t_whichoper = currop; - } - expression(&((*p)->t_args[1]), currprio) - | - SEL_OP { *p = mknode(OP_BINOP, *p, (p_tree) 0); - (*p)->t_whichoper = (int) tok.ival; - } - name(&(*p)->t_args[1]) - | - '[' { *p = mknode(OP_BINOP, *p, (p_tree) 0); - (*p)->t_whichoper = E_ARRAY; - } - expression(&(*p)->t_args[1], 0) - [ ',' { *p = mknode(OP_BINOP, *p, (p_tree) 0); - (*p)->t_whichoper = E_ARRAY; - } - expression(&(*p)->t_args[1], 0) - ]* - ']' - ]* - { in_expression--; } -; - -factor(p_tree *p;) -: - [ - %default EXPRESSION /* lexical analyzer will never return this token */ - { *p = mknode(OP_INTEGER, 0L); } - | - '(' expression(p, 0) ')' - | - INTEGER { *p = mknode(OP_INTEGER, tok.ival); } - | - REAL { *p = mknode(OP_REAL, tok.fval); } - | - STRING { *p = mknode(OP_STRING, tok.str); } - | - qualified_name(p) - | - { *p = mknode(OP_UNOP, (p_tree) 0); - (*p)->t_whichoper = (int) tok.ival; - } - [ PREF_OP - | PREF_OR_BIN_OP - { (*currlang->fix_bin_to_pref)(*p); } - ] - expression(&(*p)->t_args[0], unprio((*p)->t_whichoper)) - ] - [ %while(1) - POST_OP { *p = mknode(OP_UNOP, *p); - (*p)->t_whichoper = (int) tok.ival; - } - ]* -; - -position(p_tree *p;) - { p_tree lin; - char *str; - } -: - [ STRING { str = tok.str; } - ':' - | { if (! listfile) str = 0; - else str = listfile->sy_idf->id_text; - } - ] - count(&lin) { *p = mknode(OP_AT, lin->t_ival, str); - freenode(lin); - } -; - -args(p_tree *p;) - { int first_time = 1; } -: - [ { if (! first_time) { - *p = mknode(OP_LINK, *p, (p_tree) 0); - p = &((*p)->t_args[1]); - } - first_time = 0; - } - arg(p) - ]* -; - -arg(p_tree *p;) -: - name(p) -| - '>' name(p) { (*p)->t_oper = OP_OUTPUT; } -| - '<' name(p) { (*p)->t_oper = OP_INPUT; } -; - -count(p_tree *p;) -: - INTEGER { *p = mknode(OP_INTEGER, tok.ival); } -; - -opt_num(p_tree *p;) -: - num(p) -| - { *p = 0; } -; - -num(p_tree *p;) -: - count(p) -| - '-' count(p) { (*p)->t_ival = - (*p)->t_ival; } -; - -qualified_name(p_tree *p;) -: - name(p) - [ '`' { *p = mknode(OP_SELECT, *p, (p_tree) 0); } - name(&((*p)->t_args[1])) - ]* -; - -name(p_tree *p;) -: - [ XFILE - | LIST - | RUN - | RERUN - | STOP - | WHEN - | AT - | IN - | IF - | %default NAME - | CONT - | STEP - | NEXT - | REGS - | WHERE - | STATUS - | PRINT - | DELETE - | DUMP - | RESTORE - | TRACE - | ON - | SET - | TO - | FIND - | DISPLAY - | WHICH - | HELP - | DISABLE - | ENABLE - | SOURCE - | FRAME - | LOG - ] { *p = mknode(OP_NAME, tok.idf, tok.str); } -; - -{ -int -LLlex() -{ - int c; - - if (ASIDE) { - tok = aside; - ASIDE = 0; - return TOK; - } - do { - c = getc(db_in); - if (interrupted && c == EOF) { - c = ' '; - interrupted = 0; - continue; - } - } while (c != EOF && class(c) == STSKIP); - if (c == EOF) { - eof_seen = 1; - return c; - } - if (extended_charset && in_ext(c)) { - TOK = get_name(c); - return TOK; - } - switch(class(c)) { - case STSTR: - TOK = (*currlang->get_string)(c); - break; - case STIDF: - if (in_expression) TOK = (*currlang->get_name)(c); - else TOK = get_name(c); - break; - case STNUM: - TOK = (*currlang->get_number)(c); - break; - case STNL: - TOK = c; - break; - case STSIMP: - if (! in_expression) { - TOK = c; - break; - } - /* Fall through */ - default: - TOK = (*currlang->get_token)(c); - break; - } - return TOK; -} - -int -get_name(c) - int c; -{ - char buf[512+1]; - char *p = &buf[0]; - struct idf *id; - - do { - if (p - buf < 512) *p++ = c; - c = getc(db_in); - } while ((extended_charset && in_ext(c)) || in_idf(c)); - ungetc(c, db_in); - *p++ = 0; - if (extended_charset) { - tok.idf = 0; - tok.str = Salloc(buf, (unsigned) (p - buf)); - return NAME; - } - id = str2idf(buf, 1); - tok.idf = id; - tok.str = id->id_text; - return id->id_reserved ? id->id_reserved : NAME; -} - -extern char *symbol2str(); - -LLmessage(t) -{ - if (t > 0) { - if (! errorgiven) { - error("%s missing before %s", symbol2str(t), symbol2str(TOK)); - } - aside = tok; - } - else if (t == 0) { - if (! errorgiven) { - error("%s unexpected", symbol2str(TOK)); - } - } - else if (! errorgiven) { - error("EOF expected"); - } - errorgiven = 1; -} - -static void -catch_del() -{ - signal(SIGINT, catch_del); - if (! disable_intr) { - signal_child(7); - child_interrupted = 1; - } - interrupted = 1; -} - -void -init_del() -{ - signal(SIGINT, catch_del); -} - -static void -ctch() -{ - /* Only for shell escapes ... */ - signal(SIGINT, ctch); -} - -#define SHBUFSIZ 512 + [ + ';' + { if (*p) { *p = mknode(OP_LINK, *p, (p_tree)0); p = &((*p)->t_args[1]); } } + command_line(p) + ]* + '}' + { + if (!whr && !cond) + { + error("no position or condition"); + } + else if (!*p) + { + error("no commands given"); + } + } + ; + +step_command(p_tree* p;) + : STEP + { *p = mknode(OP_STEP, (p_tree)0); } + count(&(*p)->t_args[0])? + ; + +next_command(p_tree* p;) + : NEXT + { *p = mknode(OP_NEXT, (p_tree)0); } + count(&(*p)->t_args[0])? + ; + +regs_command(p_tree* p;) + : REGS + { *p = mknode(OP_REGS, (p_tree)0); } + count(&(*p)->t_args[0])? + ; + +delete_command(p_tree* p;) + : DELETE + num_list(p)? + { *p = mknode(OP_DELETE, *p); } + ; + +print_command(p_tree* p;) + : PRINT + [ + format_expression_list(p) + { *p = mknode(OP_PRINT, *p); } + | + { *p = mknode(OP_PRINT, (p_tree)0); } + ] + ; + +display_command(p_tree* p;) + : DISPLAY + format_expression_list(p) + { *p = mknode(OP_DISPLAY, *p); } + ; + +format_expression_list(p_tree* p;) + : format_expression(p) + [ + ',' + { + *p = mknode(OP_LINK, *p, (p_tree)0); + p = &((*p)->t_args[1]); + } + format_expression(p) + ]* + ; + +format_expression(p_tree* p;) + { + p_tree p1; + } + : expression(p, 0) + [ + '\\' + name(&p1) + { + register char* c = p1->t_str; + while (*c) + { + if (!strchr("doshcax", *c)) + { + error("illegal format: %c", *c); + break; + } + c++; + } + *p = mknode(OP_FORMAT, *p, p1); + } + | + ] + ; + +set_command(p_tree* p;) + : SET + expression(p, 0) + { *p = mknode(OP_SET, *p, (p_tree)0); } + TO + expression(&((*p)->t_args[1]), 0) + ; + +able_command(p_tree* p;) + : [ + ENABLE + { *p = mknode(OP_ENABLE, (p_tree)0); } + | DISABLE + { *p = mknode(OP_DISABLE, (p_tree)0); } + ] + num_list(&(*p)->t_args[0])? + ; + +num_list(p_tree* p;) + : num(p) + [ + ',' + { *p = mknode(OP_LINK, *p, (p_tree)0); } + num(&(*p)->t_args[1]) + ]* + ; + +condition(p_tree* p;) + : IF + expression(p, 0) + ; + +where(p_tree* p;) + : IN + qualified_name(p) + { *p = mknode(OP_IN, *p, (p_tree)0); } + [ + AT + position(&((*p)->t_args[1])) + ]? + | AT + position(p) + ; + +expression(p_tree* p; int level;) + { + int currprio, currop; + } + : + { in_expression++; } + factor(p) + [ + %while ((currprio = binprio(currop = (int)tok.ival)) > level) + [ + BIN_OP + | PREF_OR_BIN_OP + ] + { + *p = mknode(OP_BINOP, *p, (p_tree)0); + (*p)->t_whichoper = currop; + } + expression(&((*p)->t_args[1]), currprio) + | SEL_OP + { + *p = mknode(OP_BINOP, *p, (p_tree)0); + (*p)->t_whichoper = (int)tok.ival; + } + name(&(*p)->t_args[1]) + | '[' + { + *p = mknode(OP_BINOP, *p, (p_tree)0); + (*p)->t_whichoper = E_ARRAY; + } + expression(&(*p)->t_args[1], 0) + [ + ',' + { + *p = mknode(OP_BINOP, *p, (p_tree)0); + (*p)->t_whichoper = E_ARRAY; + } + expression(&(*p)->t_args[1], 0) + ]* + ']' + ]* + { in_expression--; } + ; + +factor(p_tree* p;) + : [ + %default + EXPRESSION + /* lexical analyzer will never return this token */ + { *p = mknode(OP_INTEGER, 0L); } + | '(' + expression(p, 0) + ')' + | INTEGER + { *p = mknode(OP_INTEGER, tok.ival); } + | REAL + { *p = mknode(OP_REAL, tok.fval); } + | STRING + { *p = mknode(OP_STRING, tok.str); } + | qualified_name(p) + | + { + *p = mknode(OP_UNOP, (p_tree)0); + (*p)->t_whichoper = (int)tok.ival; + } + [ + PREF_OP + | PREF_OR_BIN_OP + { (*currlang->fix_bin_to_pref)(*p); } + ] + expression(&(*p)->t_args[0], unprio((*p)->t_whichoper)) + ] + [ + %while (1) + POST_OP + { + *p = mknode(OP_UNOP, *p); + (*p)->t_whichoper = (int)tok.ival; + } + ]* + ; + +position(p_tree* p;) + { + p_tree lin; + char* str; + } + : [ + STRING + { str = tok.str; } + ':' + | + { if (!listfile) str = 0; else str = listfile->sy_idf->id_text; } + ] + count(&lin) + { + *p = mknode(OP_AT, lin->t_ival, str); + freenode(lin); + } + ; + +args(p_tree* p;) + { + int first_time = 1; + } + : [ + { + if (!first_time) + { + *p = mknode(OP_LINK, *p, (p_tree)0); + p = &((*p)->t_args[1]); + } + first_time = 0; + } + arg(p) + ]* + ; + +arg(p_tree* p;) + : name(p) + | '>' + name(p) + { (*p)->t_oper = OP_OUTPUT; } + | '<' + name(p) + { (*p)->t_oper = OP_INPUT; } + ; + +count(p_tree* p;) + : INTEGER + { *p = mknode(OP_INTEGER, tok.ival); } + ; + +opt_num(p_tree* p;) + : num(p) + | + { *p = 0; } + ; + +num(p_tree* p;) + : count(p) + | '-' + count(p) + { (*p)->t_ival = -(*p)->t_ival; } + ; + +qualified_name(p_tree* p;) + : name(p) + [ + '`' + { *p = mknode(OP_SELECT, *p, (p_tree)0); } + name(&((*p)->t_args[1])) + ]* + ; + +name(p_tree* p;) + : [ + XFILE + | LIST + | RUN + | RERUN + | STOP + | WHEN + | AT + | IN + | IF + | %default + NAME + | CONT + | STEP + | NEXT + | REGS + | WHERE + | STATUS + | PRINT + | DELETE + | DUMP + | RESTORE + | TRACE + | ON + | SET + | TO + | FIND + | DISPLAY + | WHICH + | HELP + | DISABLE + | ENABLE + | SOURCE + | FRAME + | LOG + ] + { *p = mknode(OP_NAME, tok.idf, tok.str); } + ; -static int -shellescape() { - char *p; /* walks through command */ - static char previous[SHBUFSIZ]; /* previous command */ - char comm[SHBUFSIZ]; /* space for command */ - int cnt; /* prevent array bound errors */ - int c; /* current char */ - int lastc = 0; /* will contain the previous char */ - - p = comm; - cnt = SHBUFSIZ-2; - while (c = getc(db_in), c != '\n') { - switch(c) { - case '!': - /* - * An unescaped ! expands to the previous - * command, but disappears if there is none - */ - if (lastc != '\\') { - if (*previous) { - int len = strlen(previous); - if ((cnt -= len) <= 0) break; - strcpy(p,previous); - p += len; - } - } - else { - *p++ = c; - } - continue; - case '%': - /* - * An unescaped % will expand to the current - * filename, but disappears is there is none - */ - if (lastc != '\\') { - if (listfile) { - int len = strlen(listfile->sy_idf->id_text); - if ((cnt -= len) <= 0) break; - strcpy(p,listfile->sy_idf->id_text); - p += len; - } - } - else { - *p++ = c; - } - continue; - default: - lastc = c; - if (cnt-- <= 0) break; - *p++ = c; - continue; - } - break; - } - *p = '\0'; - if (c != '\n') { - warning("shell command too long"); - while (c != '\n') c = getc(db_in); - } - ungetc(c, db_in); - strcpy(previous, comm); - signal(SIGINT, ctch); - cnt = system(comm); - signal(SIGINT, catch_del); - return cnt; -} + int LLlex() + { + int c; + + if (ASIDE) + { + tok = aside; + ASIDE = 0; + return TOK; + } + do + { + c = getc(db_in); + if (interrupted && c == EOF) + { + c = ' '; + interrupted = 0; + continue; + } + } while (c != EOF && class(c) == STSKIP); + if (c == EOF) + { + eof_seen = 1; + return c; + } + if (extended_charset && in_ext(c)) + { + TOK = get_name(c); + return TOK; + } + switch (class(c)) + { + case STSTR: + TOK = (*currlang->get_string)(c); + break; + case STIDF: + if (in_expression) + TOK = (*currlang->get_name)(c); + else + TOK = get_name(c); + break; + case STNUM: + TOK = (*currlang->get_number)(c); + break; + case STNL: + TOK = c; + break; + case STSIMP: + if (!in_expression) + { + TOK = c; + break; + } + /* Fall through */ + default: + TOK = (*currlang->get_token)(c); + break; + } + return TOK; + } + + int get_name(c) int c; + { + char buf[512 + 1]; + char* p = &buf[0]; + struct idf* id; + + do + { + if (p - buf < 512) + *p++ = c; + c = getc(db_in); + } while ((extended_charset && in_ext(c)) || in_idf(c)); + ungetc(c, db_in); + *p++ = 0; + if (extended_charset) + { + tok.idf = 0; + tok.str = Salloc(buf, (unsigned)(p - buf)); + return NAME; + } + id = str2idf(buf, 1); + tok.idf = id; + tok.str = id->id_text; + return id->id_reserved ? id->id_reserved : NAME; + } + + extern char* symbol2str(); + + LLmessage(t) + { + if (t > 0) + { + if (!errorgiven) + { + error("%s missing before %s", symbol2str(t), symbol2str(TOK)); + } + aside = tok; + } + else if (t == 0) + { + if (!errorgiven) + { + error("%s unexpected", symbol2str(TOK)); + } + } + else if (!errorgiven) + { + error("EOF expected"); + } + errorgiven = 1; + } + + static void catch_del() + { + signal(SIGINT, catch_del); + if (!disable_intr) + { + signal_child(7); + child_interrupted = 1; + } + interrupted = 1; + } + + void init_del() + { + signal(SIGINT, catch_del); + } + + static void ctch() + { + /* Only for shell escapes ... */ + signal(SIGINT, ctch); + } + + #define SHBUFSIZ 512 + + static int shellescape() + { + char* p; /* walks through command */ + static char previous[SHBUFSIZ]; /* previous command */ + char comm[SHBUFSIZ]; /* space for command */ + int cnt; /* prevent array bound errors */ + int c; /* current char */ + int lastc = 0; /* will contain the previous char */ + + p = comm; + cnt = SHBUFSIZ - 2; + while (c = getc(db_in), c != '\n') + { + switch (c) + { + case '!': + /* + * An unescaped ! expands to the previous + * command, but disappears if there is none + */ + if (lastc != '\\') + { + if (*previous) + { + int len = strlen(previous); + if ((cnt -= len) <= 0) + break; + strcpy(p, previous); + p += len; + } + } + else + { + *p++ = c; + } + continue; + case '%': + /* + * An unescaped % will expand to the current + * filename, but disappears is there is none + */ + if (lastc != '\\') + { + if (listfile) + { + int len = strlen(listfile->sy_idf->id_text); + if ((cnt -= len) <= 0) + break; + strcpy(p, listfile->sy_idf->id_text); + p += len; + } + } + else + { + *p++ = c; + } + continue; + default: + lastc = c; + if (cnt-- <= 0) + break; + *p++ = c; + continue; + } + break; + } + *p = '\0'; + if (c != '\n') + { + warning("shell command too long"); + while (c != '\n') + c = getc(db_in); + } + ungetc(c, db_in); + strcpy(previous, comm); + signal(SIGINT, ctch); + cnt = system(comm); + signal(SIGINT, catch_del); + return cnt; + } } diff --git a/util/grind/db_symtab.g b/util/grind/db_symtab.g index e996721ea..f2096ad28 100644 --- a/util/grind/db_symtab.g +++ b/util/grind/db_symtab.g @@ -1,928 +1,1095 @@ +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i util/grind/db_symtab.g + */ + /* $Id$ */ /* Symbol table reader -*/ + */ { -#include -#include -#include - -#include "position.h" -#include "file.h" -#include "type.h" -#include "symbol.h" -#include "scope.h" -#include "class.h" -#include "idf.h" -#include "rd.h" -#include "misc.h" - -extern char *strchr(); -extern long str2long(); -extern double atof(); - -static char *DbPtr; /* current pointer in db string */ -static int AllowName; /* set if NAME legal at this point */ -static long ival; -static double fval; -static char *strval; -static int last_index[2]; -static struct outname *currnam; -static int saw_code; - -static struct literal *get_literal_space(); -static struct fields *get_field_space(); -static end_field(); -static char *string_val(); + #include + #include + #include + + #include "position.h" + #include "file.h" + #include "type.h" + #include "symbol.h" + #include "scope.h" + #include "class.h" + #include "idf.h" + #include "rd.h" + #include "misc.h" + + extern char* strchr(); + extern long str2long(); + extern double atof(); + + static char* DbPtr; /* current pointer in db string */ + static int AllowName; /* set if NAME legal at this point */ + static long ival; + static double fval; + static char* strval; + static int last_index[2]; + static struct outname* currnam; + static int saw_code; + + static struct literal* get_literal_space(); + static struct fields* get_field_space(); + static end_field(); + static char* string_val(); } %start DbParser, debugger_string; - %prefix DBS; - %lexical DBSlex; - %onerror DBSonerror; - -%token INTEGER, REAL, STRING, NAME; +%token INTEGER, REAL, STRING, NAME; debugger_string - { register p_symbol s; - char *str; - p_type tmp = 0; - int upb = 0; - } -: - name(&str) - [ /* constant name */ - { s = NewSymbol(str, CurrentScope, CONST, currnam); } - 'c' const_name(s) - - | /* type name */ - { s = NewSymbol(str, CurrentScope, TYPE, currnam); } - 't' type_name(&(s->sy_type), s) - { if (! s->sy_type->ty_sym) s->sy_type->ty_sym = s; - if ((s->sy_type->ty_class == T_ENUM || - s->sy_type->ty_class == T_SUBRANGE) && - currnam->on_desc != 0) { - s->sy_type->ty_size = currnam->on_desc; - } - } - | /* tag name (only C?) */ - { s = NewSymbol(str, CurrentScope, TAG, currnam); } - 'T' type_name(&(s->sy_type), s) - { if (! s->sy_type->ty_sym) s->sy_type->ty_sym = s; - if (s->sy_type->ty_class != T_CROSS) { - resolve_cross(s->sy_type); - } - } - | /* end scope */ - 'E' INTEGER - { close_scope(); } - - | /* module begin */ - { s = NewSymbol(str, CurrentScope, MODULE, currnam); } - 'M' INTEGER - { open_scope(s, 1); - s->sy_name.nm_scope = CurrentScope; - CurrentScope->sc_start = currnam->on_valu; - CurrentScope->sc_proclevel = currnam->on_desc; - add_scope_addr(CurrentScope); - } - - | /* external procedure */ - { s = NewSymbol(str, FileScope, PROC, currnam); } - 'P' routine(s) - - | /* private procedure */ - { s = NewSymbol(str, CurrentScope, PROC, currnam); } - 'Q' routine(s) - - | /* external function */ - { s = NewSymbol(str, FileScope, FUNCTION, currnam); } - 'F' function(s) - - | /* private function */ - { s = NewSymbol(str, CurrentScope, FUNCTION, currnam); } - 'f' function(s) - - | /* global variable, external */ - /* maybe we already know it; but we need - the type information anyway for other - types. - */ - { s = Lookup(findidf(str), FileScope, VAR); - if (s) { - tmp = s->sy_type; - s->sy_type = 0; - } else s = NewSymbol(str, FileScope, VAR, currnam); - } - 'G' type(&(s->sy_type), (int *) 0, s) - { if (tmp) s->sy_type = tmp; } - - | /* static variable */ - { s = NewSymbol(str, CurrentScope, VAR, currnam); } - 'S' type(&(s->sy_type), (int *) 0, s) - - | /* static variable, local scope */ - { s = NewSymbol(str, CurrentScope, VAR, currnam); } - 'V' type(&(s->sy_type), (int *) 0, s) - - | /* register variable */ - { s = NewSymbol(str, CurrentScope, REGVAR, currnam); } - 'r' type(&(s->sy_type), (int *) 0, s) - - | /* value parameter */ - { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); } - 'p' type(&(s->sy_type), (int *) 0, s) - { add_param_type('p', s); } - - | /* value parameter but address passed */ - { s = NewSymbol(str, CurrentScope, VARPAR, currnam); } - 'i' type(&(s->sy_type), (int *) 0, s) - { add_param_type('i', s); } - - | /* variable parameter */ - { s = NewSymbol(str, CurrentScope, VARPAR, currnam); } - 'v' type(&(s->sy_type), (int *) 0, s) - { add_param_type('v', s); } - - | /* local variable */ - { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); } - type_name(&(s->sy_type), s) - - | /* lower or upper bound of array descriptor */ - [ 'A' { upb = LBOUND; } - | 'Z' { upb = UBOUND; } - ] - [ ['p' | ] { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); - if (upb == UBOUND) add_param_type('Z', s); - } - | [ 'V' | 'S' ] { s = NewSymbol(str, CurrentScope, VAR, currnam); } - ] - type_name(&(s->sy_type), s) - { p_symbol s1 = new_symbol(); - *s1 = *s; - s->sy_class = upb; - s->sy_descr = s1; - } - - | /* function result in Pascal; ignore ??? */ - { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); } - 'X' type_name(&(s->sy_type), s) - ] - ';'? -; - -name(char **s;) -: - /* anything up to a ':' */ - NAME { *s = strval; } -; + { + register p_symbol s; + char* str; + p_type tmp = 0; + int upb = 0; + } + : name(&str) + [ + /* constant name */ + { s = NewSymbol(str, CurrentScope, CONST, currnam); } + 'c' + const_name(s) + | + /* type name */ + { s = NewSymbol(str, CurrentScope, TYPE, currnam); } + 't' + type_name(&(s->sy_type), s) + { + if (!s->sy_type->ty_sym) + s->sy_type->ty_sym = s; + if ((s->sy_type->ty_class == T_ENUM || s->sy_type->ty_class == T_SUBRANGE) + && currnam->on_desc != 0) + { + s->sy_type->ty_size = currnam->on_desc; + } + } + | + /* tag name (only C?) */ + { s = NewSymbol(str, CurrentScope, TAG, currnam); } + 'T' + type_name(&(s->sy_type), s) + { + if (!s->sy_type->ty_sym) + s->sy_type->ty_sym = s; + if (s->sy_type->ty_class != T_CROSS) + { + resolve_cross(s->sy_type); + } + } + | + /* end scope */ + 'E' INTEGER + { close_scope(); } + | + /* module begin */ + { s = NewSymbol(str, CurrentScope, MODULE, currnam); } + 'M' INTEGER + { + open_scope(s, 1); + s->sy_name.nm_scope = CurrentScope; + CurrentScope->sc_start = currnam->on_valu; + CurrentScope->sc_proclevel = currnam->on_desc; + add_scope_addr(CurrentScope); + } + | + /* external procedure */ + { s = NewSymbol(str, FileScope, PROC, currnam); } + 'P' + routine(s) + | + /* private procedure */ + { s = NewSymbol(str, CurrentScope, PROC, currnam); } + 'Q' + routine(s) + | + /* external function */ + { s = NewSymbol(str, FileScope, FUNCTION, currnam); } + 'F' + function(s) + | + /* private function */ + { s = NewSymbol(str, CurrentScope, FUNCTION, currnam); } + 'f' + function(s) + | + /* global variable, external */ + /* maybe we already know it; but we need + the type information anyway for other + types. + */ + { + s = Lookup(findidf(str), FileScope, VAR); + if (s) + { + tmp = s->sy_type; + s->sy_type = 0; + } + else + s = NewSymbol(str, FileScope, VAR, currnam); + } + 'G' + type(&(s->sy_type), (int*)0, s) + { if (tmp) s->sy_type = tmp; } + | + /* static variable */ + { s = NewSymbol(str, CurrentScope, VAR, currnam); } + 'S' + type(&(s->sy_type), (int*)0, s) + | + /* static variable, local scope */ + { s = NewSymbol(str, CurrentScope, VAR, currnam); } + 'V' + type(&(s->sy_type), (int*)0, s) + | + /* register variable */ + { s = NewSymbol(str, CurrentScope, REGVAR, currnam); } + 'r' + type(&(s->sy_type), (int*)0, s) + | + /* value parameter */ + { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); } + 'p' + type(&(s->sy_type), (int*)0, s) + { add_param_type('p', s); } + | + /* value parameter but address passed */ + { s = NewSymbol(str, CurrentScope, VARPAR, currnam); } + 'i' + type(&(s->sy_type), (int*)0, s) + { add_param_type('i', s); } + | + /* variable parameter */ + { s = NewSymbol(str, CurrentScope, VARPAR, currnam); } + 'v' + type(&(s->sy_type), (int*)0, s) + { add_param_type('v', s); } + | + /* local variable */ + { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); } + type_name(&(s->sy_type), s) + | + /* lower or upper bound of array descriptor */ + [ + 'A' + { upb = LBOUND; } + | 'Z' + { upb = UBOUND; } + ] + [ + [ + 'p' + | + ] + { + s = NewSymbol(str, CurrentScope, LOCVAR, currnam); + if (upb == UBOUND) + add_param_type('Z', s); + } + | [ + 'V' + | 'S' + ] + { s = NewSymbol(str, CurrentScope, VAR, currnam); } + ] + type_name(&(s->sy_type), s) + { + p_symbol s1 = new_symbol(); + *s1 = *s; + s->sy_class = upb; + s->sy_descr = s1; + } + | + /* function result in Pascal; ignore ??? */ + { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); } + 'X' + type_name(&(s->sy_type), s) + ] + ';'? + ; + +name(char** s;) + : + /* anything up to a ':' */ + NAME + { *s = strval; } + ; const_name(p_symbol cst;) - { int type_index[2]; - long iconst; - char *p; - } -: - '=' - [ -/* - 'b' integer_const(&(cst->sy_const.co_ival)) /* boolean */ -/* | -*/ - 'c' integer_const(&(cst->sy_const.co_ival)) /* character */ - { cst->sy_type = char_type; } - | - 'i' integer_const(&(cst->sy_const.co_ival)) /* integer */ - { cst->sy_type = long_type; } - | - 'r' real_const(&(cst->sy_const.co_rval)) /* real */ - { cst->sy_type = double_type; } - | - 's' string_const /* string */ - { cst->sy_const.co_sval = string_val(strval); - cst->sy_type = string_type; - } - | - 'e' type_index(type_index) ',' integer_const(&(cst->sy_const.co_ival)) - /* enumeration constant; - * enumeration type, value - */ - { cst->sy_type = *tp_lookup(type_index); } - - | - 'S' type_index(type_index) - { cst->sy_type = *tp_lookup(type_index); - cst->sy_const.co_setval = p = - malloc((unsigned) cst->sy_type->ty_size); - } - [ ',' integer_const(&iconst) - { *p++ = iconst; } - ]+ - /* set constant: - * settype, values of the bytes - * in the set. - */ - ] -; - -integer_const(long *iconst;) - { int sign = 0; } -: - [ '+' | '-' { sign = 1; } ]? - INTEGER { *iconst = sign ? -ival : ival; } -; - -real_const(double *f;) - { int sign = 0; } -: - [ '+' | '-' { sign = 1; } ]? - REAL { *f = sign ? fval : -fval; } -; + { + int type_index[2]; + long iconst; + char* p; + } + : '=' + [ + /* + 'b' integer_const(&(cst->sy_const.co_ival)) /* boolean */ + /* | + */ + 'c' + integer_const(&(cst->sy_const.co_ival)) + /* character */ + { cst->sy_type = char_type; } + | 'i' + integer_const(&(cst->sy_const.co_ival)) + /* integer */ + { cst->sy_type = long_type; } + | 'r' + real_const(&(cst->sy_const.co_rval)) + /* real */ + { cst->sy_type = double_type; } + | 's' string_const + /* string */ + { + cst->sy_const.co_sval = string_val(strval); + cst->sy_type = string_type; + } + | 'e' + type_index(type_index) + ',' + integer_const(&(cst->sy_const.co_ival)) + /* enumeration constant; + * enumeration type, value + */ + { cst->sy_type = *tp_lookup(type_index); } + | 'S' + type_index(type_index) + { + cst->sy_type = *tp_lookup(type_index); + cst->sy_const.co_setval = p = malloc((unsigned)cst->sy_type->ty_size); + } + [ + ',' + integer_const(&iconst) + { *p++ = iconst; } + ]+ + /* set constant: + * settype, values of the bytes + * in the set. + */ + ] + ; + +integer_const(long* iconst;) + { + int sign = 0; + } + : [ + '+' + | '-' + { sign = 1; } + ]? + INTEGER + { *iconst = sign ? -ival : ival; } + ; + +real_const(double* f;) + { + int sign = 0; + } + : [ + '+' + | '-' + { sign = 1; } + ]? + REAL + { *f = sign ? fval : -fval; } + ; string_const -: - STRING /* has SINGLE quotes! */ -; - -type_name(p_type *t; p_symbol sy;) - { int type_index[2]; p_type *p; } -: - type_index(type_index) { p = tp_lookup(type_index); } - [ - { if (*p && (*p)->ty_class != 0 && - (*p)->ty_class != T_CROSS) { - error("Redefining (%d,%d) %d", - type_index[0], - type_index[1], - (*p)->ty_class); - } - } - '=' - type(p, type_index, sy) - | - { if (*t && ! *p) *p = *t; - else if (*t) **t = **p; - } - ] - { if (*p == 0) *p = new_type(); - *t = *p; - } -; - -type_index(int *type_index;) -: -[ - INTEGER { type_index[0] = 0; type_index[1] = ival; } -| - '(' INTEGER { type_index[0] = ival; } - ',' INTEGER { type_index[1] = ival; } - ')' -] - { last_index[0] = type_index[0]; - last_index[1] = type_index[1]; - } -; + : STRING + /* has SINGLE quotes! */ + ; + +type_name(p_type* t; p_symbol sy;) + { + int type_index[2]; + p_type* p; + } + : type_index(type_index) + { p = tp_lookup(type_index); } + [ + { + if (*p && (*p)->ty_class != 0 && (*p)->ty_class != T_CROSS) + { + error("Redefining (%d,%d) %d", type_index[0], type_index[1], (*p)->ty_class); + } + } + '=' + type(p, type_index, sy) + | + { if (*t && !*p) *p = *t; else if (*t) **t = **p; } + ] + { + if (*p == 0) + *p = new_type(); + *t = *p; + } + ; + +type_index(int* type_index;) + : [ + INTEGER + { + type_index[0] = 0; + type_index[1] = ival; + } + | '(' INTEGER + { type_index[0] = ival; } + ',' INTEGER + { type_index[1] = ival; } + ')' + ] + { + last_index[0] = type_index[0]; + last_index[1] = type_index[1]; + } + ; function(p_symbol p;) -: - { p->sy_type = new_type(); - p->sy_type->ty_class = T_PROCEDURE; - p->sy_type->ty_size = pointer_size; - } - type(&(p->sy_type->ty_retval), (int *) 0, (p_symbol) 0) - { if (CurrentScope != FileScope && - saw_code) { - /* if saw_code is not set, it is a nested - procedure - */ - close_scope(); - } - saw_code = 0; - open_scope(p, 1); - p->sy_name.nm_scope = CurrentScope; - CurrentScope->sc_start = currnam->on_valu; - add_scope_addr(CurrentScope); - CurrentScope->sc_proclevel = currnam->on_desc; - } -; + : + { + p->sy_type = new_type(); + p->sy_type->ty_class = T_PROCEDURE; + p->sy_type->ty_size = pointer_size; + } + type(&(p->sy_type->ty_retval), (int*)0, (p_symbol)0) + { + if (CurrentScope != FileScope && saw_code) + { + /* if saw_code is not set, it is a nested + procedure + */ + close_scope(); + } + saw_code = 0; + open_scope(p, 1); + p->sy_name.nm_scope = CurrentScope; + CurrentScope->sc_start = currnam->on_valu; + add_scope_addr(CurrentScope); + CurrentScope->sc_proclevel = currnam->on_desc; + } + ; routine(p_symbol p;) -: - { p->sy_type = new_type(); - p->sy_type->ty_class = T_PROCEDURE; - p->sy_type->ty_size = pointer_size; - if (CurrentScope != FileScope && - saw_code) { - /* if saw_code is not set, it is a nested - procedure - */ - close_scope(); - } - saw_code = 0; - open_scope(p, 1); - p->sy_name.nm_scope = CurrentScope; - CurrentScope->sc_start = currnam->on_valu; - add_scope_addr(CurrentScope); - CurrentScope->sc_proclevel = currnam->on_desc; - } - INTEGER ';' - type(&(p->sy_type->ty_retval), (int *) 0, (p_symbol) 0) -; - -type(p_type *ptp; int *type_index; p_symbol sy;) - { register p_type tp = *ptp ? *ptp : new_type(); - p_type t1 = 0, t2 = 0; - long ic1, ic2; - int A_used = 0; - int tclass; - int tp_index[2]; - char *str; - } -: - [ - /* type cross reference */ - /* these are used in C for references to a struct, union or - * enum that has not been declared (yet) - */ - 'x' - [ 's' /* struct */ - { tclass = T_STRUCT; } - | 'u' /* union */ - { tclass = T_UNION; } - | 'e' /* enum */ - { tclass = T_ENUM; } - ] - { AllowName = 1; } - name(&str) - { sy = Lookfromscope(str2idf(str,0),TAG,CurrentScope); - if (sy && - (sy->sy_type->ty_class == tclass || - sy->sy_type->ty_class == T_CROSS)) { - if (tp != *ptp) free_type(tp); - tp = sy->sy_type; - } - else { - tp->ty_class = T_CROSS; - tp->ty_size = tclass; - sy = NewSymbol(str, CurrentScope, TAG, (struct outname *) 0); - sy->sy_type = tp; - } - } - | - /* subrange */ - /* the integer_const's represent the lower and the upper bound. - * A subrange type defined as subrange of itself is an integer type. - * If the second integer_const == 0, but the first is not, we - * have a floating point type with size equal to the first - * integer_const. - * Upperbound -1 means unsigned int or unsigned long. - */ - 'r' type_index(tp_index) ';' - [ 'A' integer_const(&ic1) { A_used = 1; } - | integer_const(&ic1) - ] - ';' - [ 'A' integer_const(&ic2) { A_used |= 2; } - | integer_const(&ic2) - | 'Z' integer_const(&ic2) { A_used |= 0200; } - ] - { if (tp != *ptp) free_type(tp); - tp = subrange_type(A_used, - tp_index, - ic1, - ic2, - type_index); - } - | - /* array; first type is bound type, next type - * is element type - */ - 'a' type(&t1, (int *) 0, (p_symbol) 0) ';' type(&t2, (int *) 0, (p_symbol) 0) - { if (tp != *ptp) free_type(tp); - tp = array_type(t1, t2); - } - | - /* structure type */ - 's' { tp->ty_class = T_STRUCT; } - structure_type(tp, sy) - | - /* union type */ - 'u' { tp->ty_class = T_UNION; } - structure_type(tp, sy) - | - /* enumeration type */ - 'e' { tp->ty_class = T_ENUM; } - enum_type(tp) - | - /* pointer type */ - '*' { tp->ty_class = T_POINTER; - tp->ty_size = pointer_size; - } - type(&(tp->ty_ptrto), (int *) 0, (p_symbol) 0) - | - /* function type */ - 'f' { tp->ty_class = T_PROCEDURE; - tp->ty_size = pointer_size; - } - type(&(tp->ty_retval), (int *) 0, (p_symbol) 0) -/* - [ %prefer - ',' param_list(tp) - | - ] -*/ - | - /* procedure type */ - 'Q' { tp->ty_class = T_PROCEDURE; - tp->ty_size = pointer_size; - } - type(&(tp->ty_retval), (int *) 0, (p_symbol) 0) - ',' param_list(tp) - | - /* another procedure type */ - 'p' { tp->ty_class = T_PROCEDURE; - tp->ty_size = pointer_size; - tp->ty_retval = void_type; - } - param_list(tp) - | - /* set type */ - /* the first integer_const represents the size in bytes, - * the second one represents the low bound - */ - 'S' { tp->ty_class = T_SET; } - type(&(tp->ty_setbase), (int *) 0, (p_symbol) 0) ';' - [ - integer_const(&(tp->ty_size)) ';' - integer_const(&(tp->ty_setlow)) ';' - | - { set_bounds(tp); } - ] - | - /* file type of Pascal */ - 'L' { tp->ty_class = T_FILE; } - type(&(tp->ty_fileof), (int *) 0, (p_symbol) 0) - | - type_name(ptp, (p_symbol) 0) - { if (type_index && - (*ptp)->ty_class == 0 && - type_index[0] == last_index[0] && - type_index[1] == last_index[1]) { - **ptp = *void_type; - if (*ptp != tp) free_type(tp); - } - tp = *ptp; - } - ] - { if (*ptp && *ptp != tp) **ptp = *tp; - else *ptp = tp; - } -; + : + { + p->sy_type = new_type(); + p->sy_type->ty_class = T_PROCEDURE; + p->sy_type->ty_size = pointer_size; + if (CurrentScope != FileScope && saw_code) + { + /* if saw_code is not set, it is a nested + procedure + */ + close_scope(); + } + saw_code = 0; + open_scope(p, 1); + p->sy_name.nm_scope = CurrentScope; + CurrentScope->sc_start = currnam->on_valu; + add_scope_addr(CurrentScope); + CurrentScope->sc_proclevel = currnam->on_desc; + } + INTEGER ';' + type(&(p->sy_type->ty_retval), (int*)0, (p_symbol)0) + ; + +type(p_type* ptp; int* type_index; p_symbol sy;) + { + register p_type tp = *ptp ? *ptp : new_type(); + p_type t1 = 0, t2 = 0; + long ic1, ic2; + int A_used = 0; + int tclass; + int tp_index[2]; + char* str; + } + : [ + /* type cross reference */ + /* these are used in C for references to a struct, union or + * enum that has not been declared (yet) + */ + 'x' + [ + 's' + /* struct */ + { tclass = T_STRUCT; } + | 'u' + /* union */ + { tclass = T_UNION; } + | 'e' + /* enum */ + { tclass = T_ENUM; } + ] + { AllowName = 1; } + name(&str) + { + sy = Lookfromscope(str2idf(str, 0), TAG, CurrentScope); + if (sy && (sy->sy_type->ty_class == tclass || sy->sy_type->ty_class == T_CROSS)) + { + if (tp != *ptp) + free_type(tp); + tp = sy->sy_type; + } + else + { + tp->ty_class = T_CROSS; + tp->ty_size = tclass; + sy = NewSymbol(str, CurrentScope, TAG, (struct outname*)0); + sy->sy_type = tp; + } + } + | + /* subrange */ + /* the integer_const's represent the lower and the upper bound. + * A subrange type defined as subrange of itself is an integer type. + * If the second integer_const == 0, but the first is not, we + * have a floating point type with size equal to the first + * integer_const. + * Upperbound -1 means unsigned int or unsigned long. + */ + 'r' + type_index(tp_index) + ';' + [ + 'A' + integer_const(&ic1) + { A_used = 1; } + | integer_const(&ic1) + ] + ';' + [ + 'A' + integer_const(&ic2) + { A_used |= 2; } + | integer_const(&ic2) + | 'Z' + integer_const(&ic2) + { A_used |= 0200; } + ] + { + if (tp != *ptp) + free_type(tp); + tp = subrange_type(A_used, tp_index, ic1, ic2, type_index); + } + | + /* array; first type is bound type, next type + * is element type + */ + 'a' + type(&t1, (int*)0, (p_symbol)0) + ';' + type(&t2, (int*)0, (p_symbol)0) + { + if (tp != *ptp) + free_type(tp); + tp = array_type(t1, t2); + } + | + /* structure type */ + 's' + { tp->ty_class = T_STRUCT; } + structure_type(tp, sy) + | + /* union type */ + 'u' + { tp->ty_class = T_UNION; } + structure_type(tp, sy) + | + /* enumeration type */ + 'e' + { tp->ty_class = T_ENUM; } + enum_type(tp) + | + /* pointer type */ + '*' + { + tp->ty_class = T_POINTER; + tp->ty_size = pointer_size; + } + type(&(tp->ty_ptrto), (int*)0, (p_symbol)0) + | + /* function type */ + 'f' + { + tp->ty_class = T_PROCEDURE; + tp->ty_size = pointer_size; + } + type(&(tp->ty_retval), (int*)0, (p_symbol)0) + /* + [ %prefer + ',' param_list(tp) + | + ] + */ + | + /* procedure type */ + 'Q' + { + tp->ty_class = T_PROCEDURE; + tp->ty_size = pointer_size; + } + type(&(tp->ty_retval), (int*)0, (p_symbol)0) + ',' + param_list(tp) + | + /* another procedure type */ + 'p' + { + tp->ty_class = T_PROCEDURE; + tp->ty_size = pointer_size; + tp->ty_retval = void_type; + } + param_list(tp) + | + /* set type */ + /* the first integer_const represents the size in bytes, + * the second one represents the low bound + */ + 'S' + { tp->ty_class = T_SET; } + type(&(tp->ty_setbase), (int*)0, (p_symbol)0) + ';' + [ + integer_const(&(tp->ty_size)) + ';' + integer_const(&(tp->ty_setlow)) + ';' + | + { set_bounds(tp); } + ] + | + /* file type of Pascal */ + 'L' + { tp->ty_class = T_FILE; } + type(&(tp->ty_fileof), (int*)0, (p_symbol)0) + | type_name(ptp, (p_symbol)0) + { + if (type_index && (*ptp)->ty_class == 0 && type_index[0] == last_index[0] + && type_index[1] == last_index[1]) + { + **ptp = *void_type; + if (*ptp != tp) + free_type(tp); + } + tp = *ptp; + } + ] + { if (*ptp && *ptp != tp) **ptp = *tp; else *ptp = tp; } + ; structure_type(p_type tp; p_symbol sy;) - { register struct fields *fldp; - char *str; - } -: - integer_const(&(tp->ty_size)) /* size in bytes */ - { open_scope(sy, 0); - if (sy) sy->sy_name.nm_scope = CurrentScope; - } - [ - name(&str) { fldp = get_field_space(tp, str); } - type(&(fldp->fld_type), (int *) 0, (p_symbol) 0) ',' - integer_const(&(fldp->fld_pos)) ',' /* offset in bits */ - integer_const(&(fldp->fld_bitsize)) ';' /* size in bits */ - ]* - ';' { end_field(tp); - close_scope(); - } -; + { + register struct fields* fldp; + char* str; + } + : integer_const(&(tp->ty_size)) + /* size in bytes */ + { + open_scope(sy, 0); + if (sy) + sy->sy_name.nm_scope = CurrentScope; + } + [ + name(&str) + { fldp = get_field_space(tp, str); } + type(&(fldp->fld_type), (int*)0, (p_symbol)0) + ',' + integer_const(&(fldp->fld_pos)) + ',' + /* offset in bits */ + integer_const(&(fldp->fld_bitsize)) + ';' + /* size in bits */ + ]* + ';' + { + end_field(tp); + close_scope(); + } + ; enum_type(p_type tp;) - { register struct literal *litp; - long maxval = 0; - p_symbol s; - } -: - [ { litp = get_literal_space(tp); } - name(&(litp->lit_name)) - integer_const(&(litp->lit_val)) ',' - { if (maxval < litp->lit_val) maxval = litp->lit_val; - AllowName = 1; - s = NewSymbol(litp->lit_name, CurrentScope, CONST, (struct outname *) 0); - s->sy_const.co_ival = litp->lit_val; - s->sy_type = tp; - } - ]* - ';' { end_literal(tp, maxval); } -; + { + register struct literal* litp; + long maxval = 0; + p_symbol s; + } + : [ + { litp = get_literal_space(tp); } + name(&(litp->lit_name)) + integer_const(&(litp->lit_val)) + ',' + { + if (maxval < litp->lit_val) + maxval = litp->lit_val; + AllowName = 1; + s = NewSymbol(litp->lit_name, CurrentScope, CONST, (struct outname*)0); + s->sy_const.co_ival = litp->lit_val; + s->sy_type = tp; + } + ]* + ';' + { end_literal(tp, maxval); } + ; param_list(p_type t;) - { register struct param *p; - long iconst; - } -: - integer_const(&iconst) ';' /* number of parameters */ - { t->ty_nparams = iconst; - t->ty_params = p = (struct param *) - malloc((unsigned)(t->ty_nparams * sizeof(struct param))); - } - [ - [ 'p' { p->par_kind = 'p'; } - | 'v' { p->par_kind = 'v'; } - | 'i' { p->par_kind = 'i'; } - ] - { p->par_type = 0; } - type(&(p->par_type), (int *) 0, (p_symbol) 0) ';' - { p->par_off = t->ty_nbparams; - t->ty_nbparams += - param_size(p->par_type, p->par_kind); - p++; - } - ]* -; - -{ -static char *db_string; -static char *DbOldPtr; + { + register struct param* p; + long iconst; + } + : integer_const(&iconst) + ';' + /* number of parameters */ + { + t->ty_nparams = iconst; + t->ty_params = p + = (struct param*)malloc((unsigned)(t->ty_nparams * sizeof(struct param))); + } + [ + [ + 'p' + { p->par_kind = 'p'; } + | 'v' + { p->par_kind = 'v'; } + | 'i' + { p->par_kind = 'i'; } + ] + { p->par_type = 0; } + type(&(p->par_type), (int*)0, (p_symbol)0) + ';' + { + p->par_off = t->ty_nbparams; + t->ty_nbparams += param_size(p->par_type, p->par_kind); + p++; + } + ]* + ; -static struct outname * -DbString(n) - struct outname *n; { - currnam = n; - DbPtr = n->on_mptr; - db_string = DbPtr; - AllowName = 1; - DbParser(); - return currnam; -} - -/*ARGSUSED*/ -DBSmessage(n) -{ - fatal("error in symbol table string \"%s\", DbPtr = \"%s\", DbOldPtr = \"%s\"", - db_string, - DbPtr, - DbOldPtr); - -} - -DBSonerror(tk, p) - int *p; -{ - DbPtr = DbOldPtr; -/* ??? if (DBSsymb < 0) { - while (*p && *p != ';') p++; - if (*p) DbPtr = ";"; - return; - } -*/ - if (! tk) { - while (*p && *p != NAME) p++; - if (*p) { - AllowName = 1; - } - } - else if (tk == NAME) AllowName = 1; -} - -DBSlex() -{ - char *cp = DbPtr; - int allow_name = AllowName; - int c; - - AllowName = 0; - DbOldPtr = cp; - c = *cp; - if (c == '\\' && *(cp+1) == '\0') { - currnam++; - cp = currnam->on_mptr; - DbOldPtr = cp; - c = *cp; - } - if (! c) { - DbPtr = cp; - return -1; - } - if ((! allow_name && is_token(c)) || c == ';') { - DbPtr = cp+1; - return c; - } - if (is_dig(c)) { - int retval = INTEGER; - - while (++cp, is_dig(*cp)) /* nothing */; - c = *cp; - if (c == '.') { - retval = REAL; - while (++cp, is_dig(*cp)) /* nothing */; - c = *cp; - } - if (c == 'e' || c == 'E') { - char *oldcp = cp; - - cp++; - c = *cp; - if (c == '-' || c == '+') { - cp++; - c = *cp; - } - if (is_dig(c)) { - retval = REAL; - while (++cp, is_dig(*cp)) /* nothing */; - } - else cp = oldcp; - } - c = *cp; - *cp = 0; - if (retval == INTEGER) { - ival = str2long(DbOldPtr, 10); - } - else { - fval = atof(DbOldPtr); - } - *cp = c; - DbPtr = cp; - return retval; - } - if (c == '\'') { - cp++; - strval = cp; - while ((c = *cp) && c != '\'') { - if (c == '\\') cp++; /* backslash escapes next character */ - if (!(c = *cp)) break; /* but not a null byte */ - cp++; - } - if (! c) DBSmessage(0); /* no return */ - *cp = 0; - DbPtr = cp + 1; - return STRING; - } - strval = cp; - while ((c = *cp) && c != ':' && c != ',') cp++; - DbPtr = *cp ? cp+1 : cp; - *cp = 0; - return NAME; -} - -static struct fields * -get_field_space(tp, s) - p_type tp; - char *s; -{ - struct fields *p; - p_symbol sy; - - if (! (tp->ty_nfields & 07)) { - tp->ty_fields = (struct fields *) - realloc((char *) tp->ty_fields, - (tp->ty_nfields+8)*sizeof(struct fields)); - } - p = &tp->ty_fields[tp->ty_nfields++]; - p->fld_name = s; - p->fld_type = 0; - sy = NewSymbol(s, CurrentScope, FIELD, currnam); - sy->sy_field = p; - return p; -} - -static -end_field(tp) - p_type tp; -{ - tp->ty_fields = (struct fields *) - realloc((char *) tp->ty_fields, - tp->ty_nfields * sizeof(struct fields)); -} - -static struct literal * -get_literal_space(tp) - p_type tp; -{ - if (! (tp->ty_nenums & 07)) { - tp->ty_literals = (struct literal *) - realloc((char *) tp->ty_literals, - (tp->ty_nenums+8)*sizeof(struct literal)); - } - return &tp->ty_literals[tp->ty_nenums++]; -} - -static char * -string_val(s) - char *s; -{ - char *ns = s, *os = s; - unsigned int i = 1; - - for (;;) { - if (!*os) break; - i++; - if (*os == '\\') { - os++; - *ns++ = *os++; - } - else *ns++ = *os++; - } - *ns = '\0'; - return Salloc(s, i); -} - -static char *AckStrings; /* ACK a.out string table */ -static struct outname *AckNames; /* ACK a.out symbol table entries */ -static unsigned int NAckNames; /* Number of ACK symbol table entries */ -static struct outname *EndAckNames; /* &AckNames[NAckNames] */ - -/* Read the symbol table from file 'f', which is supposed to be an - ACK a.out format file. Offer db strings to the db string parser. -*/ -int -DbRead(f) - char *f; -{ - struct outhead h; - struct outname *n; - struct outname *line_file = 0; - long OffsetStrings; - int lbrac_required = 0; - int needs_newscope = 0; - int lbrac_level = 0; - - /* Open file, read header, and check magic word */ - if (! rd_open(f)) { - fatal("%s: could not open", f); - } - rd_ohead(&h); - if (BADMAGIC(h) && h.oh_magic != O_CONVERTED) { - fatal("%s: not an object file", f); - } - - /* Allocate space for name table and read it */ - AckNames = (struct outname *) - malloc((unsigned)(sizeof(struct outname) * h.oh_nname)); - AckStrings = malloc((unsigned) h.oh_nchar); - rd_name(AckNames, h.oh_nname); - rd_string(AckStrings, h.oh_nchar); - - /* Adjust file offsets in name table to point at strings */ - OffsetStrings = OFF_CHAR(h); - NAckNames = h.oh_nname; - EndAckNames = &AckNames[h.oh_nname]; - for (n = EndAckNames; --n >= AckNames;) { - if (n->on_foff) { - if ((unsigned)(n->on_foff - OffsetStrings) >= h.oh_nchar) { - fatal("%s: error in object file", f); - } - n->on_mptr = AckStrings + (n->on_foff - OffsetStrings); - } - else n->on_mptr = 0; - } - - /* Offer strings to the db string parser if they contain a ':'. - Also offer filename-line number information to add_position_addr(). - Here, the order may be important. - */ - for (n = &AckNames[0]; n < EndAckNames; n++) { - int tp = n->on_type >> 8; - register p_symbol sym; - - if (tp & (S_STB >> 8)) { - switch(tp) { -#ifdef N_BINCL - case N_BINCL: - n->on_valu = (long) line_file; - line_file = n; - break; - case N_EINCL: - if (line_file) { - line_file = (struct outname *) line_file->on_valu; - } - break; -#endif - case N_SO: - if (n->on_mptr[strlen(n->on_mptr)-1] == '/') { - /* another N_SO follows ... */ - break; - } - clean_tp_tab(); - while (CurrentScope != PervasiveScope) { - close_scope(); - } - saw_code = 0; - sym = add_file(n->on_mptr); - - if (! listfile) newfile(sym->sy_idf); - open_scope(sym, 0); - sym->sy_file->f_scope = CurrentScope; - FileScope = CurrentScope; - CurrentScope->sc_start = n->on_valu; - /* fall through */ - case N_SOL: - if (line_file) n->on_valu = line_file->on_valu; - line_file = n; - break; - case N_MAIN: - if (! FileScope) fatal("No file scope"); - newfile(FileScope->sc_definedby->sy_idf); - break; - case N_SLINE: - assert(line_file); - if (CurrentScope->sc_start) { - register p_scope sc = - get_scope_from_addr(n->on_valu); - - if (sc) CurrentScope = sc; - } - else if (! saw_code) { - CurrentScope->sc_start = n->on_valu; - add_scope_addr(CurrentScope); - } - if (!CurrentScope->sc_bp_opp - || CurrentScope->sc_bp_lineno > n->on_desc) { - CurrentScope->sc_bp_opp = n->on_valu; - CurrentScope->sc_bp_lineno = n->on_desc; - } - saw_code = 1; - add_position_addr(line_file->on_mptr, n); - break; - case N_LBRAC: /* block, desc = nesting level */ - if (lbrac_level && ! lbrac_required) { - open_scope((p_symbol) 0, 0); - saw_code = 0; - } - else { - /* Sun-4 ld does not relocate LBRAC - values, so we cannot use it - - register p_scope sc = - get_scope_from_addr(n->on_valu); - - if (!sc || sc->sc_bp_opp) { - } - else CurrentScope = sc; - */ - } - lbrac_level++; - needs_newscope = 1; - break; -#ifdef N_SCOPE - case N_SCOPE: - if (n->on_mptr && strchr(n->on_mptr, ':')) { - n = DbString(n); - } - break; -#endif - case N_RBRAC: /* end block, desc = nesting level */ - if (CurrentScope != FileScope) close_scope(); - needs_newscope = 1; - if (--lbrac_level == 0) needs_newscope = 0; - saw_code = 0; - break; - case N_FUN: /* function, value = address */ - case N_GSYM: /* global variable */ - case N_STSYM: /* data, static, value = address */ - case N_LCSYM: /* bss, static, value = address */ - case N_RSYM: /* register var, value = reg number */ - case N_SSYM: /* struct/union el, value = offset */ - case N_PSYM: /* parameter, value = offset from AP */ - case N_LSYM: /* local sym, value = offset from FP */ - if (needs_newscope) { - open_scope((p_symbol) 0, 0); - saw_code = 0; - needs_newscope = 0; - lbrac_required = 1; - } - if (n->on_mptr && strchr(n->on_mptr, ':')) { - n = DbString(n); - } - break; - default: -/* - if (n->on_mptr && (n->on_type&S_TYP) >= S_MIN) { - struct idf *id = str2idf(n->on_mptr, 0); - - sym = new_symbol(); - sym->sy_next = id->id_def; - id->id_def = sym; - sym->sy_class = SYMENTRY; - sym->sy_onam = *n; - sym->sy_idf = id; - } -*/ - break; - } - } - } - close_scope(); - add_position_addr((char *) 0, (struct outname *) 0); - clean_tp_tab(); - rd_close(); - return (h.oh_magic == O_CONVERTED); -} + static char* db_string; + static char* DbOldPtr; + + static struct outname* DbString(n) struct outname* n; + { + currnam = n; + DbPtr = n->on_mptr; + db_string = DbPtr; + AllowName = 1; + DbParser(); + return currnam; + } + + /*ARGSUSED*/ + DBSmessage(n) + { + fatal("error in symbol table string \"%s\", DbPtr = \"%s\", DbOldPtr = \"%s\"", db_string, + DbPtr, DbOldPtr); + } + + DBSonerror(tk, p) int* p; + { + DbPtr = DbOldPtr; + /* ??? if (DBSsymb < 0) { + while (*p && *p != ';') p++; + if (*p) DbPtr = ";"; + return; + } + */ + if (!tk) + { + while (*p && *p != NAME) + p++; + if (*p) + { + AllowName = 1; + } + } + else if (tk == NAME) + AllowName = 1; + } + + DBSlex() + { + char* cp = DbPtr; + int allow_name = AllowName; + int c; + + AllowName = 0; + DbOldPtr = cp; + c = *cp; + if (c == '\\' && *(cp + 1) == '\0') + { + currnam++; + cp = currnam->on_mptr; + DbOldPtr = cp; + c = *cp; + } + if (!c) + { + DbPtr = cp; + return -1; + } + if ((!allow_name && is_token(c)) || c == ';') + { + DbPtr = cp + 1; + return c; + } + if (is_dig(c)) + { + int retval = INTEGER; + + while (++cp, is_dig(*cp)) /* nothing */ + ; + c = *cp; + if (c == '.') + { + retval = REAL; + while (++cp, is_dig(*cp)) /* nothing */ + ; + c = *cp; + } + if (c == 'e' || c == 'E') + { + char* oldcp = cp; + + cp++; + c = *cp; + if (c == '-' || c == '+') + { + cp++; + c = *cp; + } + if (is_dig(c)) + { + retval = REAL; + while (++cp, is_dig(*cp)) /* nothing */ + ; + } + else + cp = oldcp; + } + c = *cp; + *cp = 0; + if (retval == INTEGER) + { + ival = str2long(DbOldPtr, 10); + } + else + { + fval = atof(DbOldPtr); + } + *cp = c; + DbPtr = cp; + return retval; + } + if (c == '\'') + { + cp++; + strval = cp; + while ((c = *cp) && c != '\'') + { + if (c == '\\') + cp++; /* backslash escapes next character */ + if (!(c = *cp)) + break; /* but not a null byte */ + cp++; + } + if (!c) + DBSmessage(0); /* no return */ + *cp = 0; + DbPtr = cp + 1; + return STRING; + } + strval = cp; + while ((c = *cp) && c != ':' && c != ',') + cp++; + DbPtr = *cp ? cp + 1 : cp; + *cp = 0; + return NAME; + } + + static struct fields* get_field_space(tp, s) p_type tp; + char* s; + { + struct fields* p; + p_symbol sy; + + if (!(tp->ty_nfields & 07)) + { + tp->ty_fields = (struct fields*)realloc((char*)tp->ty_fields, + (tp->ty_nfields + 8) * sizeof(struct fields)); + } + p = &tp->ty_fields[tp->ty_nfields++]; + p->fld_name = s; + p->fld_type = 0; + sy = NewSymbol(s, CurrentScope, FIELD, currnam); + sy->sy_field = p; + return p; + } + + static end_field(tp) p_type tp; + { + tp->ty_fields + = (struct fields*)realloc((char*)tp->ty_fields, tp->ty_nfields * sizeof(struct fields)); + } + + static struct literal* get_literal_space(tp) p_type tp; + { + if (!(tp->ty_nenums & 07)) + { + tp->ty_literals = (struct literal*)realloc( + (char*)tp->ty_literals, (tp->ty_nenums + 8) * sizeof(struct literal)); + } + return &tp->ty_literals[tp->ty_nenums++]; + } + + static char* string_val(s) char* s; + { + char *ns = s, *os = s; + unsigned int i = 1; + + for (;;) + { + if (!*os) + break; + i++; + if (*os == '\\') + { + os++; + *ns++ = *os++; + } + else + *ns++ = *os++; + } + *ns = '\0'; + return Salloc(s, i); + } + + static char* AckStrings; /* ACK a.out string table */ + static struct outname* AckNames; /* ACK a.out symbol table entries */ + static unsigned int NAckNames; /* Number of ACK symbol table entries */ + static struct outname* EndAckNames; /* &AckNames[NAckNames] */ + + /* Read the symbol table from file 'f', which is supposed to be an + ACK a.out format file. Offer db strings to the db string parser. + */ + int DbRead(f) char* f; + { + struct outhead h; + struct outname* n; + struct outname* line_file = 0; + long OffsetStrings; + int lbrac_required = 0; + int needs_newscope = 0; + int lbrac_level = 0; + + /* Open file, read header, and check magic word */ + if (!rd_open(f)) + { + fatal("%s: could not open", f); + } + rd_ohead(&h); + if (BADMAGIC(h) && h.oh_magic != O_CONVERTED) + { + fatal("%s: not an object file", f); + } + + /* Allocate space for name table and read it */ + AckNames = (struct outname*)malloc((unsigned)(sizeof(struct outname) * h.oh_nname)); + AckStrings = malloc((unsigned)h.oh_nchar); + rd_name(AckNames, h.oh_nname); + rd_string(AckStrings, h.oh_nchar); + + /* Adjust file offsets in name table to point at strings */ + OffsetStrings = OFF_CHAR(h); + NAckNames = h.oh_nname; + EndAckNames = &AckNames[h.oh_nname]; + for (n = EndAckNames; --n >= AckNames;) + { + if (n->on_foff) + { + if ((unsigned)(n->on_foff - OffsetStrings) >= h.oh_nchar) + { + fatal("%s: error in object file", f); + } + n->on_mptr = AckStrings + (n->on_foff - OffsetStrings); + } + else + n->on_mptr = 0; + } + + /* Offer strings to the db string parser if they contain a ':'. + Also offer filename-line number information to add_position_addr(). + Here, the order may be important. + */ + for (n = &AckNames[0]; n < EndAckNames; n++) + { + int tp = n->on_type >> 8; + register p_symbol sym; + + if (tp & (S_STB >> 8)) + { + switch (tp) + { + #ifdef N_BINCL + case N_BINCL: + n->on_valu = (long)line_file; + line_file = n; + break; + case N_EINCL: + if (line_file) + { + line_file = (struct outname*)line_file->on_valu; + } + break; + #endif + case N_SO: + if (n->on_mptr[strlen(n->on_mptr) - 1] == '/') + { + /* another N_SO follows ... */ + break; + } + clean_tp_tab(); + while (CurrentScope != PervasiveScope) + { + close_scope(); + } + saw_code = 0; + sym = add_file(n->on_mptr); + + if (!listfile) + newfile(sym->sy_idf); + open_scope(sym, 0); + sym->sy_file->f_scope = CurrentScope; + FileScope = CurrentScope; + CurrentScope->sc_start = n->on_valu; + /* fall through */ + case N_SOL: + if (line_file) + n->on_valu = line_file->on_valu; + line_file = n; + break; + case N_MAIN: + if (!FileScope) + fatal("No file scope"); + newfile(FileScope->sc_definedby->sy_idf); + break; + case N_SLINE: + assert(line_file); + if (CurrentScope->sc_start) + { + register p_scope sc = get_scope_from_addr(n->on_valu); + + if (sc) + CurrentScope = sc; + } + else if (!saw_code) + { + CurrentScope->sc_start = n->on_valu; + add_scope_addr(CurrentScope); + } + if (!CurrentScope->sc_bp_opp || CurrentScope->sc_bp_lineno > n->on_desc) + { + CurrentScope->sc_bp_opp = n->on_valu; + CurrentScope->sc_bp_lineno = n->on_desc; + } + saw_code = 1; + add_position_addr(line_file->on_mptr, n); + break; + case N_LBRAC: /* block, desc = nesting level */ + if (lbrac_level && !lbrac_required) + { + open_scope((p_symbol)0, 0); + saw_code = 0; + } + else + { + /* Sun-4 ld does not relocate LBRAC + values, so we cannot use it + + register p_scope sc = + get_scope_from_addr(n->on_valu); + + if (!sc || sc->sc_bp_opp) { + } + else CurrentScope = sc; + */ + } + lbrac_level++; + needs_newscope = 1; + break; + #ifdef N_SCOPE + case N_SCOPE: + if (n->on_mptr && strchr(n->on_mptr, ':')) + { + n = DbString(n); + } + break; + #endif + case N_RBRAC: /* end block, desc = nesting level */ + if (CurrentScope != FileScope) + close_scope(); + needs_newscope = 1; + if (--lbrac_level == 0) + needs_newscope = 0; + saw_code = 0; + break; + case N_FUN: /* function, value = address */ + case N_GSYM: /* global variable */ + case N_STSYM: /* data, static, value = address */ + case N_LCSYM: /* bss, static, value = address */ + case N_RSYM: /* register var, value = reg number */ + case N_SSYM: /* struct/union el, value = offset */ + case N_PSYM: /* parameter, value = offset from AP */ + case N_LSYM: /* local sym, value = offset from FP */ + if (needs_newscope) + { + open_scope((p_symbol)0, 0); + saw_code = 0; + needs_newscope = 0; + lbrac_required = 1; + } + if (n->on_mptr && strchr(n->on_mptr, ':')) + { + n = DbString(n); + } + break; + default: + /* + if (n->on_mptr && (n->on_type&S_TYP) >= S_MIN) { + struct idf *id = str2idf(n->on_mptr, 0); + + sym = new_symbol(); + sym->sy_next = id->id_def; + id->id_def = sym; + sym->sy_class = SYMENTRY; + sym->sy_onam = *n; + sym->sy_idf = id; + } + */ + break; + } + } + } + close_scope(); + add_position_addr((char*)0, (struct outname*)0); + clean_tp_tab(); + rd_close(); + return (h.oh_magic == O_CONVERTED); + } } diff --git a/util/topgen/topgen.g b/util/topgen/topgen.g index 25294c6ca..da9585c9c 100644 --- a/util/topgen/topgen.g +++ b/util/topgen/topgen.g @@ -3,347 +3,410 @@ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ + +/* + * Reformat from the repository root (requires clang-format): + * + * python3 util/LLgen/formatter.py -i util/topgen/topgen.g + */ /* t o p g e n . g * * Grammar of optimizer description, and some code generation */ -%token LETTER, DIGIT, OTHER, SPACE; -%token LINE_TERMINATOR, OPERAND_SEPARATOR, INSTRUCTION_SEPARATOR, - PATTERN_SEPARATOR, OPEN_BRACKET, CLOSE_BRACKET; +%token LETTER, DIGIT, OTHER, SPACE; +%token LINE_TERMINATOR, OPERAND_SEPARATOR, INSTRUCTION_SEPARATOR, PATTERN_SEPARATOR, OPEN_BRACKET, CLOSE_BRACKET; %lexical LLlex; -%start LLparse, optim_description; +%start LLparse, optim_description; { -#include -#include -#include -#include "token.h" -#include "symtab.h" -#include "misc.h" -#include "hash.h" -#include "pattern.h" - -char idbuf[BUFSIZ], buf[BUFSIZ]; -int countid; /* # of variables */ -int countpat; /* # of patterns */ -static int patlen; /* Maximum number of instructions in pattern */ -static int maxoperand; /* Maximum number of operands of instruction */ -extern FILE *input; /* file descriptor of inputfile */ - - - -extern int onlyspace(char* s); -extern void error(char *s, char* s1); + #include + #include + #include + #include "token.h" + #include "symtab.h" + #include "misc.h" + #include "hash.h" + #include "pattern.h" + char idbuf[BUFSIZ], buf[BUFSIZ]; + int countid; /* # of variables */ + int countpat; /* # of patterns */ + static int patlen; /* Maximum number of instructions in pattern */ + static int maxoperand; /* Maximum number of operands of instruction */ + extern FILE* input; /* file descriptor of inputfile */ + extern int onlyspace(char* s); + extern void error(char* s, char* s1); } optim_description - { struct symtab *p; } : - SPACE* parameters - { p = findident("MAXOP",LOOKING,&deftable); - if (p == 0) maxoperand = 2; /* default */ - else maxoperand = p->s_num; - } - separator SPACE* mode_definitions - separator SPACE* patterns - separator - { register int c; - fprintf(genc, linedir, lineno, inpfile); - while ((c = getc(input)) != EOF) { - putc(c,genc); - } - } -; + { + struct symtab* p; + } + : SPACE* + parameters + { + p = findident("MAXOP", LOOKING, &deftable); + if (p == 0) + maxoperand = 2; /* default */ + else + maxoperand = p->s_num; + } + separator + SPACE* + mode_definitions separator + SPACE* + patterns separator + { + register int c; + fprintf(genc, linedir, lineno, inpfile); + while ((c = getc(input)) != EOF) + { + putc(c, genc); + } + } + ; -parameters : - [ parameter_line | declaration_block ]* -; +parameters + : [ + parameter_line + | declaration_block + ]* + ; parameter_line - { struct symtab *p; - int lin; - } : - identifier - { p = findident(idbuf,ENTERING,&deftable);} - SPACE - { lin = lineno;} - value - { p->s_num = atoi(buf);} - /* This action in fact only needed for MAXOP */ - LINE_TERMINATOR - SPACE* - { fprintf(genh, linedir, lin, inpfile); - fprintf(genh,"#define %s %s\n",p->s_name,buf);} -; + { + struct symtab* p; + int lin; + } + : identifier + { p = findident(idbuf, ENTERING, &deftable); } + SPACE + { lin = lineno; } + value + { p->s_num = atoi(buf); } + /* This action in fact only needed for MAXOP */ + LINE_TERMINATOR + SPACE* + { + fprintf(genh, linedir, lin, inpfile); + fprintf(genh, "#define %s %s\n", p->s_name, buf); + } + ; value - { char *p1 = buf;} : - [ - [ OPEN_BRACKET - | CLOSE_BRACKET - | OPERAND_SEPARATOR - | PATTERN_SEPARATOR - | INSTRUCTION_SEPARATOR - | SPACE - | LETTER - | DIGIT - | OTHER - | '%' - ] - { *p1++ = dot.t_attrib;} - ]* - { *p1 = '\0';} -; + { + char* p1 = buf; + } + : [ + [ + OPEN_BRACKET + | CLOSE_BRACKET + | OPERAND_SEPARATOR + | PATTERN_SEPARATOR + | INSTRUCTION_SEPARATOR + | SPACE + | LETTER + | DIGIT + | OTHER + | '%' + ] + { *p1++ = dot.t_attrib; } + ]* + { *p1 = '\0'; } + ; -declaration_block : - OPEN_BRACKET - { fprintf(genh, linedir, lineno, inpfile);} - [ - [ LINE_TERMINATOR - | OPERAND_SEPARATOR - | PATTERN_SEPARATOR - | INSTRUCTION_SEPARATOR - | SPACE - | LETTER - | DIGIT - | OTHER - | '%' - ] - { putc(dot.t_attrib, genh);} - ]* - CLOSE_BRACKET - SPACE* - { putc('\n', genh);} -; +declaration_block + : OPEN_BRACKET + { fprintf(genh, linedir, lineno, inpfile); } + [ + [ + LINE_TERMINATOR + | OPERAND_SEPARATOR + | PATTERN_SEPARATOR + | INSTRUCTION_SEPARATOR + | SPACE + | LETTER + | DIGIT + | OTHER + | '%' + ] + { putc(dot.t_attrib, genh); } + ]* + CLOSE_BRACKET + SPACE* + { putc('\n', genh); } + ; mode_definitions - { int lin; } : - { fputs("int tok_chk(int varno) {\n\tint r;\n", genc); - fputs("\tchar *VAL;\n\n",genc); - fputs("\tVAL = var[varno].value;\n",genc); - fputs("\tswitch(varno) {\n",genc); - } - [ - token_list - constraint(&lin) - { fprintf(genc,linedir,lin,inpfile); - fprintf(genc,"\t\tr = (%s); break;\n",buf); - } - LINE_TERMINATOR - SPACE* - ]* - { fputs("\tdefault :\n\t\tfatal(\"invalid optimizer variable number\");\n",genc); - fputs("\t}\n\treturn r;\n}\n\n",genc); - } -; + { + int lin; + } + : + { + fputs("int tok_chk(int varno) {\n\tint r;\n", genc); + fputs("\tchar *VAL;\n\n", genc); + fputs("\tVAL = var[varno].value;\n", genc); + fputs("\tswitch(varno) {\n", genc); + } + [ + token_list + constraint(&lin) + { + fprintf(genc, linedir, lin, inpfile); + fprintf(genc, "\t\tr = (%s); break;\n", buf); + } + LINE_TERMINATOR + SPACE* + ]* + { + fputs("\tdefault :\n\t\tfatal(\"invalid optimizer variable number\");\n", genc); + fputs("\t}\n\treturn r;\n}\n\n", genc); + } + ; -token_list : - new_identifier - SPACE* - [ - OPERAND_SEPARATOR - SPACE* - new_identifier - SPACE* - ]* -; +token_list + : new_identifier + SPACE* + [ + OPERAND_SEPARATOR + SPACE* + new_identifier + SPACE* + ]* + ; new_identifier - { struct symtab *p;} : - identifier - { p = findident(idbuf,ENTERING,&idtable); - p->s_num = ++countid; - fprintf(genc,"\tcase %d:\n", countid); - } -; + { + struct symtab* p; + } + : identifier + { + p = findident(idbuf, ENTERING, &idtable); + p->s_num = ++countid; + fprintf(genc, "\tcase %d:\n", countid); + } + ; -constraint (int *lin;) - { char *p = buf; } : - OPEN_BRACKET - { *lin = lineno;} - [ - [ LINE_TERMINATOR - | OPERAND_SEPARATOR - | PATTERN_SEPARATOR - | INSTRUCTION_SEPARATOR - | LETTER - | DIGIT - | SPACE - | OTHER - | '%' - ] - { *p++ = dot.t_attrib;} - ]* - { *p = '\0'; - if (onlyspace(buf)) strcpy(buf,"TRUE"); - } - CLOSE_BRACKET - SPACE* -; +constraint(int* lin;) + { + char* p = buf; + } + : OPEN_BRACKET + { *lin = lineno; } + [ + [ + LINE_TERMINATOR + | OPERAND_SEPARATOR + | PATTERN_SEPARATOR + | INSTRUCTION_SEPARATOR + | LETTER + | DIGIT + | SPACE + | OTHER + | '%' + ] + { *p++ = dot.t_attrib; } + ]* + { + *p = '\0'; + if (onlyspace(buf)) + strcpy(buf, "TRUE"); + } + CLOSE_BRACKET + SPACE* + ; patterns - { int lin; - char *constr; - int np, nr; - } : -[ - { countpat++; - constr = (char *) 0; - fprintf(genc,"struct instr_descr pat%d[] = {\n", - countpat); - } - instruction_list(&np) - { if (np > patlen) patlen = np; - fputs("\n};\n\n",genc); - } - [ - constraint(&lin) - { /* Save the constraint, we need it later on */ - constr = malloc((unsigned)(strlen(buf)+1)); - strcpy(constr,buf); - } - ]? - PATTERN_SEPARATOR - { fprintf(genc,"struct instr_descr rep%d[] = {\n", - countpat); - } - replacement(&nr) - { fputs("\n};\n\n",genc);} - LINE_TERMINATOR - SPACE* - { addpattern(constr,lin,np,nr);} -]* - { printhashtable(); - printpatterns(); - fprintf(genh,"#define NRVARS %d\n",countid); - fprintf(genh,"#define NRPATTERNS %d\n",countpat); - fprintf(genh,"#define MIN_WINDOW_SIZE %d\n", - patlen+3); - fclose(genh); - } -; + { + int lin; + char* constr; + int np, nr; + } + : [ + { + countpat++; + constr = (char*)0; + fprintf(genc, "struct instr_descr pat%d[] = {\n", countpat); + } + instruction_list(&np) + { + if (np > patlen) + patlen = np; + fputs("\n};\n\n", genc); + } + [ + constraint(&lin) + { + /* Save the constraint, we need it later on */ + constr = malloc((unsigned)(strlen(buf) + 1)); + strcpy(constr, buf); + } + ]? + PATTERN_SEPARATOR + { fprintf(genc, "struct instr_descr rep%d[] = {\n", countpat); } + replacement(&nr) + { fputs("\n};\n\n", genc); } + LINE_TERMINATOR + SPACE* + { addpattern(constr, lin, np, nr); } + ]* + { + printhashtable(); + printpatterns(); + fprintf(genh, "#define NRVARS %d\n", countid); + fprintf(genh, "#define NRPATTERNS %d\n", countpat); + fprintf(genh, "#define MIN_WINDOW_SIZE %d\n", patlen + 3); + fclose(genh); + } + ; -instruction_list(int *n;) : - instruction(1) - { *n = 1;} - [ - INSTRUCTION_SEPARATOR - { fputs(",\n",genc);} - SPACE* - instruction(0) - { *n += 1;} - ]* -; +instruction_list(int* n;) + : instruction(1) + { *n = 1; } + [ + INSTRUCTION_SEPARATOR + { fputs(",\n", genc); } + SPACE* + instruction(0) + { *n += 1; } + ]* + ; instruction(int opt;) - { int count = 0;} : - opcode(opt) - { if (strcmp(buf,"ANY") != 0) { - fprintf(genc,"\t{\"%s\", {",buf); - } - else fputs("\t{(char *) 0, {",genc); - count = 0; - } - [ - operand(' ') - { count = 1;} - [ - OPERAND_SEPARATOR - { count++;} - SPACE* - operand(',') - ]* - { if (count > maxoperand) { - error("Too many operands",""); - } - } - ]? - { while (count++ < maxoperand) { - fprintf(genc,"%c{\"\",-1,\"\"}",count == 1 ? ' ' : ','); - } - putc('}',genc); - putc('}',genc); - } -; + { + int count = 0; + } + : opcode(opt) + { + if (strcmp(buf, "ANY") != 0) + { + fprintf(genc, "\t{\"%s\", {", buf); + } + else + fputs("\t{(char *) 0, {", genc); + count = 0; + } + [ + operand(' ') + { count = 1; } + [ + OPERAND_SEPARATOR + { count++; } + SPACE* + operand(',') + ]* + { if (count > maxoperand) { error("Too many operands", ""); } } + ]? + { + while (count++ < maxoperand) + { + fprintf(genc, "%c{\"\",-1,\"\"}", count == 1 ? ' ' : ','); + } + putc('}', genc); + putc('}', genc); + } + ; opcode(int opt;) - { char *p = buf;} : - [ - [ LETTER - | DIGIT - | OTHER - ] - { *p++ = dot.t_attrib;} - ]+ - SPACE+ - { *p = '\0'; - if (opt) addtohashtable(buf,countpat); - } -; + { + char* p = buf; + } + : [ + [ + LETTER + | DIGIT + | OTHER + ] + { *p++ = dot.t_attrib; } + ]+ + SPACE+ + { + *p = '\0'; + if (opt) + addtohashtable(buf, countpat); + } + ; operand(int c;) - { register struct symtab *p = 0;} : - { fprintf(genc, "%c{\"", c);} - [ - identifier - { if (!p) { - p = findident(idbuf,LOOKING,&idtable); - if (p) fprintf(genc,"\",%d,\"",p->s_num); - else fputs(idbuf,genc); - } - else fputs(idbuf,genc); - } - | DIGIT - { putc(dot.t_attrib,genc);} - | OTHER - { putc(dot.t_attrib,genc);} - ]+ - { if (p) fputs("\"}",genc); - else fputs("\",0,\"\"}",genc); - } - SPACE* -; - -replacement (int *n;) - {register int i;} : - SPACE* - { *n = 0;} - [ - instruction(0) - { *n = 1;} - [ - INSTRUCTION_SEPARATOR - { fputs(",\n", genc);} - SPACE* - instruction(0) - { *n += 1;} - ]* - | /* empty replacement, but there must be a - * structure initializer anyway - */ - { fputs("\t{\"\", {",genc); - for (i = 0; i < maxoperand; i++) { - fprintf(genc, "%c{\"\",-1,\"\"}",i?',':' '); - } - fputs("}}",genc); - } - ] -; + { + register struct symtab* p = 0; + } + : + { fprintf(genc, "%c{\"", c); } + [ + identifier + { + if (!p) + { + p = findident(idbuf, LOOKING, &idtable); + if (p) + fprintf(genc, "\",%d,\"", p->s_num); + else + fputs(idbuf, genc); + } + else + fputs(idbuf, genc); + } + | DIGIT + { putc(dot.t_attrib, genc); } + | OTHER + { putc(dot.t_attrib, genc); } + ]+ + { if (p) fputs("\"}", genc); else fputs("\",0,\"\"}", genc); } + SPACE* + ; +replacement(int* n;) + { + register int i; + } + : SPACE* + { *n = 0; } + [ + instruction(0) + { *n = 1; } + [ + INSTRUCTION_SEPARATOR + { fputs(",\n", genc); } + SPACE* + instruction(0) + { *n += 1; } + ]* + | + /* empty replacement, but there must be a + * structure initializer anyway + */ + { + fputs("\t{\"\", {", genc); + for (i = 0; i < maxoperand; i++) + { + fprintf(genc, "%c{\"\",-1,\"\"}", i ? ',' : ' '); + } + fputs("}}", genc); + } + ] + ; identifier - { char *p = idbuf; } : - LETTER - { *p++ = dot.t_attrib;} - [ %while (1) - LETTER { *p++ = dot.t_attrib;} - | DIGIT { *p++ = dot.t_attrib;} - ]* - { *p = '\0';} -; + { + char* p = idbuf; + } + : LETTER + { *p++ = dot.t_attrib; } + [ + %while (1) + LETTER + { *p++ = dot.t_attrib; } + | DIGIT + { *p++ = dot.t_attrib; } + ]* + { *p = '\0'; } + ; -separator : - '%' '%' SPACE* LINE_TERMINATOR -; +separator + : '%' '%' + SPACE* + LINE_TERMINATOR + ;