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