2016-03-07 121 views
0

我正在實現一個JavaScript解釋器,並且我在函數聲明和函數表達式的語法中遇到了野牛減少/減少衝突的問題。我並不是那種野牛的經歷,我可以用一些幫助來理解要做什麼。我已經粘貼野牛輸入文件的子集,說明了以下的問題:JavaScript函數聲明野牛語法減少/減少錯誤

%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); 
} 
+0

真正的JavaScript解析器通過歧義在一份聲明中爲聲明的開始治療'function'關鍵詞,其他地方爲一個表達式。 JavaScript(完整的語言)很難解析。 – Pointy

+0

這就是爲什麼我引入了pgmlist生產來確定FCN是否是聲明而不是表達式的原因。 – Malbrain

+0

但'funcexpr'也可以作爲'exprlist'的第一部分出現 – Pointy

回答

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); 
}