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