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