Javascript函数声明bison语法减少/减少错误

时间:2016-03-07 18:10:38

标签: javascript bison reduce-reduce-conflict

我实现了一个javascript解释器,我在使用bison减少/减少函数声明和函数表达式的语法冲突方面遇到了麻烦。我不是所有与野牛有过的经历,我可以使用一些帮助来理解该做什么。我已经粘贴在野牛输入文件的一个子集下面,用于说明问题:

%define api.pure full

%{
#define YY_DECL int yylex \
    (YYSTYPE * yylval_param, yyscan_t yyscanner, parseData *pd)
%}

%union {  // yylval
    uint32_t slot;
    int64_t i;
    double d;
}

%{
void yyerror( void *scanner, parseData *pd, char *s, ... );
%}

%lex-param      { void *scanner } { parseData *pd }
%parse-param    { void *scanner } { parseData *pd }

%token <i>      INT
%token <d>      NUMBER
%token <slot>   STRING 
%token <slot>   NAME
%token          EOS
%token          FCN
%token          LPAR
%token          RPAR
%token          SEMI
%token          COMMA
%token          LBRACE
%token          RBRACE

%type <slot>    expr exprlist
%type <slot>    stmt
%type <slot>    paramlist
%type <slot>    funcdecl funcexpr
%type <slot>    fname
%type <slot>    symbol
%type <slot>    pgmlist

%start script
%%

script:
        EOS
        {
            pd->beginning = 0;
            YYACCEPT;
        }
    |   pgmlist
        {
            pd->beginning = $1;
            YYACCEPT;
        }
    ;

