[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.41

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