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