/* Program : formint File : formint.y Language: yacc Purpose : grammar definition Author : Oliver Mueller */ %{ #ifdef __TURBOC__ #include #else #include #endif #include #include "formint.h" #include "code.h" #define code2(c1,c2) code(c1);code(c2) #define code3(c1,c2,c3) code(c1);code(c2);code(c3) int indef; void yyerror(char *s); int run(); void warning(char *s; char *t); int moreinput(); int execerror(char *str, char *str1); int defnonly(char *s); int follow(int expect, int ifyes, int ifon); int init(); /* defined in init.c */ %} %union { Symbol *sym; /* symbol table pointer */ Inst *inst; /* machine instructions */ int narg; /* number of arguments */ } %start list %token NUMBER STRING PRINT VAR BLTIN UNDEF WHILE IF ELSE %token FUNCTION PROCEDURE RETURN FUNC PROC READ %token ARG %type stmt asgn expr stmtlist cond while if end prlist begin %type procname %type arglist %right '=' %left OR %left AND %left GT GE LT LE EQ NE %left '+' '-' %left '*' '/' %left UNARYMINUS NOT %right '^' %% list: /* epsilon */ | list '\n' | list defn '\n' | list asgn '\n' { code2((Inst)pop,STOP); return 1; } | list stmt '\n' { code(STOP); return 1; } | list expr '\n' { code2((Inst)print, STOP); return 1; } | list error '\n' { yyerror("at list\n"); } ; asgn: VAR '=' expr { code3((Inst)varpush, (Inst)$1, (Inst)assign); $$=$3; } | ARG '=' expr { defnonly("$"); code2((Inst)argassign, (Inst)$1); $$=$3; } ; stmt: expr { code((Inst)pop); } | RETURN { defnonly("return"); code((Inst)procret); } | RETURN expr { defnonly("return"); $$ = $2; code((Inst)funcret); } | PROCEDURE begin '(' arglist ')' { $$ = $2; code3((Inst)call, (Inst)$1, (Inst)$4); } | PRINT prlist { $$ = $2; } | while cond stmt end { ($1)[1] = (Inst)$3; /* body of loop */ ($1)[2] = (Inst)$4; /* end, if cond fails */ } | if cond stmt end { /* else-less if */ ($1)[1] = (Inst)$3; /* thenpart */ ($1)[3] = (Inst)$4; /* end, if cond fails */ } | if cond stmt end ELSE stmt end { /* if with else */ ($1)[1] = (Inst)$3; /* thenpart */ ($1)[2] = (Inst)$6; /* elsepart */ ($1)[3] = (Inst)$7; /* end, if cond fails */ } | '{' stmtlist '}' { $$ = $2; } ; cond: '(' expr ')' { code(STOP); $$ = $2; } ; while: WHILE { $$ = code3((Inst)whilecode, STOP, STOP); } ; if: IF { $$ = code((Inst)ifcode); code3(STOP, STOP, STOP); } ; begin: /* nothing */ { $$ = progp; } ; end: /* nothing */ { code(STOP); $$ = progp; } ; stmtlist: /* nothing */ { $$ = progp; } | stmtlist '\n' | stmtlist stmt ; expr: NUMBER { $$ = code2((Inst)constpush, (Inst)$1); } | VAR { $$ = code3((Inst)varpush, (Inst)$1, (Inst)eval); } | ARG { defnonly("$"); $$ = code2((Inst)arg, (Inst)$1); } | asgn | FUNCTION begin '(' arglist ')' { $$ = $2; code3((Inst)call,(Inst)$1,(Inst)$4); } | READ '(' VAR ')' { $$ = code2((Inst)varread, (Inst)$3); } | BLTIN '(' expr ')' { $$ = $3; code2((Inst)bltin, (Inst)$1->u.ptr); } | '(' expr ')' { $$ = $2; } | expr '+' expr { code((Inst)add); } | expr '-' expr { code((Inst)sub); } | expr '*' expr { code((Inst)mul); } | expr '/' expr { code((Inst)div); } | expr '^' expr { code((Inst)power);} | '-' expr %prec UNARYMINUS { $$=$2; code((Inst)negate); } | expr GT expr { code((Inst)gt); } | expr GE expr { code((Inst)ge); } | expr LT expr { code((Inst)lt); } | expr LE expr { code((Inst)le); } | expr EQ expr { code((Inst)eq); } | expr NE expr { code((Inst)ne); } | expr AND expr { code((Inst)and);} | expr OR expr { code((Inst)or); } | NOT expr { $$ = $2; code((Inst)not); } ; string: STRING { code2((Inst)varpush,(Inst)$1); } ; prlist: expr { code((Inst)prexpr); } | string { code((Inst)prstr); } | prlist ',' expr { code((Inst)prexpr); } | prlist ',' string { code((Inst)prstr); } ; defn: FUNC procname { $2->type=FUNCTION; indef=1; } '(' ')' stmt { code((Inst)procret); define($2); indef=0; } | PROC procname { $2->type=PROCEDURE; indef=1; } '(' ')' stmt { code((Inst)procret); define($2); indef=0; } procname: VAR | FUNCTION | PROCEDURE arglist: /* nothing */ { $$ = 0; } | expr { $$ = 1; } | arglist ',' expr { $$ = $1 + 1; } ; %% #include #include #include char *progname; int lineno = 1; char *infile; /* input file same */ extern FILE *yyin; /* input file pointer */ char **gargv; /* global argument list */ int gargc; int c; /* global for use by warning() */ jmp_buf begin; int follow(int expect, int ifyes, int ifno) { int c=getc(yyin); if (c == expect) return ifyes; ungetc(c, yyin); return ifno; } int defnonly(char *s) /* warn if illegal definition */ { if (!indef) execerror(s, "used outside definition"); } void yyerror(char *s) { puts(s); exit(1); } int execerror(char *str, char *str1) { warning (str, str1); fseek (yyin, 0L, 2); /* flush rest of file */ longjmp (begin, 0); } int main(int argc, char *argv[]) { int i; progname = argv[0] if (argc = 1) /* fake an argument list */ { static char *stdinonly[] = {"-"}; gargv = stdinonly; gargc = 1; } else { gargv = argv + 1; gargc = argc - 1; } init(); while (moreinput()) run(); return 0; } int moreinput() { if (gargc-- <= 0) return 0; if (yyin && yyin != stdin) fclose(yyin); infile = *gargv++; lineno = 1; if (strcmp(infile, "-") = 0) { yyin = stdin; infile = 0; } else if ((yyin=fopen(infile, "r")) == NULL) { fprintf (stderr, "can't open %s\n", infile); return moreinput(); } return 1; } int run() /* execute until EOF */ { setjmp(begin); for (initcode(); yyparse(); initcode()) execute(progbase); } void warning(char *u,char *t) { fprintf(stderr, "%s: %s", progname, s); if (t) fprintf(stderr, " %s", t); if (infile) fprintf (strerr, " is %s", infile); fprintf (stderr, " near line %d\n", lineno); }