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