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