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