Annotation of src/usr.bin/bc/bc.y, Revision 1.21
1.1 otto 1: %{
1.21 ! otto 2: /* $OpenBSD: bc.y,v 1.20 2003/12/02 09:00:07 otto Exp $ */
1.1 otto 3:
4: /*
5: * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
20: /*
21: * This implementation of bc(1) uses concepts from the original 4.4
22: * BSD bc(1). The code itself is a complete rewrite, based on the
23: * Posix defined bc(1) grammar. Other differences include type safe
24: * usage of pointers to build the tree of emitted code, typed yacc
25: * rule values, dynamic allocation of all data structures and a
26: * completely rewritten lexical analyzer using lex(1).
27: *
28: * Some effort has been made to make sure that the generated code is
29: * the same as the code generated by the older version, to provide
30: * easy regression testing.
31: */
32:
33: #ifndef lint
1.21 ! otto 34: static const char rcsid[] = "$OpenBSD: bc.y,v 1.20 2003/12/02 09:00:07 otto Exp $";
1.1 otto 35: #endif /* not lint */
36:
37: #include <ctype.h>
38: #include <err.h>
39: #include <limits.h>
1.20 otto 40: #include <search.h>
1.1 otto 41: #include <signal.h>
42: #include <stdarg.h>
43: #include <stdbool.h>
44: #include <string.h>
45: #include <unistd.h>
46:
47: #include "extern.h"
48: #include "pathnames.h"
49:
50: #define END_NODE ((ssize_t) -1)
51: #define CONST_STRING ((ssize_t) -2)
52: #define ALLOC_STRING ((ssize_t) -3)
53:
54: struct tree {
55: ssize_t index;
56: union {
57: char *astr;
58: const char *cstr;
59: } u;
60: };
61:
62: int yyparse(void);
63: int yywrap(void);
64:
65: static void grow(void);
66: static ssize_t cs(const char *);
67: static ssize_t as(const char *);
68: static ssize_t node(ssize_t, ...);
69: static void emit(ssize_t);
70: static void emit_macro(int, ssize_t);
71: static void free_tree(void);
72: static ssize_t numnode(int);
1.20 otto 73: static ssize_t lookup(char *, size_t, char);
74: static ssize_t letter_node(char *);
75: static ssize_t array_node(char *);
76: static ssize_t function_node(char *);
77:
1.1 otto 78: static void add_par(ssize_t);
79: static void add_local(ssize_t);
80: static void warning(const char *);
81: static void init(void);
82: static __dead void usage(void);
1.15 otto 83: static char *escape(const char *);
1.1 otto 84:
85: static size_t instr_sz = 0;
86: static struct tree *instructions = NULL;
1.7 otto 87: static ssize_t current = 0;
1.1 otto 88: static int macro_char = '0';
89: static int reset_macro_char = '0';
90: static int nesting = 0;
91: static int breakstack[16];
92: static int breaksp = 0;
93: static ssize_t prologue;
94: static ssize_t epilogue;
1.11 otto 95: static bool st_has_continue;
1.1 otto 96: static char str_table[UCHAR_MAX][2];
97: static int sargc;
98: static char **sargv;
99: static char *filename;
100: static bool do_fork = true;
1.20 otto 101: static u_short var_count;
1.1 otto 102:
103: extern char *__progname;
104:
105: #define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0]))
106:
1.20 otto 107: /* These values are 4.4BSD bc compatible */
1.1 otto 108: #define FUNC_CHAR 0x01
109: #define ARRAY_CHAR 0xa1
110:
1.20 otto 111: /* Skip '\0', [, \ and ] */
112: #define ENCODE(c) ((c) < '[' ? (c) : (c) + 3);
113: #define VAR_BASE (256-4)
114: #define MAX_VARIABLES (VAR_BASE * VAR_BASE)
1.1 otto 115:
116: %}
117:
118: %start program
119:
120: %union {
121: ssize_t node;
122: struct lvalue lvalue;
123: const char *str;
1.20 otto 124: char *astr;
1.1 otto 125: }
126:
1.9 otto 127: %token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT
128: %token NEWLINE
1.20 otto 129: %token <astr> LETTER
130: %token <str> NUMBER STRING
1.1 otto 131: %token DEFINE BREAK QUIT LENGTH
132: %token RETURN FOR IF WHILE SQRT
133: %token SCALE IBASE OBASE AUTO
1.15 otto 134: %token CONTINUE ELSE PRINT
1.1 otto 135:
1.19 otto 136: %left BOOL_OR
137: %left BOOL_AND
138: %nonassoc BOOL_NOT
1.1 otto 139: %nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER
140: %right <str> ASSIGN_OP
141: %left PLUS MINUS
142: %left MULTIPLY DIVIDE REMAINDER
1.17 otto 143: %right EXPONENT
1.1 otto 144: %nonassoc UMINUS
145: %nonassoc INCR DECR
146:
147: %type <lvalue> named_expression
148: %type <node> argument_list
149: %type <node> alloc_macro
150: %type <node> expression
151: %type <node> function
152: %type <node> function_header
153: %type <node> input_item
154: %type <node> opt_argument_list
1.13 otto 155: %type <node> opt_expression
156: %type <node> opt_relational_expression
1.1 otto 157: %type <node> opt_statement
1.15 otto 158: %type <node> print_expression
159: %type <node> print_expression_list
1.1 otto 160: %type <node> relational_expression
161: %type <node> return_expression
162: %type <node> semicolon_list
163: %type <node> statement
164: %type <node> statement_list
165:
166: %%
167:
168: program : /* empty */
1.20 otto 169: | program input_item
1.1 otto 170: ;
171:
172: input_item : semicolon_list NEWLINE
173: {
174: emit($1);
175: macro_char = reset_macro_char;
176: putchar('\n');
177: free_tree();
1.11 otto 178: st_has_continue = false;
1.1 otto 179: }
180: | function
181: {
182: putchar('\n');
183: free_tree();
1.11 otto 184: st_has_continue = false;
1.1 otto 185: }
1.8 otto 186: | error NEWLINE
1.1 otto 187: {
1.8 otto 188: yyerrok;
1.1 otto 189: }
190: ;
191:
192: semicolon_list : /* empty */
193: {
194: $$ = cs("");
195: }
196: | statement
197: | semicolon_list SEMICOLON statement
198: {
199: $$ = node($1, $3, END_NODE);
200: }
201: | semicolon_list SEMICOLON
202: ;
203:
204: statement_list : /* empty */
205: {
206: $$ = cs("");
207: }
208: | statement
209: | statement_list NEWLINE
210: | statement_list NEWLINE statement
211: {
212: $$ = node($1, $3, END_NODE);
213: }
214: | statement_list SEMICOLON
215: | statement_list SEMICOLON statement
216: {
217: $$ = node($1, $3, END_NODE);
218: }
219: ;
220:
221:
222: opt_statement : /* empty */
223: {
224: $$ = cs("");
225: }
226: | statement
227: ;
228:
229: statement : expression
230: {
231: $$ = node($1, cs("ps."), END_NODE);
232: }
233: | named_expression ASSIGN_OP expression
234: {
1.11 otto 235: if ($2[0] == '\0')
236: $$ = node($3, cs($2), $1.store,
237: END_NODE);
238: else
239: $$ = node($1.load, $3, cs($2), $1.store,
240: END_NODE);
1.1 otto 241: }
242: | STRING
243: {
244: $$ = node(cs("["), as($1),
245: cs("]P"), END_NODE);
246: }
247: | BREAK
248: {
249: if (breaksp == 0) {
250: warning("break not in for or while");
251: YYERROR;
252: } else {
253: $$ = node(
254: numnode(nesting -
255: breakstack[breaksp-1]),
256: cs("Q"), END_NODE);
257: }
258: }
1.11 otto 259: | CONTINUE
260: {
261: if (breaksp == 0) {
262: warning("continue not in for or while");
263: YYERROR;
264: } else {
265: st_has_continue = true;
266: $$ = node(numnode(nesting -
267: breakstack[breaksp-1] - 1),
268: cs("J"), END_NODE);
269: }
270: }
1.1 otto 271: | QUIT
272: {
273: putchar('q');
274: fflush(stdout);
275: exit(0);
276: }
1.16 otto 277: | RETURN return_expression
1.1 otto 278: {
279: if (nesting == 0) {
1.8 otto 280: warning("return must be in a function");
1.1 otto 281: YYERROR;
282: }
1.16 otto 283: $$ = $2;
1.1 otto 284: }
1.13 otto 285: | FOR LPAR alloc_macro opt_expression SEMICOLON
286: opt_relational_expression SEMICOLON
287: opt_expression RPAR opt_statement pop_nesting
1.1 otto 288: {
1.11 otto 289: ssize_t n;
290:
291: if (st_has_continue)
292: n = node($10, cs("M"), $8, cs("s."),
293: $6, $3, END_NODE);
294: else
295: n = node($10, $8, cs("s."), $6, $3,
296: END_NODE);
297:
1.1 otto 298: emit_macro($3, n);
299: $$ = node($4, cs("s."), $6, $3, cs(" "),
300: END_NODE);
301: }
302: | IF LPAR alloc_macro pop_nesting relational_expression RPAR
303: opt_statement
304: {
305: emit_macro($3, $7);
306: $$ = node($5, $3, cs(" "), END_NODE);
1.14 otto 307: }
308: | IF LPAR alloc_macro pop_nesting relational_expression RPAR
309: opt_statement ELSE alloc_macro pop_nesting opt_statement
310: {
311: emit_macro($3, $7);
312: emit_macro($9, $11);
313: $$ = node($5, $3, cs("e"), $9, cs(" "),
314: END_NODE);
1.1 otto 315: }
316: | WHILE LPAR alloc_macro relational_expression RPAR
317: opt_statement pop_nesting
318: {
1.11 otto 319: ssize_t n;
320:
321: if (st_has_continue)
322: n = node($6, cs("M"), $4, $3, END_NODE);
323: else
324: n = node($6, $4, $3, END_NODE);
1.1 otto 325: emit_macro($3, n);
326: $$ = node($4, $3, cs(" "), END_NODE);
327: }
328: | LBRACE statement_list RBRACE
329: {
330: $$ = $2;
331: }
1.15 otto 332: | PRINT print_expression_list
333: {
334: $$ = $2;
335: }
1.1 otto 336: ;
337:
338: alloc_macro : /* empty */
339: {
340: $$ = cs(str_table[macro_char]);
341: macro_char++;
342: /* Do not use [, \ and ] */
343: if (macro_char == '[')
344: macro_char += 3;
345: /* skip letters */
346: else if (macro_char == 'a')
347: macro_char = '{';
348: else if (macro_char == ARRAY_CHAR)
349: macro_char += 26;
1.20 otto 350: else if (macro_char == 255)
1.1 otto 351: fatal("program too big");
352: if (breaksp == BREAKSTACK_SZ)
353: fatal("nesting too deep");
354: breakstack[breaksp++] = nesting++;
355: }
1.11 otto 356: ;
357:
1.1 otto 358: pop_nesting : /* empty */
359: {
360: breaksp--;
361: }
1.11 otto 362: ;
1.1 otto 363:
1.16 otto 364: function : function_header opt_parameter_list RPAR opt_newline
1.1 otto 365: LBRACE NEWLINE opt_auto_define_list
366: statement_list RBRACE
367: {
1.16 otto 368: int n = node(prologue, $8, epilogue,
1.1 otto 369: cs("0"), numnode(nesting),
370: cs("Q"), END_NODE);
371: emit_macro($1, n);
372: reset_macro_char = macro_char;
373: nesting = 0;
374: breaksp = 0;
375: }
376: ;
377:
378: function_header : DEFINE LETTER LPAR
379: {
1.20 otto 380: $$ = function_node($2);
381: free($2);
1.1 otto 382: prologue = cs("");
383: epilogue = cs("");
384: nesting = 1;
385: breaksp = 0;
386: breakstack[breaksp] = 0;
387: }
1.11 otto 388: ;
1.1 otto 389:
1.16 otto 390: opt_newline : /* empty */
391: | NEWLINE
392: ;
393:
1.1 otto 394: opt_parameter_list
395: : /* empty */
396: | parameter_list
397: ;
398:
399:
400: parameter_list : LETTER
401: {
1.20 otto 402: add_par(letter_node($1));
403: free($1);
1.1 otto 404: }
405: | LETTER LBRACKET RBRACKET
406: {
1.20 otto 407: add_par(array_node($1));
408: free($1);
1.1 otto 409: }
410: | parameter_list COMMA LETTER
411: {
1.20 otto 412: add_par(letter_node($3));
413: free($3);
1.1 otto 414: }
415: | parameter_list COMMA LETTER LBRACKET RBRACKET
416: {
1.20 otto 417: add_par(array_node($3));
418: free($3);
1.1 otto 419: }
420: ;
421:
422:
423:
424: opt_auto_define_list
425: : /* empty */
426: | AUTO define_list NEWLINE
427: | AUTO define_list SEMICOLON
428: ;
429:
430:
431: define_list : LETTER
432: {
1.20 otto 433: add_local(letter_node($1));
434: free($1);
1.1 otto 435: }
436: | LETTER LBRACKET RBRACKET
437: {
1.20 otto 438: add_local(array_node($1));
439: free($1);
1.1 otto 440: }
441: | define_list COMMA LETTER
442: {
1.20 otto 443: add_local(letter_node($3));
444: free($3);
1.1 otto 445: }
446: | define_list COMMA LETTER LBRACKET RBRACKET
447: {
1.20 otto 448: add_local(array_node($3));
449: free($3);
1.1 otto 450: }
451: ;
452:
453:
454: opt_argument_list
455: : /* empty */
456: {
457: $$ = cs("");
458: }
459: | argument_list
460: ;
461:
462:
463: argument_list : expression
464: | argument_list COMMA expression
465: {
466: $$ = node($1, $3, END_NODE);
467: }
468: | argument_list COMMA LETTER LBRACKET RBRACKET
469: {
1.20 otto 470: $$ = node($1, cs("l"), array_node($3),
1.3 deraadt 471: END_NODE);
1.20 otto 472: free($3);
1.1 otto 473: }
474: ;
475:
1.13 otto 476: opt_relational_expression
477: : /* empty */
478: {
479: $$ = cs(" 0 0=");
480: }
481: | relational_expression
482: ;
1.1 otto 483:
484: relational_expression
1.19 otto 485: : expression EQUALS expression
1.1 otto 486: {
487: $$ = node($1, $3, cs("="), END_NODE);
488: }
489: | expression UNEQUALS expression
490: {
491: $$ = node($1, $3, cs("!="), END_NODE);
492: }
493: | expression LESS expression
494: {
495: $$ = node($1, $3, cs(">"), END_NODE);
496: }
497: | expression LESS_EQ expression
498: {
499: $$ = node($1, $3, cs("!<"), END_NODE);
500: }
501: | expression GREATER expression
502: {
503: $$ = node($1, $3, cs("<"), END_NODE);
504: }
505: | expression GREATER_EQ expression
506: {
507: $$ = node($1, $3, cs("!>"), END_NODE);
508: }
1.19 otto 509: | expression
510: {
511: $$ = node($1, cs(" 0!="), END_NODE);
512: }
1.1 otto 513: ;
514:
515:
516: return_expression
517: : /* empty */
518: {
519: $$ = node(cs("0"), epilogue,
520: numnode(nesting), cs("Q"), END_NODE);
521: }
522: | expression
523: {
524: $$ = node($1, epilogue,
1.16 otto 525: numnode(nesting), cs("Q"), END_NODE);
526: }
527: | LPAR RPAR
528: {
529: $$ = node(cs("0"), epilogue,
1.1 otto 530: numnode(nesting), cs("Q"), END_NODE);
531: }
532: ;
533:
1.13 otto 534:
535: opt_expression : /* empty */
536: {
537: $$ = cs(" 0");
538: }
539: | expression
540: ;
1.1 otto 541:
542: expression : named_expression
543: {
544: $$ = node($1.load, END_NODE);
1.9 otto 545: }
546: | DOT {
547: $$ = node(cs("l."), END_NODE);
1.1 otto 548: }
549: | NUMBER
550: {
551: $$ = node(cs(" "), as($1), END_NODE);
552: }
553: | LPAR expression RPAR
554: {
555: $$ = $2;
556: }
557: | LETTER LPAR opt_argument_list RPAR
558: {
559: $$ = node($3, cs("l"),
1.20 otto 560: function_node($1), cs("x"),
1.1 otto 561: END_NODE);
1.20 otto 562: free($1);
1.1 otto 563: }
564: | MINUS expression %prec UMINUS
565: {
566: $$ = node(cs(" 0"), $2, cs("-"),
567: END_NODE);
568: }
569: | expression PLUS expression
570: {
571: $$ = node($1, $3, cs("+"), END_NODE);
572: }
573: | expression MINUS expression
574: {
575: $$ = node($1, $3, cs("-"), END_NODE);
576: }
577: | expression MULTIPLY expression
578: {
579: $$ = node($1, $3, cs("*"), END_NODE);
580: }
581: | expression DIVIDE expression
582: {
583: $$ = node($1, $3, cs("/"), END_NODE);
584: }
585: | expression REMAINDER expression
586: {
587: $$ = node($1, $3, cs("%"), END_NODE);
588: }
589: | expression EXPONENT expression
590: {
591: $$ = node($1, $3, cs("^"), END_NODE);
592: }
593: | INCR named_expression
594: {
595: $$ = node($2.load, cs("1+d"), $2.store,
596: END_NODE);
597: }
598: | DECR named_expression
599: {
600: $$ = node($2.load, cs("1-d"),
601: $2.store, END_NODE);
602: }
603: | named_expression INCR
604: {
605: $$ = node($1.load, cs("d1+"),
606: $1.store, END_NODE);
607: }
608: | named_expression DECR
609: {
610: $$ = node($1.load, cs("d1-"),
611: $1.store, END_NODE);
612: }
613: | named_expression ASSIGN_OP expression
614: {
1.11 otto 615: if ($2[0] == '\0')
616: $$ = node($3, cs($2), cs("d"), $1.store,
617: END_NODE);
618: else
619: $$ = node($1.load, $3, cs($2), cs("d"),
620: $1.store, END_NODE);
1.1 otto 621: }
622: | LENGTH LPAR expression RPAR
623: {
624: $$ = node($3, cs("Z"), END_NODE);
625: }
626: | SQRT LPAR expression RPAR
627: {
628: $$ = node($3, cs("v"), END_NODE);
629: }
630: | SCALE LPAR expression RPAR
631: {
632: $$ = node($3, cs("X"), END_NODE);
1.19 otto 633: }
634: | BOOL_NOT expression
635: {
636: $$ = node($2, cs("N"), END_NODE);
637: }
638: | expression BOOL_AND alloc_macro pop_nesting expression
639: {
640: ssize_t n = node(cs("R"), $5, END_NODE);
641: emit_macro($3, n);
642: $$ = node($1, cs("d0!="), $3, END_NODE);
643: }
644: | expression BOOL_OR alloc_macro pop_nesting expression
645: {
646: ssize_t n = node(cs("R"), $5, END_NODE);
647: emit_macro($3, n);
648: $$ = node($1, cs("d0="), $3, END_NODE);
649: }
650: | expression EQUALS expression
651: {
652: $$ = node($1, $3, cs("G"), END_NODE);
653: }
654: | expression UNEQUALS expression
655: {
656: $$ = node($1, $3, cs("GN"), END_NODE);
657: }
658: | expression LESS expression
659: {
660: $$ = node($3, $1, cs("("), END_NODE);
661: }
662: | expression LESS_EQ expression
663: {
664: $$ = node($3, $1, cs("{"), END_NODE);
665: }
666: | expression GREATER expression
667: {
668: $$ = node($1, $3, cs("("), END_NODE);
669: }
670: | expression GREATER_EQ expression
671: {
672: $$ = node($1, $3, cs("{"), END_NODE);
1.1 otto 673: }
674: ;
675:
676: named_expression
677: : LETTER
678: {
1.20 otto 679: $$.load = node(cs("l"), letter_node($1),
1.1 otto 680: END_NODE);
1.20 otto 681: $$.store = node(cs("s"), letter_node($1),
1.1 otto 682: END_NODE);
1.20 otto 683: free($1);
1.1 otto 684: }
685: | LETTER LBRACKET expression RBRACKET
686: {
687: $$.load = node($3, cs(";"),
1.20 otto 688: array_node($1), END_NODE);
1.1 otto 689: $$.store = node($3, cs(":"),
1.20 otto 690: array_node($1), END_NODE);
691: free($1);
1.1 otto 692: }
693: | SCALE
694: {
695: $$.load = cs("K");
696: $$.store = cs("k");
697: }
698: | IBASE
699: {
700: $$.load = cs("I");
701: $$.store = cs("i");
702: }
703: | OBASE
704: {
705: $$.load = cs("O");
706: $$.store = cs("o");
707: }
708: ;
1.15 otto 709:
710: print_expression_list
711: : print_expression
712: | print_expression_list COMMA print_expression
713: {
714: $$ = node($1, $3, END_NODE);
715: }
716:
717: print_expression
718: : expression
719: {
1.18 otto 720: $$ = node($1, cs("ds.n"), END_NODE);
1.15 otto 721: }
722: | STRING
723: {
724: char *p = escape($1);
1.18 otto 725: $$ = node(cs("["), as(p), cs("]n"), END_NODE);
1.15 otto 726: free(p);
727: }
1.1 otto 728: %%
729:
730:
731: static void
732: grow(void)
733: {
734: struct tree *p;
735: int newsize;
736:
737: if (current == instr_sz) {
738: newsize = instr_sz * 2 + 1;
739: p = realloc(instructions, newsize * sizeof(*p));
740: if (p == NULL) {
741: free(instructions);
1.12 otto 742: err(1, NULL);
1.1 otto 743: }
744: instructions = p;
745: instr_sz = newsize;
746: }
747: }
748:
1.7 otto 749: static ssize_t
1.1 otto 750: cs(const char *str)
751: {
752: grow();
753: instructions[current].index = CONST_STRING;
754: instructions[current].u.cstr = str;
755: return current++;
756: }
757:
1.7 otto 758: static ssize_t
1.1 otto 759: as(const char *str)
760: {
761: grow();
762: instructions[current].index = ALLOC_STRING;
763: instructions[current].u.astr = strdup(str);
1.2 otto 764: if (instructions[current].u.astr == NULL)
1.12 otto 765: err(1, NULL);
1.1 otto 766: return current++;
767: }
768:
769: static ssize_t
770: node(ssize_t arg, ...)
771: {
772: va_list ap;
773: ssize_t ret;
774:
775: va_start(ap, arg);
776:
777: ret = current;
778: grow();
779: instructions[current++].index = arg;
780:
781: do {
782: arg = va_arg(ap, ssize_t);
783: grow();
784: instructions[current++].index = arg;
785: } while (arg != END_NODE);
786:
787: va_end(ap);
788: return ret;
789: }
790:
791: static void
792: emit(ssize_t i)
793: {
794: if (instructions[i].index >= 0)
795: while (instructions[i].index != END_NODE)
796: emit(instructions[i++].index);
797: else
798: fputs(instructions[i].u.cstr, stdout);
799: }
800:
801: static void
802: emit_macro(int node, ssize_t code)
803: {
804: putchar('[');
805: emit(code);
806: printf("]s%s\n", instructions[node].u.cstr);
807: nesting--;
808: }
809:
810: static void
811: free_tree(void)
812: {
813: size_t i;
814:
815: for (i = 0; i < current; i++)
816: if (instructions[i].index == ALLOC_STRING)
817: free(instructions[i].u.astr);
818: current = 0;
819: }
820:
821: static ssize_t
822: numnode(int num)
823: {
824: const char *p;
825:
826: if (num < 10)
827: p = str_table['0' + num];
828: else if (num < 16)
829: p = str_table['A' - 10 + num];
830: else
1.20 otto 831: errx(1, "internal error: break num > 15");
1.1 otto 832: return node(cs(" "), cs(p), END_NODE);
833: }
834:
1.20 otto 835:
836: static ssize_t
837: lookup(char * str, size_t len, char type)
838: {
839: ENTRY entry, *found;
840: u_short num;
841: u_char *p;
842:
843: /* The scanner allocated an extra byte already */
844: if (str[len-1] != type) {
845: str[len] = type;
846: str[len+1] = '\0';
847: }
848: entry.key = str;
849: found = hsearch(entry, FIND);
850: if (found == NULL) {
851: if (var_count == MAX_VARIABLES)
852: errx(1, "too many variables");
853: p = malloc(4);
854: if (p == NULL)
855: err(1, NULL);
856: num = var_count++;
857: p[0] = 255;
858: p[1] = ENCODE(num / VAR_BASE + 1);
859: p[2] = ENCODE(num % VAR_BASE + 1);
860: p[3] = '\0';
861:
862: entry.data = p;
863: entry.key = strdup(str);
864: if (entry.key == NULL)
865: err(1, NULL);
866: found = hsearch(entry, ENTER);
867: if (found == NULL)
868: err(1, NULL);
869: }
870: return cs(found->data);
871: }
872:
873: static ssize_t
874: letter_node(char *str)
875: {
876: size_t len;
877:
878: len = strlen(str);
879: if (len == 1 && str[0] != '_')
880: return cs(str_table[(int)str[0]]);
881: else
882: return lookup(str, len, 'L');
883: }
884:
885: static ssize_t
886: array_node(char *str)
887: {
888: size_t len;
889:
890: len = strlen(str);
891: if (len == 1 && str[0] != '_')
892: return cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR]);
893: else
894: return lookup(str, len, 'A');
895: }
896:
897: static ssize_t
898: function_node(char *str)
899: {
900: size_t len;
901:
902: len = strlen(str);
903: if (len == 1 && str[0] != '_')
904: return cs(str_table[(int)str[0] - 'a' + FUNC_CHAR]);
905: else
906: return lookup(str, len, 'F');
907: }
908:
1.1 otto 909: static void
910: add_par(ssize_t n)
911: {
912: prologue = node(cs("S"), n, prologue, END_NODE);
913: epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
914: }
915:
916: static void
917: add_local(ssize_t n)
918: {
919: prologue = node(cs("0S"), n, prologue, END_NODE);
920: epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
921: }
922:
923: int
924: yywrap(void)
925: {
926: if (optind < sargc) {
927: filename = sargv[optind++];
928: yyin = fopen(filename, "r");
1.8 otto 929: lineno = 1;
1.1 otto 930: if (yyin == NULL)
931: err(1, "cannot open %s", filename);
932: return 0;
1.6 deraadt 933: } else if (optind == sargc) {
1.1 otto 934: optind++;
935: yyin = stdin;
1.8 otto 936: lineno = 1;
1.1 otto 937: filename = "stdin";
938: return 0;
939: }
940: return 1;
941: }
942:
943: void
944: yyerror(char *s)
945: {
1.10 otto 946: char *str, *p;
947:
948: if (isspace(yytext[0]) || !isprint(yytext[0]))
949: asprintf(&str, "%s: %s:%d: %s: ascii char 0x%x unexpected",
950: __progname, filename, lineno, s, yytext[0]);
1.1 otto 951: else
1.10 otto 952: asprintf(&str, "%s: %s:%d: %s: %s unexpected",
1.8 otto 953: __progname, filename, lineno, s, yytext);
1.10 otto 954: if (str == NULL)
1.12 otto 955: err(1, NULL);
1.10 otto 956:
957: fputs("c[", stdout);
958: for (p = str; *p != '\0'; p++) {
959: if (*p == '[' || *p == ']' || *p =='\\')
960: putchar('\\');
961: putchar(*p);
962: }
963: fputs("]pc\n", stdout);
964: free(str);
1.1 otto 965: }
966:
1.8 otto 967: void
1.1 otto 968: fatal(const char *s)
969: {
970: errx(1, "%s:%d: %s", filename, lineno, s);
971: }
972:
973: static void
974: warning(const char *s)
975: {
976: warnx("%s:%d: %s", filename, lineno, s);
977: }
978:
979: static void
980: init(void)
981: {
982: int i;
983:
984: for (i = 0; i < UCHAR_MAX; i++) {
985: str_table[i][0] = i;
986: str_table[i][1] = '\0';
987: }
1.20 otto 988: if (hcreate(1 << 16) == 0)
989: err(1, NULL);
1.1 otto 990: }
991:
992:
993: static __dead void
994: usage(void)
995: {
1.4 deraadt 996: fprintf(stderr, "%s: usage: [-cl] [file ...]\n", __progname);
1.1 otto 997: exit(1);
998: }
999:
1.15 otto 1000: static char *
1001: escape(const char *str)
1002: {
1003: char *ret, *p;
1004:
1005: ret = malloc(strlen(str) + 1);
1006: if (ret == NULL)
1007: err(1, NULL);
1008:
1009: p = ret;
1010: while (*str != '\0') {
1011: /*
1012: * We get _escaped_ strings here. Single backslashes are
1013: * already converted to double backslashes
1014: */
1015: if (*str == '\\') {
1016: if (*++str == '\\') {
1017: switch (*++str) {
1018: case 'a':
1019: *p++ = '\a';
1020: break;
1021: case 'b':
1022: *p++ = '\b';
1023: break;
1024: case 'f':
1025: *p++ = '\f';
1026: break;
1027: case 'n':
1028: *p++ = '\n';
1029: break;
1030: case 'q':
1031: *p++ = '"';
1032: break;
1033: case 'r':
1034: *p++ = '\r';
1035: break;
1036: case 't':
1037: *p++ = '\t';
1038: break;
1039: case '\\':
1040: *p++ = '\\';
1041: break;
1042: }
1043: str++;
1044: } else {
1045: *p++ = '\\';
1046: *p++ = *str++;
1047: }
1048: } else
1049: *p++ = *str++;
1050: }
1051: *p = '\0';
1052: return ret;
1053: }
1.1 otto 1054:
1055: int
1056: main(int argc, char *argv[])
1057: {
1058: int ch, ret;
1059: int p[2];
1060:
1061: init();
1062: setlinebuf(stdout);
1063:
1064: /* The d debug option is 4.4 BSD dc(1) compatible */
1065: while ((ch = getopt(argc, argv, "cdl")) != -1) {
1066: switch (ch) {
1067: case 'c':
1068: case 'd':
1069: do_fork = false;
1070: break;
1071: case 'l':
1072: argv[1] = _PATH_LIBB;
1073: optind = 1;
1074: break;
1075: default:
1.5 deraadt 1076: usage();
1.1 otto 1077: }
1078: }
1079:
1080: sargc = argc;
1081: sargv = argv;
1082:
1083: if (do_fork) {
1084: if (pipe(p) == -1)
1085: err(1, "cannot create pipe");
1086: ret = fork();
1087: if (ret == -1)
1088: err(1, "cannot fork");
1089: else if (ret == 0) {
1090: close(STDOUT_FILENO);
1091: dup(p[1]);
1092: close(p[0]);
1093: close(p[1]);
1.6 deraadt 1094: } else {
1.1 otto 1095: close(STDIN_FILENO);
1096: dup(p[0]);
1097: close(p[0]);
1098: close(p[1]);
1.20 otto 1099: execl(_PATH_DC, "dc", "-x", (char *)NULL);
1.1 otto 1100: err(1, "cannot find dc");
1101: }
1102: }
1103: signal(SIGINT, abort_line);
1104: yywrap();
1105: return yyparse();
1106: }