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