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

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