pgmlist:
        %empty
        {
            $$ = newNode(pd, node_endlist, sizeof(Node));
        }
    |   funcdecl pgmlist
        {
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    |   stmt pgmlist
        {
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;

funcdecl:
        FCN symbol LPAR paramlist RPAR LBRACE pgmlist RBRACE
        {
            $$ = newNode(pd, node_fcndecl, sizeof(fcnDeclNode));
            fcnDeclNode *fn = (fcnDeclNode *)(pd->table + $$);
            memset (fn, 0, sizeof(fcnDeclNode));
            fn->name = $2;
            fn->params = $4;
            fn->body = $7;
        }
   ;

funcexpr:
        FCN fname LPAR paramlist RPAR LBRACE pgmlist RBRACE
        {
            $$ = newNode(pd, node_fcndecl, sizeof(fcnDeclNode));
            fcnDeclNode *fn = (fcnDeclNode *)(pd->table + $$);
            memset (fn, 0, sizeof(fcnDeclNode));
            fn->name = $2;
            fn->params = $4;
            fn->body = $7;
        }
   ;

fname:
        %empty
        {
            $$ = 0;
        }
    |   NAME
        {
            fcnDeclNode *fn = (fcnDeclNode *)(pd->table + $1);
            fn->hdr->flag |= flag_decl | flag_lval;
            $$ = $1;
        }
    ;

stmt:  
        exprlist SEMI
        {
            $$ = $1;
        }
    ;

symbol:
        NAME
        {
            $$ = newNode(pd, node_var, sizeof(symNode));
            symNode *sn = (symNode *)(pd->table + $$);
            sn->name = $1;
        }
        ;

expr:   
        NUMBER
        {
            $$ = newNode(pd, node_num, sizeof(numNode));
            numNode *nn = (numNode *)(pd->table + $$);
            nn->value = $1;
        }
    |   STRING
        {
            $$ = $1;
        }
    |   funcexpr
        {
            $$ = $1;
        }
    ;

exprlist:     // non-empty
        expr 
        {
            newNode(pd, node_endlist, sizeof(Node));
        }
    |   expr COMMA exprlist
        {
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;

paramlist:
        %empty
        {
            $$ = newNode(pd, node_endlist, sizeof(Node));
        }
    |   symbol 
        {
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_decl;
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    |   symbol COMMA paramlist
        {
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_decl;
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;
%%

void yyerror( void *scanner, parseData *pd, char *s, ... )
{
    fprintf(stderr, "yyerror: %s\n", s);
}

1 个答案:

答案 0 :(得分:2)

我通过认识到函数表达式只能用作赋值,声明值,参数,数组元素或对象值来解决问题。我放弃了立即调用的情况。它本身并不需要被引入一般表达式。

我以前用同样的方法解决了对象文字的制作。这是我实施的javascript子集的完整语法:

%define api.pure full
%error-verbose

%{
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "jsdb.h"

#define YY_DECL int yylex \
    (YYSTYPE * yylval_param, yyscan_t yyscanner, parseData *pd)
%}

%union {  // yylval
    uint32_t slot;
    int64_t i;
    double d;
}

%{
#include "jsdb.lex.h"

static bool debug = true;

void yyerror( void *scanner, parseData *pd, char *s, ... );
%}

%lex-param      { void *scanner } { parseData *pd }
%parse-param    { void *scanner } { parseData *pd }

%token <i>      INT
%token <d>      NUMBER
%token <slot>   STRING 
%token <slot>   NAME
%token          EOS
%token          IF
%token          ELSE
%token          WHILE
%token          DO
%token          FOR
%token          FCN
%token          VAR
%token          RETURN
%token          CONTINUE
%token          BREAK
%token          AMPER
%token          LPAR
%token          RPAR
%token          SEMI
%token          COMMA
%token          LBRACE
%token          RBRACE
%token          LBRACK
%token          RBRACK
%token          COLON
%token          DOT
%right          RPAR ELSE
%precedence     PLUS_ASSIGN MINUS_ASSIGN ASSIGN
%left           LT LE EQ NEQ GT GE
%left           PLUS MINUS
%left           TIMES DIV
%precedence     UMINUS
%precedence     LPAR
%precedence     LBRACK
%precedence     DOT

%type <slot>    expr exprlist
%type <slot>    decl decllist
%type <slot>    arg arglist
%type <slot>    stmt stmtlist
%type <slot>    paramlist
%type <slot>    elem elemlist
%type <slot>    lval objlit
%type <slot>    arrayelem arraylist 
%type <slot>    funcdef funcexpr
%type <slot>    fname pgmlist
%type <slot>    symbol optexpr

%start script
%%

script:
        EOS
        {
            if (debug) printf("script -> EOS\n");
            pd->beginning = 0;
            YYACCEPT;
        }
    |   pgmlist
        {
            if (debug) printf("script -> pgmlist\n");
            pd->beginning = $1;
            YYACCEPT;
        }
    ;

pgmlist: 
        %empty
        {
            if (debug) printf("pgmlist -> _empty_\n");
            $$ = newNode(pd, node_endlist, sizeof(Node));
        }
    |   stmt pgmlist 
        {
            if (debug) printf("pgmlist -> stmt pgmlist\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    |   funcdef pgmlist 
        {
            if (debug) printf("pgmlist -> funcdef pgmlist\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;

funcdef:
        FCN symbol LPAR paramlist RPAR LBRACE stmtlist RBRACE
        {
            if (debug) printf("funcdef -> symbol fname LPAR paramlist RPAR LBRACE stmtlist RBRACE\n");
            $$ = newNode(pd, node_fcnexpr, sizeof(fcnDeclNode));
            fcnDeclNode *fn = (fcnDeclNode *)(pd->table + $$);
            memset (fn, 0, sizeof(fcnDeclNode));
            fn->hdr->flag |= flag_decl;
            fn->name = $2;
            fn->params = $4;
            fn->body = $7;
        }
   ;

funcexpr:
        FCN fname LPAR paramlist RPAR LBRACE stmtlist RBRACE
        {
            if (debug) printf("funcexpr -> FCN fname LPAR paramlist RPAR LBRACE stmtlist RBRACE\n");
            $$ = newNode(pd, node_fcnexpr, sizeof(fcnDeclNode));
            fcnDeclNode *fn = (fcnDeclNode *)(pd->table + $$);
            memset (fn, 0, sizeof(fcnDeclNode));
            fn->name = $2;
            fn->params = $4;
            fn->body = $7;
        }
   ;

fname:
        %empty
        {
            if (debug) printf("fname -> _empty_\n");
            $$ = 0;
        }
    |   NAME
        {
            if (debug) printf("fname -> NAME\n");
            $$ = $1;
        }
    ;

stmt:  
        IF LPAR expr RPAR stmt
        {
            if (debug) printf("stmt -> IF LPAR expr RPAR stmt\n");
            $$ = newNode(pd, node_ifthen, sizeof(ifThenNode));
            ifThenNode *ifthen = (ifThenNode *)(pd->table + $$);
            ifthen->condexpr = $3;
            ifthen->thenstmt = $5;
            ifthen->elsestmt = 0;
        }
    |   IF LPAR expr RPAR stmt ELSE stmt
        {
            if (debug) printf("stmt -> IF LPAR expr RPAR stmt ELSE stmt\n");
            $$ = newNode(pd, node_ifthen, sizeof(ifThenNode));
            ifThenNode *ifthen = (ifThenNode *)(pd->table + $$);
            ifthen->condexpr = $3;
            ifthen->thenstmt = $5;
            ifthen->elsestmt = $7;
        }
    |   RETURN optexpr SEMI
        {
            if (debug) printf("stmt -> RETURN optexpr SEMI\n");
            $$ = newNode(pd, node_return, sizeof(exprNode));
            exprNode *en = (exprNode *)(pd->table + $$);
            en->expr = $2;
        }
    |   BREAK SEMI
        {
            if (debug) printf("stmt -> BREAK SEMI\n");
            $$ = newNode(pd, node_return, sizeof(exprNode));
            exprNode *en = (exprNode *)(pd->table + $$);
            en->hdr->flag |= flag_break;
        }
    |   CONTINUE SEMI
        {
            if (debug) printf("stmt -> CONTINUE SEMI\n");
            $$ = newNode(pd, node_return, sizeof(exprNode));
            exprNode *en = (exprNode *)(pd->table + $$);
            en->hdr->flag |= flag_continue;
        }
    |   WHILE LPAR expr RPAR stmt
        {
            if (debug) printf("stmt -> WHILE LPAR expr RPAR stmt\n");
            $$ = newNode(pd, node_while, sizeof(whileNode));
            whileNode *wn = (whileNode *)(pd->table + $$);
            wn->cond = $3;
            wn->stmt = $5;
        }
    |   DO stmt WHILE LPAR expr RPAR SEMI
        {
            if (debug) printf("stmt -> DO stmt WHILE LPAR expr RPAR SEMI\n");
            $$ = newNode(pd, node_dowhile, sizeof(whileNode));
            whileNode *wn = (whileNode *)(pd->table + $$);
            wn->cond = $5;
            wn->stmt = $2;
        }
    |   FOR LPAR expr SEMI expr SEMI expr RPAR stmt
        {
            if (debug) printf("stmt -> FOR LPAR expr SEMI expr SEMI expr RPAR stmt\n");
            $$ = newNode(pd, node_for, sizeof(forNode));
            forNode *fn = (forNode *)(pd->table + $$);
            fn->init = $3;
            fn->cond = $5;
            fn->incr = $7;
            fn->stmt = $9;
        }
    |   LBRACE stmtlist RBRACE
        {
            if (debug) printf("stmt -> LBRACE stmtlist RBRACE\n");
            $$ = $2;
        }
    |   VAR decllist SEMI
        {
            if (debug) printf("stmt -> VAR decllist SEMI\n");
            $$ = $2;
        }
    |   exprlist SEMI
        {
            if (debug) printf("stmt -> exprlist SEMI\n");
            $$ = $1;
        }
    |   SEMI
        {
            if (debug) printf("stmt -> _empty_\n");
            $$ = 0;
        }
    ;

stmtlist: 
        %empty
        {
            if (debug) printf("stmtlist -> _empty_\n");
            $$ = newNode(pd, node_endlist, sizeof(Node));
        }
    |   stmt stmtlist 
        {
            if (debug) printf("stmtlist -> stmt stmtlist\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;

symbol:
        NAME
        {
            if (debug) {
                stringNode *sn = (stringNode *)(pd->table + $1);
                printf("symbol -> NAME[%.*s]\n", sn->hdr->aux, sn->string);
            }
            $$ = newNode(pd, node_var, sizeof(symNode));
            symNode *sn = (symNode *)(pd->table + $$);
            sn->name = $1;
        }
        ;

decl:
        symbol
        {
            if (debug) printf("decl -> symbol\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_decl;
            $$ = $1;
        }
    |   symbol ASSIGN expr
        {
            if (debug) printf("decl -> symbol ASSIGN expr\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_lval | flag_decl;

            $$ = newNode(pd, node_assign, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->hdr->aux = pm_assign;
            bn->right = $3;
            bn->left = $1;
        }
    |   symbol ASSIGN funcexpr
        {
            if (debug) printf("decl -> symbol ASSIGN funcexpr\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_lval | flag_decl;

            $$ = newNode(pd, node_assign, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->hdr->aux = pm_assign;
            bn->right = $3;
            bn->left = $1;
        }
    |   symbol ASSIGN objlit
        {
            if (debug) printf("decl -> symbol ASSIGN objlit\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_lval | flag_decl;

            $$ = newNode(pd, node_assign, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->hdr->aux = pm_assign;
            bn->right = $3;
            bn->left = $1;
        }
    ;

decllist:
        decl
        {
            if (debug) printf("decllist -> decl\n");
            newNode(pd, node_endlist, sizeof(Node));

            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    |
        decl COMMA decllist
        {
            if (debug) printf("decllist -> decl COMMA decllist\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;

expr:   
        expr LT expr
        {
            if (debug) printf("expr -> expr LT expr\n");
            $$ = newNode(pd, node_lt, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   expr LE expr
        {
            if (debug) printf("expr -> expr LE expr\n");
            $$ = newNode(pd, node_le, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   expr EQ expr
        {
            if (debug) printf("expr -> expr EQ expr\n");
            $$ = newNode(pd, node_eq, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   expr NEQ expr
        {
            if (debug) printf("expr -> expr NEQ expr\n");
            $$ = newNode(pd, node_ne, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   expr GE expr
        {
            if (debug) printf("expr -> expr GE expr\n");
            $$ = newNode(pd, node_ge, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   expr GT expr
        {
            if (debug) printf("expr -> expr GT expr\n");
            $$ = newNode(pd, node_gt, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   expr PLUS expr
        {
            if (debug) printf("expr -> expr PLUS expr\n");
            $$ = newNode(pd, node_plus, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   expr MINUS expr
        {
            if (debug) printf("expr -> expr MINUS expr\n");
            $$ = newNode(pd, node_minus, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   expr TIMES expr
        {
            if (debug) printf("expr -> expr TIMES expr\n");
            $$ = newNode(pd, node_times, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   expr DIV expr
        {
            if (debug) printf("expr -> expr DIV expr\n");
            $$ = newNode(pd, node_div, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   LPAR exprlist RPAR
        {
            if (debug) printf("expr -> LPAR expr RPAR\n");
            $$ = $2;
        }
    |   MINUS expr %prec UMINUS
        {
            if (debug) printf("expr -> UMINUS expr\n");
            $$ = newNode(pd, node_uminus, sizeof(exprNode));
            exprNode *en = (exprNode *)(pd->table + $$);
            en->expr = $2;
        }
    |   NUMBER
        {
            if (debug) printf("expr -> NUMBER[%f]\n", $1);
            $$ = newNode(pd, node_num, sizeof(numNode));
            numNode *nn = (numNode *)(pd->table + $$);
            nn->value = $1;
        }
    |   INT
        {
            if (debug) printf("expr -> INT[%d]\n", $1);
            $$ = newNode(pd, node_int, sizeof(intNode));
            intNode *in = (intNode *)(pd->table + $$);
            in->value = $1;
        }
    |   STRING
        {
            if (debug) {
                stringNode *sn = (stringNode *)(pd->table + $1);
                printf("expr -> STRING[%.*s]\n", sn->hdr->aux, sn->string);
            }
            $$ = $1;
        }
    |   lval ASSIGN expr
        {
            if (debug) printf("expr -> lval ASSIGN expr\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_lval;

            $$ = newNode(pd, node_assign, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->hdr->aux = pm_assign;
            bn->right = $3;
            bn->left = $1;
        }
    |   lval ASSIGN funcexpr
        {
            if (debug) printf("expr -> lval ASSIGN funcexpr\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_lval;

            $$ = newNode(pd, node_assign, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->hdr->aux = pm_assign;
            bn->right = $3;
            bn->left = $1;
        }
    |   lval ASSIGN objlit
        {
            if (debug) printf("expr -> lval ASSIGN objlit\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_lval;

            $$ = newNode(pd, node_assign, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->hdr->aux = pm_assign;
            bn->right = $3;
            bn->left = $1;
        }
    |   lval PLUS_ASSIGN expr
        {
            if (debug) printf("expr -> lval PLUS_ASSIGN expr\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_lval;

            $$ = newNode(pd, node_assign, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->hdr->aux = pm_add;
            bn->right = $3;
            bn->left = $1;
        }
    |   lval MINUS_ASSIGN expr
        {
            if (debug) printf("expr -> lval MINUS_ASSIGN expr\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_lval;

            $$ = newNode(pd, node_assign, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->hdr->aux = pm_sub;
            bn->right = $3;
            bn->left = $1;
        }
    |   expr LPAR arglist RPAR
        {
            if (debug) printf("expr -> expr LPAR arglist RPAR\n");
            $$ = newNode(pd, node_fcncall, sizeof(fcnCallNode));
            fcnCallNode *fc = (fcnCallNode *)(pd->table + $$);
            fc->name = $1;
            fc->args = $3;
        }
    |   LBRACK arraylist RBRACK
        {
            if (debug) printf("expr -> LBRACK arraylist RBRACK\n");
            $$ = newNode(pd, node_array, sizeof(arrayNode));
            arrayNode *an = (arrayNode *)(pd->table + $$);
            an->exprlist = $2;
        }
    |   lval
        {
            if (debug) printf("expr -> lval\n");
            $$ = $1;
        }
    ;

optexpr:
        %empty
        {
            if (debug) printf("optexpr -> _empty_\n");
            $$ = 0;
        }
    |   expr
        {
            if (debug) printf("optexpr -> expr\n");
            $$ = $1;
        }
    ;

arrayelem:
        expr
        {
            if (debug) printf("arrayelem -> expr\n");
            $$ = $1;
        }
    |   funcexpr
        {
            if (debug) printf("arrayelem -> funcexpr\n");
            $$ = $1;
        }
    |   objlit
        {
            if (debug) printf("arrayelem -> objlit\n");
            $$ = $1;
        }
    ;

arraylist:
        %empty
        {
            if (debug) printf("arraylist -> _empty_\n");
            newNode(pd, node_endlist, sizeof(Node));
        }
    |   arrayelem
        {
            if (debug) printf("arraylist -> arrayelem\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }

    |   arrayelem COMMA arraylist
        {
            if (debug) printf("arraylist -> arrayelem COMMA arraylist\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;

lval:
        symbol
        {
            $$ = $1;
        }
    |   expr DOT NAME
        {
            if (debug) {
                stringNode *sn = (stringNode *)(pd->table + $3);
                printf("lval -> expr DOT NAME[%.*s]\n", sn->hdr->aux, sn->string);
            }
            $$ = newNode(pd, node_lookup, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   expr LBRACK expr RBRACK
        {
            if (debug) printf("lval -> expr LBRACK expr RBRACK\n");
            $$ = newNode(pd, node_lookup, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    ;

exprlist:     // non-empty
        expr 
        {
            if (debug) printf("exprlist -> expr\n");
            newNode(pd, node_endlist, sizeof(Node));

            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    |   expr COMMA exprlist
        {
            if (debug) printf("exprlist -> expr COMMA exprlist\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;

objlit:
        LBRACE elemlist RBRACE 
        {
            if (debug) printf("objlit -> LBRACE elemlist RBRACE\n");
            $$ = newNode(pd, node_obj, sizeof(objNode));
            objNode *on = (objNode *)(pd->table + $$);
            on->elemlist = $2;
        }
    ;

elemlist:
        %empty
        {
            if (debug) printf("elemlist -> _empty_\n");
            $$ = newNode(pd, node_endlist, sizeof(Node));
        }
    |   elem
        {
            if (debug) printf("elemlist -> elem\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    |   elem COMMA elemlist
        {
            if (debug) printf("elemlist -> elem COMMA elemlist\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;

elem:
        NAME COLON expr
        {
            if (debug) {
                stringNode *sn = (stringNode *)(pd->table + $1);
                printf("elem -> NAME[%.*s] COLON expr\n", sn->hdr->aux, sn->string);
            }
            $$ = newNode(pd, node_elem, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   STRING COLON expr
        {
            if (debug) {
                stringNode *sn = (stringNode *)(pd->table + $1);
                printf("elem -> STRING[%.*s] COLON expr\n", sn->hdr->aux, sn->string);
            }
            $$ = newNode(pd, node_elem, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   NAME COLON funcexpr
        {
            if (debug) {
                stringNode *sn = (stringNode *)(pd->table + $1);
                printf("elem -> NAME[%.*s] COLON funcexpr\n", sn->hdr->aux, sn->string);
            }
            $$ = newNode(pd, node_elem, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   NAME COLON objlit
        {
            if (debug) {
                stringNode *sn = (stringNode *)(pd->table + $1);
                printf("elem -> NAME[%.*s] COLON objlit\n", sn->hdr->aux, sn->string);
            }
            $$ = newNode(pd, node_elem, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   STRING COLON funcexpr
        {
            if (debug) {
                stringNode *sn = (stringNode *)(pd->table + $1);
                printf("elem -> STRING[%.*s] COLON funcexpr\n", sn->hdr->aux, sn->string);
            }
            $$ = newNode(pd, node_elem, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    |   STRING COLON objlit
        {
            if (debug) {
                stringNode *sn = (stringNode *)(pd->table + $1);
                printf("elem -> STRING[%.*s] COLON objlit\n", sn->hdr->aux, sn->string);
            }
            $$ = newNode(pd, node_elem, sizeof(binaryNode));
            binaryNode *bn = (binaryNode *)(pd->table + $$);
            bn->right = $3;
            bn->left = $1;
        }
    ;

paramlist:
        %empty
        {
            if (debug) printf("paramlist -> _empty_\n");
            $$ = newNode(pd, node_endlist, sizeof(Node));
        }
    |   symbol 
        {
            if (debug) printf("paramlist -> symbol\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_decl;
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    |   symbol COMMA paramlist
        {
            if (debug) printf("paramlist -> symbol COMMA paramlist\n");
            symNode *sn = (symNode *)(pd->table + $1);
            sn->hdr->flag |= flag_decl;
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;

arg:
       AMPER symbol
        {
            if (debug) printf("arg -> AMPER symbol\n");
            symNode *sn = (symNode *)(pd->table + $2);
            sn->hdr->type = node_ref;
            $$ = $2;
        }
    |   expr
        {
            if (debug) printf("arg -> expr\n");
            $$ = $1;
        }
    |   funcexpr
        {
            if (debug) printf("arg -> funcexpr\n");
            $$ = $1;
        }
    |   objlit
        {
            if (debug) printf("arg -> objlit\n");
            $$ = $1;
        }
    ;

arglist:
        %empty
        {
            if (debug) printf("arglist -> _empty_\n");
            $$ = newNode(pd, node_endlist, sizeof(Node));
        }
    |   arg
        {
            if (debug) printf("arglist -> arg\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    |   arg COMMA arglist
        {
            if (debug) printf("arglist -> arg COMMA arglist\n");
            $$ = newNode(pd, node_list, sizeof(listNode));
            listNode *ln = (listNode *)(pd->table + $$);
            ln->elem = $1;
        }
    ;

%%

void yyerror( void *scanner, parseData *pd, char *s, ... )
{
    fprintf(stderr, "yyerror: %s\n", s);
}