]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/bc/bc.y
Merge bmake-20230909
[FreeBSD/FreeBSD.git] / usr.bin / bc / bc.y
1 %{
2 /*      $OpenBSD: bc.y,v 1.46 2014/10/14 15:35:18 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 #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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1002 fatal(const char *s)
1003 {
1004
1005         errx(1, "%s:%d: %s", filename, lineno, s);
1006 }
1007
1008 static void
1009 warning(const char *s)
1010 {
1011
1012         warnx("%s:%d: %s", filename, lineno, s);
1013 }
1014
1015 static 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
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 *
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
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 *
1117 dummy_prompt(void)
1118 {
1119
1120         return ("");
1121 }
1122
1123 int
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 }