3 #define code2(c1,c2) code(c1); code(c2)
4 #define code3(c1,c2,c3) code(c1); code(c2); code(c3)
7 Symbol *sym; /* symbol table pointer */
8 Inst *inst; /* machine instruction */
9 int narg; /* number of arguments */
10 Formal *formals; /* list of formal parameters */
12 %token <sym> NUMBER STRING PRINT VAR BLTIN UNDEF WHILE FOR IF ELSE
13 %token <sym> FUNCTION PROCEDURE RETURN FUNC PROC READ
14 %type <formals> formals
15 %type <inst> expr stmt asgn prlist stmtlist
16 %type <inst> cond while for if begin end
19 %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ
22 %left GT GE LT LE EQ NE
25 %left UNARYMINUS NOT INC DEC
31 | list asgn '\n' { code2(xpop, STOP); return 1; }
32 | list stmt '\n' { code(STOP); return 1; }
33 | list expr '\n' { code2(printtop, STOP); return 1; }
34 | list error '\n' { yyerrok; }
36 asgn: VAR '=' expr { code3(varpush,(Inst)$1,assign); $$=$3; }
37 | VAR ADDEQ expr { code3(varpush,(Inst)$1,addeq); $$=$3; }
38 | VAR SUBEQ expr { code3(varpush,(Inst)$1,subeq); $$=$3; }
39 | VAR MULEQ expr { code3(varpush,(Inst)$1,muleq); $$=$3; }
40 | VAR DIVEQ expr { code3(varpush,(Inst)$1,diveq); $$=$3; }
41 | VAR MODEQ expr { code3(varpush,(Inst)$1,modeq); $$=$3; }
43 stmt: expr { code(xpop); }
44 | RETURN { defnonly("return"); code(procret); }
46 { defnonly("return"); $$=$2; code(funcret); }
47 | PROCEDURE begin '(' arglist ')'
48 { $$ = $2; code3(call, (Inst)$1, (Inst)$4); }
49 | PRINT prlist { $$ = $2; }
50 | while '(' cond ')' stmt end {
51 ($1)[1] = (Inst)$5; /* body of loop */
52 ($1)[2] = (Inst)$6; } /* end, if cond fails */
53 | for '(' cond ';' cond ';' cond ')' stmt end {
54 ($1)[1] = (Inst)$5; /* condition */
55 ($1)[2] = (Inst)$7; /* post loop */
56 ($1)[3] = (Inst)$9; /* body of loop */
57 ($1)[4] = (Inst)$10; } /* end, if cond fails */
58 | if '(' cond ')' stmt end { /* else-less if */
59 ($1)[1] = (Inst)$5; /* thenpart */
60 ($1)[3] = (Inst)$6; } /* end, if cond fails */
61 | if '(' cond ')' stmt end ELSE stmt end { /* if with else */
62 ($1)[1] = (Inst)$5; /* thenpart */
63 ($1)[2] = (Inst)$8; /* elsepart */
64 ($1)[3] = (Inst)$9; } /* end, if cond fails */
65 | '{' stmtlist '}' { $$ = $2; }
67 cond: expr { code(STOP); }
69 while: WHILE { $$ = code3(whilecode,STOP,STOP); }
71 for: FOR { $$ = code(forcode); code3(STOP,STOP,STOP); code(STOP); }
73 if: IF { $$ = code(ifcode); code3(STOP,STOP,STOP); }
75 begin: /* nothing */ { $$ = progp; }
77 end: /* nothing */ { code(STOP); $$ = progp; }
79 stmtlist: /* nothing */ { $$ = progp; }
83 expr: NUMBER { $$ = code2(constpush, (Inst)$1); }
84 | VAR { $$ = code3(varpush, (Inst)$1, eval); }
86 | FUNCTION begin '(' arglist ')'
87 { $$ = $2; code3(call,(Inst)$1,(Inst)$4); }
88 | READ '(' VAR ')' { $$ = code2(varread, (Inst)$3); }
89 | BLTIN '(' expr ')' { $$=$3; code2(bltin, (Inst)$1->u.ptr); }
90 | '(' expr ')' { $$ = $2; }
91 | expr '+' expr { code(add); }
92 | expr '-' expr { code(sub); }
93 | expr '*' expr { code(mul); }
94 | expr '/' expr { code(div); }
95 | expr '%' expr { code(mod); }
96 | expr '^' expr { code (power); }
97 | '-' expr %prec UNARYMINUS { $$=$2; code(negate); }
98 | expr GT expr { code(gt); }
99 | expr GE expr { code(ge); }
100 | expr LT expr { code(lt); }
101 | expr LE expr { code(le); }
102 | expr EQ expr { code(eq); }
103 | expr NE expr { code(ne); }
104 | expr AND expr { code(and); }
105 | expr OR expr { code(or); }
106 | NOT expr { $$ = $2; code(not); }
107 | INC VAR { $$ = code2(preinc,(Inst)$2); }
108 | DEC VAR { $$ = code2(predec,(Inst)$2); }
109 | VAR INC { $$ = code2(postinc,(Inst)$1); }
110 | VAR DEC { $$ = code2(postdec,(Inst)$1); }
112 prlist: expr { code(prexpr); }
113 | STRING { $$ = code2(prstr, (Inst)$1); }
114 | prlist ',' expr { code(prexpr); }
115 | prlist ',' STRING { code2(prstr, (Inst)$3); }
117 defn: FUNC procname { $2->type=FUNCTION; indef=1; }
118 '(' formals ')' stmt { code(procret); define($2, $5); indef=0; }
119 | PROC procname { $2->type=PROCEDURE; indef=1; }
120 '(' formals ')' stmt { code(procret); define($2, $5); indef=0; }
123 | VAR { $$ = formallist($1, 0); }
124 | VAR ',' formals { $$ = formallist($1, $3); }
130 arglist: /* nothing */ { $$ = 0; }
132 | arglist ',' expr { $$ = $1 + 1; }
144 char *infile; /* input file name */
145 Biobuf *bin; /* input file descriptor */
147 char **gargv; /* global argument list */
150 int c = '\n'; /* global for use by warning() */
152 int backslash(int), follow(int, int, int);
153 void defnonly(char*), run(void);
154 void warning(char*, char*);
156 yylex(void) /* hoc6 */
158 while ((c=Bgetc(bin)) == ' ' || c == '\t')
169 if (c == '#') { /* comment */
170 while ((c=Bgetc(bin)) != '\n' && c >= 0)
176 if (c == '.' || isdigit(c)) { /* number */
180 yylval.sym = install("", NUMBER, d);
183 if (isalpha(c) || c == '_' || c >= 0x80) {
185 char sbuf[100], *p = sbuf;
187 if (p >= sbuf + sizeof(sbuf) - 1) {
189 execerror("name too long", sbuf);
192 } while ((c=Bgetc(bin)) >= 0 && (isalnum(c) || c == '_' || c >= 0x80));
195 if ((s=lookup(sbuf)) == 0)
196 s = install(sbuf, UNDEF, 0.0);
198 return s->type == UNDEF ? VAR : s->type;
200 if (c == '"') { /* quoted string */
202 for (p = sbuf; (c=Bgetc(bin)) != '"'; p++) {
203 if (c == '\n' || c == Beof)
204 execerror("missing quote", "");
205 if (p >= sbuf + sizeof(sbuf) - 1) {
207 execerror("string too long", sbuf);
212 yylval.sym = (Symbol *)emalloc(strlen(sbuf)+1);
213 strcpy((char*)yylval.sym, sbuf);
217 case '+': return follow('+', INC, follow('=', ADDEQ, '+'));
218 case '-': return follow('-', DEC, follow('=', SUBEQ, '-'));
219 case '*': return follow('=', MULEQ, '*');
220 case '/': return follow('=', DIVEQ, '/');
221 case '%': return follow('=', MODEQ, '%');
222 case '>': return follow('=', GE, GT);
223 case '<': return follow('=', LE, LT);
224 case '=': return follow('=', EQ, '=');
225 case '!': return follow('=', NE, NOT);
226 case '|': return follow('|', OR, '|');
227 case '&': return follow('&', AND, '&');
228 case '\n': lineno++; return '\n';
233 backslash(int c) /* get next char with \'s interpreted */
235 static char transtab[] = "b\bf\fn\nr\rt\t";
239 if (islower(c) && strchr(transtab, c))
240 return strchr(transtab, c)[1];
244 follow(int expect, int ifyes, int ifno) /* look ahead for >=, etc. */
255 yyerror(char* s) /* report compile-time error */
258 warning(s, (char *)0);
261 execerror(s, (char *)0);
265 execerror(char* s, char* t) /* recover from run-time error */
268 Bseek(bin, 0L, 2); /* flush rest of file */
274 fpecatch(void) /* catch floating point exceptions */
276 execerror("floating point exception", (char *) 0);
280 intcatch(void) /* catch interrupts */
282 execerror("interrupt", 0);
286 run(void) /* execute until EOF */
289 for (initcode(); yyparse(); initcode())
294 main(int argc, char* argv[]) /* hoc6 */
296 static int first = 1;
303 if (argc == 1) { /* fake an argument list */
304 static char *stdinonly[] = { "-" };
308 } else if (first) { /* for interrupts */
313 Binit(&binbuf, 0, OREAD);
329 if (bin && bin != &binbuf)
333 if (strcmp(infile, "-") == 0) {
338 if(strncmp(infile, "-e", 2) == 0) {
341 fprint(2, "%s: no argument for -e\n", progname);
348 sprint(buf, "/tmp/hocXXXXXXX");
349 infile = mktemp(buf);
350 fd = create(infile, ORDWR|ORCLOSE, 0600);
352 fprint(2, "%s: can't create temp. file: %r\n", progname);
355 fprint(fd, "%s\n", expr);
356 /* leave fd around; file will be removed on exit */
357 /* the following looks weird but is required for unix version */
360 Binit(bin, fd, OREAD);
362 bin=Bopen(infile, OREAD);
364 fprint(2, "%s: can't open %s\n", progname, infile);
372 warning(char* s, char* t) /* print warning message */
374 fprint(2, "%s: %s", progname, s);
378 fprint(2, " in %s", infile);
379 fprint(2, " near line %d\n", lineno);
380 while (c != '\n' && c != Beof)
381 if((c = Bgetc(bin)) == '\n') /* flush rest of input line */
386 defnonly(char *s) /* warn if illegal definition */
389 execerror(s, "used outside definition");