Blob


1 %{
2 #include <u.h>
3 #include <libc.h>
4 #include <bio.h>
5 #include <ctype.h>
6 #include "hoc.h"
7 #define code2(c1,c2) code(c1); code(c2)
8 #define code3(c1,c2,c3) code(c1); code(c2); code(c3)
9 %}
10 %union {
11 Symbol *sym; /* symbol table pointer */
12 Inst *inst; /* machine instruction */
13 int narg; /* number of arguments */
14 Formal *formals; /* list of formal parameters */
15 }
16 %token <sym> NUMBER STRING PRINT VAR BLTIN UNDEF WHILE FOR IF ELSE
17 %token <sym> FUNCTION PROCEDURE RETURN FUNC PROC READ
18 %type <formals> formals
19 %type <inst> expr stmt asgn prlist stmtlist
20 %type <inst> cond while for if begin end
21 %type <sym> procname
22 %type <narg> arglist
23 %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ
24 %left OR
25 %left AND
26 %left GT GE LT LE EQ NE
27 %left '+' '-'
28 %left '*' '/' '%'
29 %left UNARYMINUS NOT INC DEC
30 %right '^'
31 %%
32 list: /* nothing */
33 | list '\n'
34 | list defn '\n'
35 | list asgn '\n' { code2(xpop, STOP); return 1; }
36 | list stmt '\n' { code(STOP); return 1; }
37 | list expr '\n' { code2(printtop, STOP); return 1; }
38 | list error '\n' { yyerrok; }
39 ;
40 asgn: VAR '=' expr { code3(varpush,(Inst)$1,assign); $$=$3; }
41 | VAR ADDEQ expr { code3(varpush,(Inst)$1,addeq); $$=$3; }
42 | VAR SUBEQ expr { code3(varpush,(Inst)$1,subeq); $$=$3; }
43 | VAR MULEQ expr { code3(varpush,(Inst)$1,muleq); $$=$3; }
44 | VAR DIVEQ expr { code3(varpush,(Inst)$1,diveq); $$=$3; }
45 | VAR MODEQ expr { code3(varpush,(Inst)$1,modeq); $$=$3; }
46 ;
47 stmt: expr { code(xpop); }
48 | RETURN { defnonly("return"); code(procret); }
49 | RETURN expr
50 { defnonly("return"); $$=$2; code(funcret); }
51 | PROCEDURE begin '(' arglist ')'
52 { $$ = $2; code3(call, (Inst)$1, (Inst)(uintptr)$4); }
53 | PRINT prlist { $$ = $2; }
54 | while '(' cond ')' stmt end {
55 ($1)[1] = (Inst)$5; /* body of loop */
56 ($1)[2] = (Inst)$6; } /* end, if cond fails */
57 | for '(' cond ';' cond ';' cond ')' stmt end {
58 ($1)[1] = (Inst)$5; /* condition */
59 ($1)[2] = (Inst)$7; /* post loop */
60 ($1)[3] = (Inst)$9; /* body of loop */
61 ($1)[4] = (Inst)$10; } /* end, if cond fails */
62 | if '(' cond ')' stmt end { /* else-less if */
63 ($1)[1] = (Inst)$5; /* thenpart */
64 ($1)[3] = (Inst)$6; } /* end, if cond fails */
65 | if '(' cond ')' stmt end ELSE stmt end { /* if with else */
66 ($1)[1] = (Inst)$5; /* thenpart */
67 ($1)[2] = (Inst)$8; /* elsepart */
68 ($1)[3] = (Inst)$9; } /* end, if cond fails */
69 | '{' stmtlist '}' { $$ = $2; }
70 ;
71 cond: expr { code(STOP); }
72 ;
73 while: WHILE { $$ = code3(whilecode,STOP,STOP); }
74 ;
75 for: FOR { $$ = code(forcode); code3(STOP,STOP,STOP); code(STOP); }
76 ;
77 if: IF { $$ = code(ifcode); code3(STOP,STOP,STOP); }
78 ;
79 begin: /* nothing */ { $$ = progp; }
80 ;
81 end: /* nothing */ { code(STOP); $$ = progp; }
82 ;
83 stmtlist: /* nothing */ { $$ = progp; }
84 | stmtlist '\n'
85 | stmtlist stmt
86 ;
87 expr: NUMBER { $$ = code2(constpush, (Inst)$1); }
88 | VAR { $$ = code3(varpush, (Inst)$1, eval); }
89 | asgn
90 | FUNCTION begin '(' arglist ')'
91 { $$ = $2; code3(call,(Inst)$1,(Inst)(uintptr)$4); }
92 | READ '(' VAR ')' { $$ = code2(varread, (Inst)$3); }
93 | BLTIN '(' expr ')' { $$=$3; code2(bltin, (Inst)$1->u.ptr); }
94 | '(' expr ')' { $$ = $2; }
95 | expr '+' expr { code(add); }
96 | expr '-' expr { code(sub); }
97 | expr '*' expr { code(mul); }
98 | expr '/' expr { code(div); }
99 | expr '%' expr { code(mod); }
100 | expr '^' expr { code (power); }
101 | '-' expr %prec UNARYMINUS { $$=$2; code(negate); }
102 | expr GT expr { code(gt); }
103 | expr GE expr { code(ge); }
104 | expr LT expr { code(lt); }
105 | expr LE expr { code(le); }
106 | expr EQ expr { code(eq); }
107 | expr NE expr { code(ne); }
108 | expr AND expr { code(and); }
109 | expr OR expr { code(or); }
110 | NOT expr { $$ = $2; code(not); }
111 | INC VAR { $$ = code2(preinc,(Inst)$2); }
112 | DEC VAR { $$ = code2(predec,(Inst)$2); }
113 | VAR INC { $$ = code2(postinc,(Inst)$1); }
114 | VAR DEC { $$ = code2(postdec,(Inst)$1); }
116 prlist: expr { code(prexpr); }
117 | STRING { $$ = code2(prstr, (Inst)$1); }
118 | prlist ',' expr { code(prexpr); }
119 | prlist ',' STRING { code2(prstr, (Inst)$3); }
121 defn: FUNC procname { $2->type=FUNCTION; indef=1; }
122 '(' formals ')' stmt { code(procret); define($2, $5); indef=0; }
123 | PROC procname { $2->type=PROCEDURE; indef=1; }
124 '(' formals ')' stmt { code(procret); define($2, $5); indef=0; }
126 formals: { $$ = 0; }
127 | VAR { $$ = formallist($1, 0); }
128 | VAR ',' formals { $$ = formallist($1, $3); }
130 procname: VAR
131 | FUNCTION
132 | PROCEDURE
134 arglist: /* nothing */ { $$ = 0; }
135 | expr { $$ = 1; }
136 | arglist ',' expr { $$ = $1 + 1; }
138 %%
139 /* end of grammar */
140 char *progname;
141 int lineno = 1;
142 jmp_buf begin;
143 int indef;
144 char *infile; /* input file name */
145 Biobuf *bin; /* input file descriptor */
146 Biobuf binbuf;
147 char **gargv; /* global argument list */
148 int gargc;
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 int
157 yylex(void) /* hoc6 */
159 while ((c=Bgetc(bin)) == ' ' || c == '\t')
161 if (c < 0)
162 return 0;
163 if (c == '\\') {
164 c = Bgetc(bin);
165 if (c == '\n') {
166 lineno++;
167 return yylex();
170 if (c == '#') { /* comment */
171 while ((c=Bgetc(bin)) != '\n' && c >= 0)
173 if (c == '\n')
174 lineno++;
175 return c;
177 if (c == '.' || isdigit(c)) { /* number */
178 double d;
179 Bungetc(bin);
180 Bgetd(bin, &d);
181 yylval.sym = install("", NUMBER, d);
182 return NUMBER;
184 if (isalpha(c) || c == '_') {
185 Symbol *s;
186 char sbuf[100], *p = sbuf;
187 do {
188 if (p >= sbuf + sizeof(sbuf) - 1) {
189 *p = '\0';
190 execerror("name too long", sbuf);
192 *p++ = c;
193 } while ((c=Bgetc(bin)) >= 0 && (isalnum(c) || c == '_'));
194 Bungetc(bin);
195 *p = '\0';
196 if ((s=lookup(sbuf)) == 0)
197 s = install(sbuf, UNDEF, 0.0);
198 yylval.sym = s;
199 return s->type == UNDEF ? VAR : s->type;
201 if (c == '"') { /* quoted string */
202 char sbuf[100], *p;
203 for (p = sbuf; (c=Bgetc(bin)) != '"'; p++) {
204 if (c == '\n' || c == Beof)
205 execerror("missing quote", "");
206 if (p >= sbuf + sizeof(sbuf) - 1) {
207 *p = '\0';
208 execerror("string too long", sbuf);
210 *p = backslash(c);
212 *p = 0;
213 yylval.sym = (Symbol *)emalloc(strlen(sbuf)+1);
214 strcpy((char*)yylval.sym, sbuf);
215 return STRING;
217 switch (c) {
218 case '+': return follow('+', INC, '+') == INC ? INC : follow('=', ADDEQ, '+');
219 case '-': return follow('-', DEC, '-') == DEC ? DEC : follow('=', SUBEQ, '-');
220 case '*': return follow('=', MULEQ, '*');
221 case '/': return follow('=', DIVEQ, '/');
222 case '%': return follow('=', MODEQ, '%');
223 case '>': return follow('=', GE, GT);
224 case '<': return follow('=', LE, LT);
225 case '=': return follow('=', EQ, '=');
226 case '!': return follow('=', NE, NOT);
227 case '|': return follow('|', OR, '|');
228 case '&': return follow('&', AND, '&');
229 case '\n': lineno++; return '\n';
230 default: return c;
234 int
235 backslash(int c) /* get next char with \'s interpreted */
237 static char transtab[] = "b\bf\fn\nr\rt\t";
238 if (c != '\\')
239 return c;
240 c = Bgetc(bin);
241 if (islower(c) && strchr(transtab, c))
242 return strchr(transtab, c)[1];
243 return c;
246 int
247 follow(int expect, int ifyes, int ifno) /* look ahead for >=, etc. */
249 int c = Bgetc(bin);
251 if (c == expect)
252 return ifyes;
253 Bungetc(bin);
254 return ifno;
257 void
258 yyerror(char* s) /* report compile-time error */
260 /*rob
261 warning(s, (char *)0);
262 longjmp(begin, 0);
263 rob*/
264 execerror(s, (char *)0);
267 void
268 execerror(char* s, char* t) /* recover from run-time error */
270 warning(s, t);
271 Bseek(bin, 0L, 2); /* flush rest of file */
272 restoreall();
273 longjmp(begin, 0);
276 void
277 fpecatch(void) /* catch floating point exceptions */
279 execerror("floating point exception", (char *) 0);
282 void
283 intcatch(void) /* catch interrupts */
285 execerror("interrupt", 0);
288 void
289 run(void) /* execute until EOF */
291 setjmp(begin);
292 for (initcode(); yyparse(); initcode())
293 execute(progbase);
296 void
297 main(int argc, char* argv[]) /* hoc6 */
299 static int first = 1;
300 #ifdef YYDEBUG
301 extern int yydebug;
302 yydebug=3;
303 #endif
304 progname = argv[0];
305 init();
306 if (argc == 1) { /* fake an argument list */
307 static char *stdinonly[] = { "-" };
309 gargv = stdinonly;
310 gargc = 1;
311 } else if (first) { /* for interrupts */
312 first = 0;
313 gargv = argv+1;
314 gargc = argc-1;
316 Binit(&binbuf, 0, OREAD);
317 bin = &binbuf;
318 while (moreinput())
319 run();
320 exits(0);
323 int
324 moreinput(void)
326 char *expr;
327 static char buf[64];
328 int fd;
329 static Biobuf b;
331 if (gargc-- <= 0)
332 return 0;
333 if (bin && bin != &binbuf)
334 Bterm(bin);
335 infile = *gargv++;
336 lineno = 1;
337 if (strcmp(infile, "-") == 0) {
338 bin = &binbuf;
339 infile = 0;
340 return 1;
342 if(strncmp(infile, "-e", 2) == 0) {
343 if(infile[2]==0){
344 if(gargc == 0){
345 fprint(2, "%s: no argument for -e\n", progname);
346 return 0;
348 gargc--;
349 expr = *gargv++;
350 }else
351 expr = infile+2;
352 sprint(buf, "/tmp/hocXXXXXXX");
353 fd = mkstemp(buf);
354 remove(buf);
355 /*
356 infile = mktemp(buf);
357 fd = create(infile, ORDWR|ORCLOSE, 0600);
358 if(fd < 0){
359 fprint(2, "%s: can't create temp. file: %r\n", progname);
360 return 0;
362 */
363 fprint(fd, "%s\n", expr);
364 /* leave fd around; file will be removed on exit */
365 /* the following looks weird but is required for unix version */
366 bin = &b;
367 seek(fd, 0, 0);
368 Binit(bin, fd, OREAD);
369 } else {
370 bin=Bopen(infile, OREAD);
371 if (bin == 0) {
372 fprint(2, "%s: can't open %s\n", progname, infile);
373 return moreinput();
376 return 1;
379 void
380 warning(char* s, char* t) /* print warning message */
382 fprint(2, "%s: %s", progname, s);
383 if (t)
384 fprint(2, " %s", t);
385 if (infile)
386 fprint(2, " in %s", infile);
387 fprint(2, " near line %d\n", lineno);
388 while (c != '\n' && c != Beof)
389 if((c = Bgetc(bin)) == '\n') /* flush rest of input line */
390 lineno++;
393 void
394 defnonly(char *s) /* warn if illegal definition */
396 if (!indef)
397 execerror(s, "used outside definition");