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