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