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