%{ #include <stdio.h> #include "pret.h" #include "pret.d" #define YYDEBUG 1 struct Node { int ntyp; /* OP ~ nval&left&right, NM ~ val */ int nval; struct Node *left, *right; }; extern struct Node *newnode(); struct PARS { int home; int dest; int bpnt; } ties[MAXDEPTH]; FILE *tb; /* temp file to store tables */ char procname[MAXNAME], refname[MAXNAME], qsetname[MAXNAME]; char str[256], filename[256]; char strings[MANY][MAXNAME]; extern char yytext[]; extern struct QTABLE qtable[NQUEUES]; extern int varwidths; int nnames = 0; int linenumber = 1; int linecode = 0; /* include source code references */ int nest = 0; /* nesting level of comments (lex) */ int anyerror = 0; int pid = NONE; /* process number */ int qid = NONE; /* queue number */ int rid = NONE; /* template number when defined */ int sid = NONE; /* qset number */ int nid = NONE; /* template number when refered */ int cid = NONE; /* index in call table */ int qind, qisz; /* queue's initial string size */ int parnum; /* counts actual parameters */ int assertion = -1; /* id of assertion table, if any */ int inertion = -1; /* id of error table, if any */ int vartype, inside; int n, m, from, xx, zz; int soo = 0; /* start of optionlist */ int curstate = 0; int curdepth = 0; int lastloop = -1; int verbose = 0; int nopurge = 0; checknames() { checkrefs(); checkglobvars(); checkqs(); } putglobals(fd) FILE *fd; { numrefs(fd); numprocs(fd); numsorts(fd); numinits(fd); numglobvars(fd); } puttables(fd1) FILE *fd1; { FILE *fd2; char buffer[MANY]; int howmuch; if ((fd2 = fopen("pret.tmp", "r")) == NULL) whoops("cannot find pret.tmp"); while ((howmuch = fread(buffer, sizeof(*buffer), MANY, fd2)) > 0) fwrite(buffer, sizeof(*buffer), howmuch, fd1); fclose(fd2); unlink("pret.tmp"); } makebin() { FILE *fd; if ((fd = fopen((anyerror)?"pret.err":"pret.out", "w")) == NULL) whoops("cannot create output file"); putglobals(fd); puttables(fd); numexps(fd); fclose(fd); if (anyerror) fprintf(stderr, "output written to `pret.err'\n"); } transfer(cl, tg) { int i = curstate; curstate = enterowname(NEW, "", DAR); setrans(i, cl, curstate, tg); } #include "pret.expr.c" %} %union{ int resu; struct Node *node; } %type <resu> PREIO INDEX QINDEX IMPORT ASGN ASGN %type <node> expr VARNAME %token <resu> NAME VALUE ARNAME QSNAME %start PROT_SPEC %token ASSERT ERROR %token PROCESS PBEGIN END IF FI DO OD %token timeout skip BREAK DEFAULT GOTO %token FLAG ARROW SEMICOLON COLON %token QUEUES QSET PVAR MESG %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ %left OR %left AND %left GT GE LT LE EQ NE %left '+' '-' %left '*' '/' '%' %left UNARYMINUS NOT INC DEC %right '^' %% PROT_SPEC : ONEMODULE | PROT_SPEC ONEMODULE ; ONEMODULE : PROC_SPEC | TASK_SPEC | ONEDECL | REQUIREMENT ; PROC_SPEC : PROCESS NAME QINDEX { strcpy(procname, strings[$2]); pid = newprocname(strings[$2], $3); } PBEGIN ANYDECLS { extern int extras; int ival; curstate = enterowname(NEW, "", DAR); newcalltable(); ival = 3*MANY+pid+extras; addvarname("_PROCID", (DCL|RFR), ival, NONE, 0); } SEQUENCE END { wrapup(NONE, pid, tb, nopurge, verbose); pid = NONE; strcpy(procname, "_"); } ; ANYDECLS : /* empty */ | DECLS ; DECLS : ONEDECL | DECLS ONEDECL ; ONEDECL : QDECLS | VARDECLS ; /* * QUEUES * ====== */ QDECLS : QUEUES QDECL SEPARATOR ; QDECL : ONEQ | QNAMELIST ; ONEQ : NAME QINDEX '=' { if ($2 == NONE || (qisz=$2) <= 0) yyerror("illegal queue size, %s", strings[$1]); qid = newqname(strings[$1], DCL, qisz, NONE); } PBEGIN MNAMELIST END ; /* * VARIABLES and QUEUESETS * ======================= */ VARDECLS : PVAR VNAMELIST SEPARATOR | QSET QSETDECL SEPARATOR ; QINDEX : /* empty */ { $$ = NONE; } | '[' VALUE ']' { $$ = $2; } ; QSETDECL : NAME PBEGIN NAME QINDEX COLON { xx = newqname(strings[$3], RFR, NONE, $4); sid = newqset(strings[$1], strings[$3], DCL, $4); } SNAMELIST END { closeqset(sid); } ; /* * PROCEDURES * ========== */ TASK_SPEC : NAME { rid = newreftask(strings[$1], DCL); curstate = enterowname(NEW, "", DAR); strcpy(refname, strings[$1]); newcalltable(); vartype = ISV; inside = 1; } '(' ANYPARAMS ')' { inside = 0; } ANYPARTYPES { reorder(); /* renumber formal parameters */ } PBEGIN ANYDECLS SEQUENCE END { wrapup(rid, NONE, tb, nopurge, verbose); strcpy(refname, "_"); rid = NONE; } ; ANYPARAMS : /* empty */ | PNAMELIST | error { yyerror("bad namelist", ""); } ; ANYPARTYPES : /* empty */ | PARTYPES | error { yyerror("bad parameterlist", ""); } ; PARTYPES : ONEPARTYPE SEMICOLON | PARTYPES ONEPARTYPE SEMICOLON ; ONEPARTYPE : PVAR { vartype = ISV; } PNAMELIST | QSET NAME PBEGIN NAME COLON { strcpy(qsetname, strings[$2]); sid = newqset(strings[$2], strings[$4], DCL, NONE); qid = addFpar(rid, strings[$2], sid, ISQ, inside); vartype = ISM; } PNAMELIST END { qid = NONE; closeqset(sid); } ; /* * REQUIREMENTS * ============ */ REQUIREMENT : ASSERT PBEGIN { rid = newreftask(" assert", DCL); assertion = rid; curstate = enterowname(NEW, "", DAR); strcpy(refname, " assert"); newcalltable(); } _SEQUENCE END { wrapup(rid, NONE, tb, nopurge, verbose); strcpy(refname, "_"); rid = NONE; lastloop = -1; } | ERROR PBEGIN { rid = newreftask(" error", DCL); inertion = rid; curstate = enterowname(NEW, "", DAR); strcpy(refname, " error"); newcalltable(); } _SEQUENCE END { wrapup(rid, NONE, tb, nopurge, verbose); strcpy(refname, "_"); rid = NONE; lastloop = -1; } ; _SEQUENCE : _STMNT | _SEQUENCE SEPARATOR _STMNT ; _STMNT : skip { lastloop = -1; } | _SELECT { lastloop = -1; } | _CYCLE | SEND { lastloop = -1; } | GUARD { lastloop = -1; } | STRUCTGOTO { lastloop = -1; } | error { yyerror("illegal assertion statement, %s", yytext); } ; _SELECT : IF { if (++curdepth == MAXDEPTH) whoops("nesting too deep"); ties[curdepth].home = curstate; ties[curdepth].dest = enterowname(NEW, "", DAR); ties[curdepth].bpnt = (curdepth > 1) ? ties[curdepth-1].bpnt : -1; } _OPTIONLIST FI { setrowname(ties[curdepth].dest); curstate = ties[curdepth--].dest; } ; _CYCLE : DO { if (curdepth++ == MAXDEPTH) whoops("nesting too deep"); labelrow(curstate); ties[curdepth].home = curstate; ties[curdepth].dest = curstate; ties[curdepth].bpnt = enterowname(NEW, "", DAR); } _OPTIONLIST OD { lastloop = ties[curdepth].home; setrowname(ties[curdepth].bpnt); curstate = ties[curdepth--].bpnt; } ; _OPTIONLIST : _ONEOPTION | _ONEOPTION _OPTIONLIST ; _ONEOPTION : FLAG _SEQUENCE { getrowname(str, ties[curdepth].dest); from = curstate; curstate = enterowname(OLD, str, DAR); setrans(from, 0, curstate, NONE); curstate = ties[curdepth].home; } ; /* * NAMELISTS * ========= */ ANAMELIST : ANAME | ANAMELIST ',' ANAME ; MNAMELIST : MNAME | MNAMELIST ',' MNAME ; PNAMELIST : PNAME | PNAMELIST ',' PNAME ; QNAMELIST : QNAME | QNAMELIST ',' QNAME ; SNAMELIST : SNAME | SNAMELIST ',' SNAME ; VNAMELIST : VNAME | VNAMELIST ',' VNAME ; /* * NAMES * ===== */ ANAME : QSNAME { addApars(strings[$1], nid, parnum++, NONE); } | expr { addAspecial(makeexpr($1), nid, parnum++); } ; MNAME : NAME { qtable[qid].status |= ADR; addmsg(strings[$1], qid, SND, INITM, NONE); if (--qisz < 0) yyerror("queue overfilled, %s", strings[$1]); } ; PNAME : NAME { if (vartype == ISM) addsetname(strings[$1], sid, 1); else addFpar(rid, strings[$1], qid, vartype, inside); } ; QNAME : NAME '[' VALUE ']' { if ((qisz = $3) <= 0) yyerror("illegal queue size, %s", strings[$1]); newqname(strings[$1], DCL, $3, NONE); } | NAME '[' VALUE ']' '[' VALUE ']' { if ((qisz = $6) <= 0) yyerror("illegal queue size, %s", strings[$1]); newqname(strings[$1], DCL, qisz, $3); } ; SNAME : NAME { addsetname(strings[$1], sid, 0); } ; VNAME : NAME QINDEX { addvarname(strings[$1], DCL, NONE, $2, 0); } | NAME QINDEX '=' expr { addvarname(strings[$1], DCL, makeexpr($4), $2, 0); } | NAME QINDEX COLON VALUE { addvarname(strings[$1], DCL, NONE, $2, $4); } ; /* * CODE * ==== */ SEQUENCE : STMNT { soo = 0; } | SEQUENCE SEPARATOR STMNT { soo = 0; } ; STMNT : skip { if (soo) /* only if used as a guard */ transfer(0, NONE); } | SELECT | CYCLE | SEND | GUARD | JUMP | LABEL STMNT | TEMPLATE | BUILTIN | CONDITIONAL | END { yyerror("expecting a statement", ""); whoops("exit"); } ; SELECT : IF { if (++curdepth == MAXDEPTH) whoops("nesting too deep"); ties[curdepth].home = curstate; ties[curdepth].dest = enterowname(NEW, "", DAR); ties[curdepth].bpnt = (curdepth>1) ? ties[curdepth-1].bpnt : -1; } OPTIONLIST FI { setrowname(ties[curdepth].dest); curstate = ties[curdepth--].dest; } ; CYCLE : DO { if (curdepth++ == MAXDEPTH) whoops("nesting too deep"); labelrow(curstate); ties[curdepth].home = curstate; ties[curdepth].dest = curstate; ties[curdepth].bpnt = enterowname(NEW, "", DAR); } OPTIONLIST OD { setrowname(ties[curdepth].bpnt); curstate = ties[curdepth--].bpnt; } ; OPTIONLIST : ONEOPTION | ONEOPTION OPTIONLIST ; ONEOPTION : FLAG { soo = 1; /* start of an option string */ } SEQUENCE { getrowname(str, ties[curdepth].dest); from = curstate; curstate = enterowname(OLD, str, DAR); setrans(from, 0, curstate, NONE); curstate = ties[curdepth].home; } ; INDEX : /* empty */ { $$ = NONE; } | '[' expr ']' { $$ = makeexpr($2); } ; PREIO : NAME INDEX { strcpy(str, strings[$1]); /* swivel away name */ $$ = $2; } ; SEND : PREIO NOT NAME EXPORT { xx = newqname(str, ADR, NONE, $1); zz = addmsg(strings[$3], xx, SND, NORM, $1); n = entercolname(zz, OUTP); transfer(n, m); } ; EXPORT : /* empty */ { m = NONE; } | '(' expr ')' { m = makeexpr($2); } ; GUARD : PREIO '?' timeout { int x; xx = newqname(str, RFR, NONE, $1); x = addmsg(" tau", xx, SAR, NORM, $1); /* ** the leading space is to avoid ** clashes with a user name `tau', ** e.g. in a formal parameter list */ n = entercolname(x, TMO); transfer(n, NONE); } | PREIO '?' NAME IMPORT { xx = newqname(str, RFR, NONE, $1); zz = addmsg(strings[$3], xx, RCV, NORM, $1); n = entercolname(zz, INP); transfer(n, $4); } | PREIO '?' DEFAULT IMPORT { xx = newqname(str, RFR, NONE, $1); zz = addmsg(" any", xx, SAR, NORM, $1); n = entercolname(zz, DFL); transfer(n, $4); } ; IMPORT : /* empty */ { $$ = NONE; } | '(' ARNAME INDEX ')' { $$ = addvarname(strings[$2], RFR, NONE, $3, 0); } | '(' NAME ')' { $$ = addvarname(strings[$2], RFR, NONE, NONE, 0); } | '(' VALUE ')' { yyerror("importing into constant", ""); } ; SEPARATOR : ARROW | SEMICOLON | error { yyerror("expecting a stmnt separator", ""); } ; JUMP : GOTO NAME { from = curstate; curstate = enterowname(LAB, strings[$2], ADR); setrans(from, 0, curstate, NONE); curstate = enterowname(NEW, "", DAR); } | STRUCTGOTO ; STRUCTGOTO : BREAK { int i; from = curstate; i = ties[curdepth].bpnt; if (curdepth == 0 || i == -1) whoops("illegal break statement"); getrowname(str, i); curstate = enterowname(OLD, str, DAR); setrans(from, 0, curstate, NONE); curstate = enterowname(NEW, "", DAR); } ; TEMPLATE : NAME { nid = newreftask(strings[$1], RFR); parnum = 0; qid = sid = NONE; cid = newcall(nid); } '(' ANYACTUALS ')' { int x; parrefs(parnum, nid); x = entercolname(cid, FCT); transfer(x, NONE); } ; ANYACTUALS : /* empty */ | ANAMELIST ; CONDITIONAL : '(' expr ')' { transfer(entercolname(makeexpr($2), CND), NONE); } ; VARNAME : ARNAME INDEX { m = addvarname(strings[$1], RFR, NONE, $2, 0); $$ = newnode(NM, m, NULL, NULL); } | NAME { m = addvarname(strings[$1], RFR, NONE, NONE, 0); $$ = newnode(NM, m, NULL, NULL); } ; BUILTIN : VARNAME ASGN expr { m = makeexpr(newnode(OP, $2, $1, $3)); transfer(0, m); } | VARNAME INC { m = makeexpr(newnode(OP, poinc, $1, NULL)); transfer(0, m); } | VARNAME DEC { m = makeexpr(newnode(OP, podec, $1, NULL)); transfer(0, m); } ; ASGN : '=' { $$ = setv; } | ADDEQ { $$ = addeq; } | SUBEQ { $$ = subeq; } | MULEQ { $$ = muleq; } | DIVEQ { $$ = diveq; } | MODEQ { $$ = modeq; } ; expr : expr '+' expr { $$ = newnode(OP, plus, $1, $3); } | expr '-' expr { $$ = newnode(OP, minus, $1, $3); } | expr '*' expr { $$ = newnode(OP, times, $1, $3); } | expr '/' expr { $$ = newnode(OP, div, $1, $3); } | expr '%' expr { $$ = newnode(OP, mod, $1, $3); } | expr '^' expr { $$ = newnode(OP, power, $1, $3); } | expr GT expr { $$ = newnode(OP, gt, $1, $3); } | expr GE expr { $$ = newnode(OP, ge, $1, $3); } | expr LT expr { $$ = newnode(OP, lt, $1, $3); } | expr LE expr { $$ = newnode(OP, le, $1, $3); } | expr EQ expr { $$ = newnode(OP, eq, $1, $3); } | expr NE expr { $$ = newnode(OP, ne, $1, $3); } | expr AND expr { $$ = newnode(OP, land, $1, $3); } | expr OR expr { $$ = newnode(OP, lor, $1, $3); } | '-' expr %prec UNARYMINUS { $$ = newnode(OP, uminus, $2, NULL); } | NOT expr { $$ = newnode(OP, lnot, $2, NULL); } | VALUE { $$ = newnode(NM, $1+3*MANY, NULL, NULL); } | ARNAME INDEX { m = addvarname(strings[$1], RFR, NONE, $2, 0); $$ = newnode(NM, m, NULL, NULL); } | NAME { m = addvarname(strings[$1], RFR, NONE, NONE, 0); $$ = newnode(NM, m, NULL, NULL); } | '(' expr ')' { $$ = $2; } ; LABEL : NAME COLON { from = curstate; curstate = enterowname(LAB, strings[$1], DCL); labelrow(curstate); setrans(from, 0, curstate, NONE); } ; %% extern FILE *yyin; main(argc, argv) char **argv; { int base = 1, i = 1; char c, buff[256]; char outfile[32]; if (argc > base && argv[1][0] == '-') { while ((c = argv[1][i++]) != '\0') switch (c) { case 's': varwidths = 1; break; case 'v': verbose = 1; break; case 'n': nopurge = 1; break; case 'l': linecode = 1; break; default : fprintf(stderr, "usage: pret [-vsnl] file\n"); fprintf(stderr, "\tv - verbose\n"); fprintf(stderr, "\ts - supertrace format\n"); fprintf(stderr, "\tn - no minimization\n"); fprintf(stderr, "\tl - enables linecode\n"); exit(1); } base++; } if (argc <= base) { fprintf(stderr, "usage: pret [-vnl] file\n"); exit(1); } if ((tb = fopen("pret.tmp", "w")) == NULL) whoops("cannot create pret.tmp\n"); strcpy(procname, "_"); strcpy(refname, "_"); unlink("pret.out"); unlink("pret.err"); if (argc > base) { strcpy(filename, argv[base]); mktemp(strcpy(outfile, "/tmp/trans.XXXXXX")); sprintf(buff, "/lib/cpp %s > %s", filename, outfile); if (system(buff)) { unlink(outfile); exit(1); } else if ((yyin = fopen(outfile, "r")) == NULL) { printf("cannot open %s\n", outfile); whoops("aborting"); } unlink(outfile); } parsed = (struct REVPOL *) Emalloc(EXPRMAX * sizeof(struct REVPOL)); prs = 0; yyparse(); prepsorts(); checknames(); fclose(tb); chatter(); makebin(); exit(0); } newstring(str) char *str; { register int i; for (i = 0; i < nnames; i++) if (strcmp(str, strings[i]) == 0) return i; if (++nnames >= MANY) yyerror("symbol table overflow, %s", str); strncpy(strings[i], str, MAXNAME-1); return i; }