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