xref: /trueos/usr.bin/bc/bc.y (revision ebef83dbd2b82b4ddf471e1d2b423eef86ccf414)
1 %{
2 /*	$OpenBSD: bc.y,v 1.44 2013/11/20 21:33:54 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);
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);
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 = realloc(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
cs(const char * str)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
as(const char * str)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
node(ssize_t arg,...)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
emit(ssize_t i)829 emit(ssize_t i)
830 {
831 
832 	if (instructions[i].index >= 0)
833 		while (instructions[i].index != END_NODE)
834 			emit(instructions[i++].index);
835 	else
836 		fputs(instructions[i].u.cstr, stdout);
837 }
838 
839 static void
emit_macro(int nodeidx,ssize_t code)840 emit_macro(int nodeidx, ssize_t code)
841 {
842 
843 	putchar('[');
844 	emit(code);
845 	printf("]s%s\n", instructions[nodeidx].u.cstr);
846 	nesting--;
847 }
848 
849 static void
free_tree(void)850 free_tree(void)
851 {
852 	ssize_t	i;
853 
854 	for (i = 0; i < current; i++)
855 		if (instructions[i].index == ALLOC_STRING)
856 			free(instructions[i].u.astr);
857 	current = 0;
858 }
859 
860 static ssize_t
numnode(int num)861 numnode(int num)
862 {
863 	const char *p;
864 
865 	if (num < 10)
866 		p = str_table['0' + num];
867 	else if (num < 16)
868 		p = str_table['A' - 10 + num];
869 	else
870 		errx(1, "internal error: break num > 15");
871 	return (node(cs(" "), cs(p), END_NODE));
872 }
873 
874 
875 static ssize_t
lookup(char * str,size_t len,char type)876 lookup(char * str, size_t len, char type)
877 {
878 	ENTRY entry, *found;
879 	u_char *p;
880 	u_short num;
881 
882 	/* The scanner allocated an extra byte already */
883 	if (str[len-1] != type) {
884 		str[len] = type;
885 		str[len+1] = '\0';
886 	}
887 	entry.key = str;
888 	found = hsearch(entry, FIND);
889 	if (found == NULL) {
890 		if (var_count == MAX_VARIABLES)
891 			errx(1, "too many variables");
892 		p = malloc(4);
893 		if (p == NULL)
894 			err(1, NULL);
895 		num = var_count++;
896 		p[0] = 255;
897 		p[1] = ENCODE(num / VAR_BASE + 1);
898 		p[2] = ENCODE(num % VAR_BASE + 1);
899 		p[3] = '\0';
900 
901 		entry.data = (char *)p;
902 		entry.key = strdup(str);
903 		if (entry.key == NULL)
904 			err(1, NULL);
905 		found = hsearch(entry, ENTER);
906 		if (found == NULL)
907 			err(1, NULL);
908 	}
909 	return (cs(found->data));
910 }
911 
912 static ssize_t
letter_node(char * str)913 letter_node(char *str)
914 {
915 	size_t len;
916 
917 	len = strlen(str);
918 	if (len == 1 && str[0] != '_')
919 		return (cs(str_table[(int)str[0]]));
920 	else
921 		return (lookup(str, len, 'L'));
922 }
923 
924 static ssize_t
array_node(char * str)925 array_node(char *str)
926 {
927 	size_t len;
928 
929 	len = strlen(str);
930 	if (len == 1 && str[0] != '_')
931 		return (cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR]));
932 	else
933 		return (lookup(str, len, 'A'));
934 }
935 
936 static ssize_t
function_node(char * str)937 function_node(char *str)
938 {
939 	size_t len;
940 
941 	len = strlen(str);
942 	if (len == 1 && str[0] != '_')
943 		return (cs(str_table[(int)str[0] - 'a' + FUNC_CHAR]));
944 	else
945 		return (lookup(str, len, 'F'));
946 }
947 
948 static void
add_par(ssize_t n)949 add_par(ssize_t n)
950 {
951 
952 	prologue = node(cs("S"), n, prologue, END_NODE);
953 	epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
954 }
955 
956 static void
add_local(ssize_t n)957 add_local(ssize_t n)
958 {
959 
960 	prologue = node(cs("0S"), n, prologue, END_NODE);
961 	epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
962 }
963 
964 void
yyerror(const char * s)965 yyerror(const char *s)
966 {
967 	char *p, *str;
968 	int n;
969 
970 	if (yyin != NULL && feof(yyin))
971 		n = asprintf(&str, "%s: %s:%d: %s: unexpected EOF",
972 		    __progname, filename, lineno, s);
973 	else if (yytext[0] == '\n')
974 		n = asprintf(&str,
975 		    "%s: %s:%d: %s: newline unexpected",
976 		    __progname, filename, lineno, s);
977 	else if (isspace((unsigned char)yytext[0]) ||
978 	    !isprint((unsigned char)yytext[0]))
979 		n = asprintf(&str,
980 		    "%s: %s:%d: %s: ascii char 0x%02x unexpected",
981 		    __progname, filename, lineno, s, yytext[0]);
982 	else
983 		n = asprintf(&str, "%s: %s:%d: %s: %s unexpected",
984 		    __progname, filename, lineno, s, yytext);
985 	if (n == -1)
986 		err(1, NULL);
987 
988 	fputs("c[", stdout);
989 	for (p = str; *p != '\0'; p++) {
990 		if (*p == '[' || *p == ']' || *p =='\\')
991 			putchar('\\');
992 		putchar(*p);
993 	}
994 	fputs("]pc\n", stdout);
995 	free(str);
996 }
997 
998 void
fatal(const char * s)999 fatal(const char *s)
1000 {
1001 
1002 	errx(1, "%s:%d: %s", filename, lineno, s);
1003 }
1004 
1005 static void
warning(const char * s)1006 warning(const char *s)
1007 {
1008 
1009 	warnx("%s:%d: %s", filename, lineno, s);
1010 }
1011 
1012 static void
init(void)1013 init(void)
1014 {
1015 	unsigned int i;
1016 
1017 	for (i = 0; i < UCHAR_MAX; i++) {
1018 		str_table[i][0] = i;
1019 		str_table[i][1] = '\0';
1020 	}
1021 	if (hcreate(1 << 16) == 0)
1022 		err(1, NULL);
1023 }
1024 
1025 
1026 static void
usage(void)1027 usage(void)
1028 {
1029 
1030 	fprintf(stderr, "usage: %s [-chlv] [-e expression] [file ...]\n",
1031 	    __progname);
1032 	exit(1);
1033 }
1034 
1035 static char *
escape(const char * str)1036 escape(const char *str)
1037 {
1038 	char *p, *ret;
1039 
1040 	ret = malloc(strlen(str) + 1);
1041 	if (ret == NULL)
1042 		err(1, NULL);
1043 
1044 	p = ret;
1045 	while (*str != '\0') {
1046 		/*
1047 		 * We get _escaped_ strings here. Single backslashes are
1048 		 * already converted to double backslashes
1049 		 */
1050 		if (*str == '\\') {
1051 			if (*++str == '\\') {
1052 				switch (*++str) {
1053 				case 'a':
1054 					*p++ = '\a';
1055 					break;
1056 				case 'b':
1057 					*p++ = '\b';
1058 					break;
1059 				case 'f':
1060 					*p++ = '\f';
1061 					break;
1062 				case 'n':
1063 					*p++ = '\n';
1064 					break;
1065 				case 'q':
1066 					*p++ = '"';
1067 					break;
1068 				case 'r':
1069 					*p++ = '\r';
1070 					break;
1071 				case 't':
1072 					*p++ = '\t';
1073 					break;
1074 				case '\\':
1075 					*p++ = '\\';
1076 					break;
1077 				}
1078 				str++;
1079 			} else {
1080 				*p++ = '\\';
1081 				*p++ = *str++;
1082 			}
1083 		} else
1084 			*p++ = *str++;
1085 	}
1086 	*p = '\0';
1087 	return (ret);
1088 }
1089 
1090 /* ARGSUSED */
1091 static void
sigchld(int signo __unused)1092 sigchld(int signo __unused)
1093 {
1094 	pid_t pid;
1095 	int status, save_errno = errno;
1096 
1097 	for (;;) {
1098 		pid = waitpid(dc, &status, WCONTINUED | WNOHANG);
1099 		if (pid == -1) {
1100 			if (errno == EINTR)
1101 				continue;
1102 			_exit(0);
1103 		} else if (pid == 0)
1104 			break;
1105 		if (WIFEXITED(status) || WIFSIGNALED(status))
1106 			_exit(0);
1107 		else
1108 			break;
1109 	}
1110 	errno = save_errno;
1111 }
1112 
1113 static const char *
dummy_prompt(void)1114 dummy_prompt(void)
1115 {
1116 
1117         return ("");
1118 }
1119 
1120 int
main(int argc,char * argv[])1121 main(int argc, char *argv[])
1122 {
1123 	char *q;
1124 	int p[2];
1125 	int ch, i;
1126 
1127 	init();
1128 	setlinebuf(stdout);
1129 
1130 	sargv = malloc(argc * sizeof(char *));
1131 	if (sargv == NULL)
1132 		err(1, NULL);
1133 
1134 	if ((cmdexpr = strdup("")) == NULL)
1135 		err(1, NULL);
1136 	/* The d debug option is 4.4 BSD bc(1) compatible */
1137 	while ((ch = getopt_long(argc, argv, "cde:hlqv",
1138 	   long_options, NULL)) != -1) {
1139 		switch (ch) {
1140 		case 'c':
1141 		case 'd':
1142 			do_fork = false;
1143 			break;
1144 		case 'e':
1145 			q = cmdexpr;
1146 			if (asprintf(&cmdexpr, "%s%s\n", cmdexpr, optarg) == -1)
1147 				err(1, NULL);
1148 			free(q);
1149 			break;
1150 		case 'h':
1151 			usage();
1152 			break;
1153 		case 'l':
1154 			sargv[sargc++] = _PATH_LIBB;
1155 			break;
1156 		case 'q':
1157 			/* compatibility option */
1158 			break;
1159 		case 'v':
1160 			fprintf(stderr, "%s (BSD bc) %s\n", __progname, BC_VER);
1161 			exit(0);
1162 			break;
1163 		default:
1164 			usage();
1165 		}
1166 	}
1167 
1168 	argc -= optind;
1169 	argv += optind;
1170 
1171 	interactive = isatty(STDIN_FILENO);
1172 	for (i = 0; i < argc; i++)
1173 		sargv[sargc++] = argv[i];
1174 
1175 	if (do_fork) {
1176 		if (pipe(p) == -1)
1177 			err(1, "cannot create pipe");
1178 		dc = fork();
1179 		if (dc == -1)
1180 			err(1, "cannot fork");
1181 		else if (dc != 0) {
1182 			signal(SIGCHLD, sigchld);
1183 			close(STDOUT_FILENO);
1184 			dup(p[1]);
1185 			close(p[0]);
1186 			close(p[1]);
1187 		} else {
1188 			close(STDIN_FILENO);
1189 			dup(p[0]);
1190 			close(p[0]);
1191 			close(p[1]);
1192 			execl(_PATH_DC, "dc", "-x", (char *)NULL);
1193 			err(1, "cannot find dc");
1194 		}
1195 	}
1196 	if (interactive) {
1197 		gettty(&ttysaved);
1198 		el = el_init("bc", stdin, stderr, stderr);
1199 		hist = history_init();
1200 		history(hist, &he, H_SETSIZE, 100);
1201 		el_set(el, EL_HIST, history, hist);
1202 		el_set(el, EL_EDITOR, "emacs");
1203 		el_set(el, EL_SIGNAL, 1);
1204 		el_set(el, EL_PROMPT, dummy_prompt);
1205 		el_set(el, EL_ADDFN, "bc_eof", "", bc_eof);
1206 		el_set(el, EL_BIND, "^D", "bc_eof", NULL);
1207 		el_source(el, NULL);
1208 	}
1209 	yywrap();
1210 	return (yyparse());
1211 }
1212