Introduction
Introduction Statistics Contact Development Disclaimer Help
hoc.y - 9base - revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log
Files
Refs
README
LICENSE
---
hoc.y (9754B)
---
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…
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 els…
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); co…
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); }
115 ;
116 prlist: expr { code(prexpr); }
117 | STRING { $$ = code2(prstr, (Inst)$1); }
118 | prlist ',' expr { code(prexpr); }
119 | prlist ',' STRING { code2(prstr, (Inst)$3); }
120 ;
121 defn: FUNC procname { $2->type=FUNCTION; indef=1; }
122 '(' formals ')' stmt { code(procret); define($2, $5); indef=…
123 | PROC procname { $2->type=PROCEDURE; indef=1; }
124 '(' formals ')' stmt { code(procret); define($2, $5); indef=…
125 ;
126 formals: { $$ = 0; }
127 | VAR { $$ = formallist($1, 0); }
128 | VAR ',' formals { $$ = formallist($1, $3); }
129 ;
130 procname: VAR
131 | FUNCTION
132 | PROCEDURE
133 ;
134 arglist: /* nothing */ { $$ = 0; }
135 | expr { $$ = 1; }
136 | arglist ',' expr { $$ = $1 + 1; }
137 ;
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;
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 int
157 yylex(void) /* hoc6 */
158 {
159 while ((c=Bgetc(bin)) == ' ' || c == '\t')
160 ;
161 if (c < 0)
162 return 0;
163 if (c == '\\') {
164 c = Bgetc(bin);
165 if (c == '\n') {
166 lineno++;
167 return yylex();
168 }
169 }
170 if (c == '#') { /* comment */
171 while ((c=Bgetc(bin)) != '\n' && c >= 0)
172 ;
173 if (c == '\n')
174 lineno++;
175 return c;
176 }
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;
183 }
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);
191 }
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;
200 }
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);
209 }
210 *p = backslash(c);
211 }
212 *p = 0;
213 yylval.sym = (Symbol *)emalloc(strlen(sbuf)+1);
214 strcpy((char*)yylval.sym, sbuf);
215 return STRING;
216 }
217 switch (c) {
218 case '+': return follow('+', INC, '+') == INC ? INC : fol…
219 case '-': return follow('-', DEC, '-') == DEC ? DEC : fol…
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;
231 }
232 }
233
234 int
235 backslash(int c) /* get next char with \'s interpreted */
236 {
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;
244 }
245
246 int
247 follow(int expect, int ifyes, int ifno) /* look ahead for >=, etc…
248 {
249 int c = Bgetc(bin);
250
251 if (c == expect)
252 return ifyes;
253 Bungetc(bin);
254 return ifno;
255 }
256
257 void
258 yyerror(char* s) /* report compile-time error */
259 {
260 /*rob
261 warning(s, (char *)0);
262 longjmp(begin, 0);
263 rob*/
264 execerror(s, (char *)0);
265 }
266
267 void
268 execerror(char* s, char* t) /* recover from run-time error */
269 {
270 warning(s, t);
271 Bseek(bin, 0L, 2); /* flush rest of file */
272 restoreall();
273 longjmp(begin, 0);
274 }
275
276 void
277 fpecatch(void) /* catch floating point exceptions */
278 {
279 execerror("floating point exception", (char *) 0);
280 }
281
282 void
283 intcatch(void) /* catch interrupts */
284 {
285 execerror("interrupt", 0);
286 }
287
288 void
289 run(void) /* execute until EOF */
290 {
291 setjmp(begin);
292 for (initcode(); yyparse(); initcode())
293 execute(progbase);
294 }
295
296 void
297 main(int argc, char* argv[]) /* hoc6 */
298 {
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[] = { "-" };
308
309 gargv = stdinonly;
310 gargc = 1;
311 } else if (first) { /* for interrupts */
312 first = 0;
313 gargv = argv+1;
314 gargc = argc-1;
315 }
316 Binit(&binbuf, 0, OREAD);
317 bin = &binbuf;
318 while (moreinput())
319 run();
320 exits(0);
321 }
322
323 int
324 moreinput(void)
325 {
326 char *expr;
327 static char buf[64];
328 int fd;
329 static Biobuf b;
330
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;
341 }
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", pr…
346 return 0;
347 }
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", p…
360 return 0;
361 }
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 ve…
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, infil…
373 return moreinput();
374 }
375 }
376 return 1;
377 }
378
379 void
380 warning(char* s, char* t) /* print warning message */
381 {
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 inp…
390 lineno++;
391 }
392
393 void
394 defnonly(char *s) /* warn if illegal definition */
395 {
396 if (!indef)
397 execerror(s, "used outside definition");
398 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.