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