]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hoc/hoc.y
merge
[plan9front.git] / sys / src / cmd / hoc / hoc.y
1 %{
2 #include "hoc.h"
3 #define code2(c1,c2)    code(c1); code(c2)
4 #define code3(c1,c2,c3) code(c1); code(c2); code(c3)
5 %}
6 %union {
7         Symbol  *sym;   /* symbol table pointer */
8         Inst    *inst;  /* machine instruction */
9         int     narg;   /* number of arguments */
10         Formal  *formals;       /* list of formal parameters */
11 }
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 
17 %type   <sym>   procname
18 %type   <narg>  arglist
19 %right  '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ
20 %left   OR
21 %left   AND
22 %left   GT GE LT LE EQ NE
23 %left   '+' '-'
24 %left   '*' '/' '%'
25 %left   UNARYMINUS NOT INC DEC
26 %right  '^'
27 %%
28 list:     /* nothing */
29         | list '\n'
30         | list defn '\n'
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; }
35         ;
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; }
42         ;
43 stmt:     expr  { code(xpop); }
44         | RETURN { defnonly("return"); code(procret); }
45         | RETURN expr
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; }
66         ;
67 cond:      expr         { code(STOP); }
68         ;
69 while:    WHILE { $$ = code3(whilecode,STOP,STOP); }
70         ;
71 for:      FOR   { $$ = code(forcode); code3(STOP,STOP,STOP); code(STOP); }
72         ;
73 if:       IF    { $$ = code(ifcode); code3(STOP,STOP,STOP); }
74         ;
75 begin:    /* nothing */         { $$ = progp; }
76         ;
77 end:      /* nothing */         { code(STOP); $$ = progp; }
78         ;
79 stmtlist: /* nothing */         { $$ = progp; }
80         | stmtlist '\n'
81         | stmtlist stmt
82         ;
83 expr:     NUMBER { $$ = code2(constpush, (Inst)$1); }
84         | VAR    { $$ = code3(varpush, (Inst)$1, eval); }
85         | asgn
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); }
111         ;
112 prlist:   expr                  { code(prexpr); }
113         | STRING                { $$ = code2(prstr, (Inst)$1); }
114         | prlist ',' expr       { code(prexpr); }
115         | prlist ',' STRING     { code2(prstr, (Inst)$3); }
116         ;
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; }
121         ;
122 formals:        { $$ = 0; }
123         | VAR                   { $$ = formallist($1, 0); }
124         | VAR ',' formals       { $$ = formallist($1, $3); }
125         ;
126 procname: VAR
127         | FUNCTION
128         | PROCEDURE
129         ;
130 arglist:  /* nothing */         { $$ = 0; }
131         | expr                  { $$ = 1; }
132         | arglist ',' expr      { $$ = $1 + 1; }
133         ;
134 %%
135         /* end of grammar */
136 #include <u.h>
137 #include <libc.h>
138 #include <bio.h>
139 #include <ctype.h>
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;
149
150 int c = '\n';   /* global for use by warning() */
151
152 int     backslash(int), follow(int, int, int);
153 void    defnonly(char*), run(void);
154 void    warning(char*, char*);
155
156 yylex(void)             /* hoc6 */
157 {
158         while ((c=Bgetc(bin)) == ' ' || c == '\t')
159                 ;
160         if (c < 0)
161                 return 0;
162         if (c == '\\') {
163                 c = Bgetc(bin);
164                 if (c == '\n') {
165                         lineno++;
166                         return yylex();
167                 }
168         }
169         if (c == '#') {         /* comment */
170                 while ((c=Bgetc(bin)) != '\n' && c >= 0)
171                         ;
172                 if (c == '\n')
173                         lineno++;
174                 return c;
175         }
176         if (c == '.' || isdigit(c)) {   /* number */
177                 double d;
178                 Bungetc(bin);
179                 Bgetd(bin, &d);
180                 yylval.sym = install("", NUMBER, d);
181                 return NUMBER;
182         }
183         if (isalpha(c) || c == '_' || c >= 0x80) {
184                 Symbol *s;
185                 char sbuf[100], *p = sbuf;
186                 do {
187                         if (p >= sbuf + sizeof(sbuf) - 1) {
188                                 *p = '\0';
189                                 execerror("name too long", sbuf);
190                         }
191                         *p++ = c;
192                 } while ((c=Bgetc(bin)) >= 0 && (isalnum(c) || c == '_' || c >= 0x80));
193                 Bungetc(bin);
194                 *p = '\0';
195                 if ((s=lookup(sbuf)) == 0)
196                         s = install(sbuf, UNDEF, 0.0);
197                 yylval.sym = s;
198                 return s->type == UNDEF ? VAR : s->type;
199         }
200         if (c == '"') { /* quoted string */
201                 char sbuf[100], *p;
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) {
206                                 *p = '\0';
207                                 execerror("string too long", sbuf);
208                         }
209                         *p = backslash(c);
210                 }
211                 *p = 0;
212                 yylval.sym = (Symbol *)emalloc(strlen(sbuf)+1);
213                 strcpy((char*)yylval.sym, sbuf);
214                 return STRING;
215         }
216         switch (c) {
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';
229         default:        return c;
230         }
231 }
232
233 backslash(int c)        /* get next char with \'s interpreted */
234 {
235         static char transtab[] = "b\bf\fn\nr\rt\t";
236         if (c != '\\')
237                 return c;
238         c = Bgetc(bin);
239         if (islower(c) && strchr(transtab, c))
240                 return strchr(transtab, c)[1];
241         return c;
242 }
243
244 follow(int expect, int ifyes, int ifno) /* look ahead for >=, etc. */
245 {
246         int c = Bgetc(bin);
247
248         if (c == expect)
249                 return ifyes;
250         Bungetc(bin);
251         return ifno;
252 }
253
254 void
255 yyerror(char* s)        /* report compile-time error */
256 {
257 /*rob
258         warning(s, (char *)0);
259         longjmp(begin, 0);
260 rob*/
261         execerror(s, (char *)0);
262 }
263
264 void
265 execerror(char* s, char* t)     /* recover from run-time error */
266 {
267         warning(s, t);
268         Bseek(bin, 0L, 2);              /* flush rest of file */
269         restoreall();
270         longjmp(begin, 0);
271 }
272
273 void
274 fpecatch(void)  /* catch floating point exceptions */
275 {
276         execerror("floating point exception", (char *) 0);
277 }
278
279 void
280 intcatch(void)  /* catch interrupts */
281 {
282         execerror("interrupt", 0);
283 }
284
285 void
286 run(void)       /* execute until EOF */
287 {
288         setjmp(begin);
289         for (initcode(); yyparse(); initcode())
290                 execute(progbase);
291 }
292
293 void
294 main(int argc, char* argv[])    /* hoc6 */
295 {
296         static int first = 1;
297 #ifdef YYDEBUG
298         extern int yydebug;
299         yydebug=3;
300 #endif
301         progname = argv[0];
302         init();
303         if (argc == 1) {        /* fake an argument list */
304                 static char *stdinonly[] = { "-" };
305
306                 gargv = stdinonly;
307                 gargc = 1;
308         } else if (first) {     /* for interrupts */
309                 first = 0;
310                 gargv = argv+1;
311                 gargc = argc-1;
312         }
313         Binit(&binbuf, 0, OREAD);
314         bin = &binbuf;
315         while (moreinput())
316                 run();
317         exits(0);
318 }
319
320 moreinput(void)
321 {
322         char *expr;
323         static char buf[64];
324         int fd;
325         static Biobuf b;
326
327         if (gargc-- <= 0)
328                 return 0;
329         if (bin && bin != &binbuf)
330                 Bterm(bin);
331         infile = *gargv++;
332         lineno = 1;
333         if (strcmp(infile, "-") == 0) {
334                 bin = &binbuf;
335                 infile = 0;
336                 return 1;
337         }
338         if(strncmp(infile, "-e", 2) == 0) {
339                 if(infile[2]==0){
340                         if(gargc == 0){
341                                 fprint(2, "%s: no argument for -e\n", progname);
342                                 return 0;
343                         }
344                         gargc--;
345                         expr = *gargv++;
346                 }else
347                         expr = infile+2;
348                 sprint(buf, "/tmp/hocXXXXXXX");
349                 infile = mktemp(buf);
350                 fd = create(infile, ORDWR|ORCLOSE, 0600);
351                 if(fd < 0){
352                         fprint(2, "%s: can't create temp. file: %r\n", progname);
353                         return 0;
354                 }
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 */
358                 bin = &b;
359                 seek(fd, 0, 0);
360                 Binit(bin, fd, OREAD);
361         } else {
362                 bin=Bopen(infile, OREAD);
363                 if (bin == 0) {
364                         fprint(2, "%s: can't open %s\n", progname, infile);
365                         return moreinput();
366                 }
367         }
368         return 1;
369 }
370
371 void
372 warning(char* s, char* t)       /* print warning message */
373 {
374         fprint(2, "%s: %s", progname, s);
375         if (t)
376                 fprint(2, " %s", t);
377         if (infile)
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 */
382                         lineno++;
383 }
384
385 void
386 defnonly(char *s)       /* warn if illegal definition */
387 {
388         if (!indef)
389                 execerror(s, "used outside definition");
390 }