[BACK]Return to bc.y CVS log [TXT][DIR] Up to [local] / src / usr.bin / bc

Annotation of src/usr.bin/bc/bc.y, Revision 1.53

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