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