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