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