|
|
1.1 root 1: /* Bc - an infix desk calculator */
2:
3: %{
4: #include <stdio.h>
5: #include "bc.h"
6: #define YYTNAMES
7:
8: /* This will generate yyerror() and error recovery */
9: #define YYSYNTAX goto YYerract
10: /* This will enter error recovery */
11: #define YYERROR ++yyerrflag; goto YYerract
12:
13: static code *breakloc = NULL; /* where to go on break statement */
14: static code *contloc = NULL; /* where to go on continue statement */
15: static dicent *retfrom = NULL; /* what function to return from */
16: static dicent **dvec; /* list of locals */
17: static dicent **pardvec; /* list of formal parameters */
18: static dicent **autdvec; /* list of automatic variables */
19: static int ldvec; /* length of dvec */
20: static int lpardvec; /* length of pardvec */
21: static int lautdvec; /* length of autdvec */
22: %}
23:
24:
25: %union {
26: opcode opcode;
27: rvalue *lvalue;
28: char *svalue;
29: dicent *dvalue;
30: int ivalue;
31: code *location;
32: }
33:
34:
35: %token <lvalue> NUMBER
36: %token <svalue> STRING
37: %token <dvalue> IDENTIFIER
38: %token ADDAB AUTO BREAK CONTINUE DECR DEFINE
39: %token DIVAB DO DOT ELSE EQP ERROR
40: %token EXPAB FOR GEP GTP IBASE IF
41: %token INCR LENGTH_ LEP LTP MULAB NEP
42: %token OBASE QUIT REMAB RETURN_ SCALE_ SQRT_
43: %token SUBAB WHILE
44:
45: %type <opcode> assignment_op special_load special_store
46: %type <opcode> function_like_primitive relational
47: %type <dvalue> local
48: %type <ivalue> argument_list non_empty_argument_list
49: %type <location> jump_true jump_false else_part
50: %type <location> goto save_loc save_break
51: %type <location> save_continue
52:
53: %right '='
54: %left '+' '-'
55: %left '*' '/' '%'
56: %right '^'
57: %left INCR DECR UMINUS
58:
59: %%
60: /* Error recovery: allok is FALSE if any syntax or semantic error
61: * occurred, but the error production will be reduced in all cases
62: * except one, the case where cstream overflows.
63: */
64:
65: session:
66: /* empty */
67: | session statement {
68: emitop(STOP);
69: immfix: if (allok)
70: interp();
71: litfree(cstream, loc);
72: loc = cstream;
73: allok = TRUE;
74: breakloc = contloc = retfrom = NULL;
75: }
76: | session definition {
77: if (loc[-1].opcode != RETURN) {
78: emitop(PGLSC);
79: emitnum(&zero);
80: emitop(LOAD);
81: emitop(RETURN);
82: emitid(retfrom);
83: }
84: deffix: if (allok)
85: install(&retfrom->globalv.fvalue, pardvec, lpardvec,
86: autdvec, lautdvec);
87: else {
88: remloc(pardvec, lpardvec);
89: remloc(autdvec, lautdvec);
90: retfrom->globalt = UNDEFINED;
91: litfree(cstream, loc);
92: }
93: mpfree(pardvec);
94: lpardvec = 0;
95: pardvec = NULL;
96: mpfree(autdvec);
97: lautdvec = 0;
98: autdvec = NULL;
99: mpfree(dvec);
100: ldvec = 0;
101: dvec = NULL;
102: loc = cstream;
103: allok = TRUE;
104: breakloc = contloc = retfrom = NULL;
105: }
106: | session error '\n' {
107: YYERROK;
108: if (retfrom != NULL)
109: goto deffix;
110: else
111: goto immfix;
112: }
113: ;
114:
115: /*
116: * Statements.
117: */
118:
119: statement:
120: /*
121: * The code generated for an IF statement with an else part is as
122: * follows:
123: * if not condition, goto L1
124: * true part of IF statement
125: * goto L2
126: * L1: false part of IF statement
127: * L2:
128: *
129: * If there is no ELSE part, then the code generated is as
130: * follows:
131: * if not condition, goto L1
132: * true part of IF statement
133: * L1:
134: */
135: IF '(' jump_false ')' /* $1 */
136: statement /* $5 */
137: else_part { /* $6 */
138: patch($3, $6);
139: }
140: |
141: /*
142: * The code generated for the WHILE statement is as
143: * follows:
144: * CONTINUE: if condition, goto L1
145: * BREAK: goto L2
146: * L1: body of WHILE statement
147: * goto CONTINUE
148: * L2:
149: */
150: WHILE save_continue '(' jump_true ')' /* $1 */
151: save_break goto /* $6 */
152: save_loc statement /* $8 */
153: goto { /* $10 */
154: patch($4, $8);
155: patch($7, loc);
156: patch($10, contloc);
157: breakloc = $6; /* restore break */
158: contloc = $2; /* restore continue */
159: }
160: |
161: /*
162: * The code produced for the FOR statement is as
163: * follows:
164: * initialization expression
165: * L1: if condition, goto L3
166: * BREAK: goto L4
167: * CONTINUE: increment expression
168: * goto L1
169: * L3: body of FOR statement
170: * goto CONTINUE
171: * L4:
172: */
173: FOR '(' optional_expression_list';' /* $1 */
174: save_loc jump_true ';' /* $5 */
175: save_break goto /* $8 */
176: save_continue optional_expression_list ')' /* $10 */
177: goto /* $13 */
178: save_loc statement /* $14 */
179: goto { /* $16 */
180: patch($6, $14);
181: patch($9, loc);
182: patch($13, $5);
183: patch($16, contloc);
184: breakloc = $8;
185: contloc = $10;
186: }
187: |
188: /*
189: * The code produced for the DO-WHILE statement is as
190: * follows:
191: * goto L1
192: * BREAK: goto L3
193: * CONTINUE: goto L2
194: * L1: body of DO-WHILE statement
195: * L2: if condition, goto L1
196: * L3:
197: */
198: DO goto /* $1 */
199: save_break goto /* $3 */
200: save_continue goto /* $5 */
201: save_loc statement WHILE '(' /* $7 */
202: save_loc jump_true ')' end_of_statement { /* $11 */
203: patch($2, $7);
204: patch($4, loc);
205: patch($6, $11);
206: patch($12, $7);
207: breakloc = $3;
208: contloc = $5;
209: }
210: | BREAK end_of_statement {
211: if (breakloc == NULL) {
212: gerror("Break not in loop");
213: YYERROR;
214: }
215: emitop(BRALW);
216: emitaddr(breakloc);
217: }
218: | CONTINUE end_of_statement {
219: if (contloc == NULL) {
220: gerror("Continue not in loop");
221: YYERROR;
222: }
223: emitop(BRALW);
224: emitaddr(contloc);
225: }
226: | RETURN_ end_of_statement {
227: if (retfrom == NULL) {
228: gerror("Return not in function");
229: YYERROR;
230: }
231: emitop(PGLSC);
232: emitnum(&zero);
233: emitop(LOAD);
234: emitop(RETURN);
235: emitid(retfrom);
236: }
237: | RETURN_ expression end_of_statement {
238: if (retfrom == NULL) {
239: gerror("Return not in function");
240: YYERROR;
241: }
242: emitop(RETURN);
243: emitid(retfrom);
244: }
245: | assignment_expression end_of_statement {
246: emitop(POP);
247: }
248: | non_assignment_expression end_of_statement {
249: emitop(PRNUM);
250: emitop(PRNL);
251: }
252: | non_assignment_expression '$' end_of_statement {
253: emitop(PRNUM);
254: }
255: | STRING end_of_statement {
256: emitop(PRSTR);
257: emitstr($1);
258: emitop(PRNL);
259: }
260: | STRING '$' end_of_statement {
261: emitop(PRSTR);
262: emitstr($1);
263: }
264: | '{' statement_list '}'
265: | QUIT end_of_statement {
266: emitop(EXIT);
267: }
268: | end_of_statement
269: ;
270:
271: end_of_statement:
272: ';'
273: | '\n'
274: ;
275:
276: statement_list:
277: /* empty */
278: | statement_list statement
279: ;
280:
281: else_part:
282: /* empty */ {
283: $$ = loc;
284: }
285: | ELSE goto save_loc statement {
286: $$ = $3;
287: patch($2, loc);
288: }
289: ;
290:
291: optional_expression_list:
292: /* empty */
293: | non_empty_expression_list
294: ;
295:
296: non_empty_expression_list:
297: expression {
298: emitop(POP);
299: }
300: | non_empty_expression_list ',' expression {
301: emitop(POP);
302: }
303: ;
304:
305: goto:
306: /* empty */ {
307: emitop(BRALW);
308: $$ = emitzap;
309: }
310: ;
311:
312: save_loc:
313: /* empty */ {
314: $$ = loc;
315: }
316: ;
317:
318: save_break:
319: /* empty */ {
320: $$ = breakloc;
321: breakloc = loc;
322: }
323: ;
324:
325: save_continue:
326: /* empty */ {
327: $$ = contloc;
328: contloc = loc;
329: }
330: ;
331:
332: /*
333: * Function definition.
334: */
335:
336: definition:
337: definition_header '(' parameter_list ')' /* $1 */
338: optional_nl '{' '\n' /* $5 */
339: optional_auto statement_list '}' /* $8 */
340: ;
341:
342: definition_header:
343: DEFINE IDENTIFIER {
344: if (chkfunc($2)) {
345: retfrom = $2;
346: } else {
347: YYERROR;
348: }
349: }
350: ;
351:
352: parameter_list:
353: /* empty */
354: | non_empty_local_list {
355: pardvec = dvec;
356: lpardvec = ldvec;
357: locaddr(pardvec, lpardvec, 0);
358: dvec = NULL;
359: ldvec = 0;
360: }
361: ;
362:
363: optional_auto:
364: /* empty */
365: | AUTO non_empty_local_list end_of_statement {
366: autdvec = dvec;
367: lautdvec = ldvec;
368: locaddr(autdvec, lautdvec, lpardvec);
369: dvec = NULL;
370: ldvec = 0;
371: }
372: ;
373:
374: non_empty_local_list:
375: local {
376: dvec = (dicent **)mpalc(ldvec * sizeof (*dvec));
377: dvec += ldvec;
378: *--dvec = $1;
379: }
380: | local ',' non_empty_local_list {
381: *--dvec = $1;
382: }
383: ;
384:
385: local:
386: IDENTIFIER {
387: if ($1->localt != UNDEFINED) {
388: gerror("Attempt to redeclare %s", $1->word);
389: YYERROR;
390: }
391: $1->localt = SCALAR;
392: ++ldvec;
393: /* $$ = $1 */
394: }
395: | IDENTIFIER '[' ']' {
396: if ($1->localt != UNDEFINED) {
397: gerror("Attempt to redeclare %s", $1->word);
398: YYERROR;
399: }
400: $1->localt = ARRAY;
401: ++ldvec;
402: /* $$ = $1 */
403: }
404: ;
405:
406: optional_nl:
407: /* empty */
408: | '\n'
409: ;
410:
411: /*
412: * Expressions.
413: */
414:
415: expression:
416: assignment_expression
417: | non_assignment_expression
418: ;
419:
420: assignment_expression:
421: l_value '=' expression {
422: emitop(STORE);
423: }
424: | l_value add_r_value assignment_op expression {
425: emitop($3);
426: emitop(STORE);
427: }
428: | special_store '=' expression {
429: emitop($1);
430: }
431: | special_load assignment_op expression {
432: emitop($2);
433: emitop($1);
434: }
435: ;
436:
437: non_assignment_expression:
438: NUMBER {
439: emitop(PLISC);
440: emitnum($1);
441: emitop(LOAD);
442: }
443: | l_value {
444: emitop(LOAD);
445: }
446: | special_load
447: | IDENTIFIER '(' argument_list ')' {
448: if (chkfunc($1)) {
449: emitop(CALL);
450: emitid($1);
451: emitcnt($3);
452: } else {
453: YYERROR;
454: }
455: }
456: | INCR l_value {
457: emitop(PRVAL);
458: emitop(INC);
459: emitop(STORE);
460: }
461: | INCR special_load {
462: emitop(INC);
463: emitop($2);
464: }
465: | DECR l_value {
466: emitop(PRVAL);
467: emitop(DEC);
468: emitop(STORE);
469: }
470: | DECR special_load {
471: emitop(DEC);
472: emitop($2);
473: }
474: | l_value INCR {
475: emitop(PRVAL);
476: emitop(INC);
477: emitop(STORE);
478: emitop(DEC);
479: }
480: | special_load INCR {
481: emitop(INC);
482: emitop($1);
483: emitop(DEC);
484: }
485: | l_value DECR {
486: emitop(PRVAL);
487: emitop(DEC);
488: emitop(STORE);
489: emitop(INC);
490: }
491: | special_load DECR {
492: emitop(DEC);
493: emitop($1);
494: emitop(INC);
495: }
496: | '-' non_assignment_expression %prec UMINUS {
497: emitop(NEG);
498: }
499: | non_assignment_expression '^' non_assignment_expression {
500: emitop(EXP);
501: }
502: | non_assignment_expression '*' non_assignment_expression {
503: emitop(MUL);
504: }
505: | non_assignment_expression '/' non_assignment_expression {
506: emitop(DIV);
507: }
508: | non_assignment_expression '%' non_assignment_expression {
509: emitop(REM);
510: }
511: | non_assignment_expression '+' non_assignment_expression {
512: emitop(ADD);
513: }
514: | non_assignment_expression '-' non_assignment_expression {
515: emitop(SUB);
516: }
517: | '(' expression ')'
518: | function_like_primitive '(' expression ')' {
519: emitop($1);
520: }
521: ;
522:
523: l_value:
524: IDENTIFIER {
525: if (chktype($1, SCALAR))
526: sload($1);
527: else {
528: YYERROR;
529: }
530: }
531: | IDENTIFIER '[' expression ']' {
532: if (chktype($1, ARRAY))
533: aeload($1);
534: else {
535: YYERROR;
536: }
537: }
538: | DOT {
539: emitop(PGLSC);
540: emitnum(&dot);
541: }
542: ;
543:
544: argument:
545: expression
546: | IDENTIFIER '[' ']' {
547: if (chktype($1, ARRAY))
548: arload($1);
549: else {
550: YYERROR;
551: }
552: }
553: ;
554:
555: argument_list:
556: /* empty */ {
557: $$ = 0;
558: }
559: | non_empty_argument_list
560: /* $$ = $1 */
561: ;
562:
563: non_empty_argument_list:
564: argument {
565: $$ = 1;
566: }
567: | non_empty_argument_list ',' argument {
568: $$ = $1 + 1;
569: }
570: ;
571:
572: add_r_value:
573: /* empty */ {
574: emitop(PRVAL);
575: }
576: ;
577:
578: special_store:
579: IBASE {
580: $$ = SIBASE;
581: }
582: | OBASE {
583: $$ = SOBASE;
584: }
585: | SCALE_ {
586: $$ = SSCALE;
587: }
588: ;
589:
590: special_load:
591: IBASE {
592: emitop(LIBASE);
593: $$ = SIBASE;
594: }
595: | OBASE {
596: emitop(LOBASE);
597: $$ = SOBASE;
598: }
599: | SCALE_ {
600: emitop(LSCALE);
601: $$ = SSCALE;
602: }
603: ;
604:
605: assignment_op:
606: ADDAB {
607: $$ = ADD;
608: }
609: | SUBAB {
610: $$ = SUB;
611: }
612: | MULAB {
613: $$ = MUL;
614: }
615: | DIVAB {
616: $$ = DIV;
617: }
618: | REMAB {
619: $$ = REM;
620: }
621: | EXPAB {
622: $$ = EXP;
623: }
624: ;
625:
626: function_like_primitive:
627: SQRT_ {
628: $$ = SQRT;
629: }
630: | LENGTH_ {
631: $$ = LENGTH;
632: }
633: | SCALE_ {
634: $$ = SCALE;
635: }
636: ;
637:
638: /*
639: * Conditionals.
640: */
641:
642: jump_true:
643: /* empty */ {
644: emitop(BRALW);
645: $$ = emitzap;
646: }
647: | non_assignment_expression relational non_assignment_expression {
648: emitop($2);
649: $$ = emitzap;
650: }
651: ;
652:
653: jump_false:
654: /* empty */ {
655: emitop(BRNEV);
656: $$ = emitzap;
657: }
658: | non_assignment_expression relational non_assignment_expression {
659: emitop(negate($2));
660: $$ = emitzap;
661: }
662: ;
663:
664: relational:
665: LTP {
666: $$ = BRLT;
667: }
668: | LEP {
669: $$ = BRLE;
670: }
671: | EQP {
672: $$ = BREQ;
673: }
674: | GEP {
675: $$ = BRGE;
676: }
677: | GTP {
678: $$ = BRGT;
679: }
680: | NEP {
681: $$ = BRNE;
682: }
683: ;
684:
685: %%
686:
687: /*
688: * Yyerror is the error routine called on a syntax error by
689: * yyparse.
690: */
691:
692: yyerror(m)
693: char *m;
694: {
695: register struct yytname *ptr;
696:
697: for (ptr = yytnames; ptr->tn_name != NULL; ++ptr)
698: if (ptr->tn_val == yychar)
699: return gerror("%s at %s", m, ptr->tn_name);
700: return gerror("%s", m);
701: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.