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