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

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