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