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