3

我正在尝试使用一些简单的功能来扩展Jison 计算器示例。我对解析和野牛/吉森相当陌生,但这是我到目前为止所拥有的一点:

/* lexical grammar */
%lex

%{
  var funcs = {
    pow: function(a, b) { return Math.pow(a, b); },
    test: function(a) { return a*2; }
  }
%}

%%

\s+                   /* skip whitespace */
[0-9]+("."[0-9]+)?\b  return 'NUMBER'
[a-zA-Z]+             return 'NAME'
","                   return ','
"*"                   return '*'
"("                   return '('
")"                   return ')'
<<EOF>>               return 'EOF'
.                     return 'INVALID'

/lex

%start expressions

%% /* language grammar */
expressions
    : e EOF
      { return $1; }
    ;

expression_list
    : expression_list ',' e
    | e
    ;

e
    : e '*' e
        {$$ = $1*$3;}
    | '(' e ')'
        {$$ = $2;}
    | NUMBER
        {$$ = Number(yytext);}
    | NAME '(' expression_list ')'
        {$$ = funcs[$NAME]($expression_list);}
    ;

问题是函数只得到一个参数传递给它们。例如:

test(2) -> 4
pow(2,3) -> null

事实上,如果你console.log的论点pow,它似乎b甚至没有定义。为什么它在将整个表达式列表发送到函数之前不解析整个表达式列表?

4

2 回答 2

4

以下代码可以满足您的要求。要点:

  1. 现在的规则expression_list构建了一个实际的值列表,用于被调用的函数。

  2. 建立的列表expression_list被传递给,apply以便它们成为被调用函数的参数(undefined作为第一个参数来设置 to 的值thisundefined

  3. 我已经为操作添加了一条console.log指令,expression以便在我在命令行运行生成的解析器时看到发生了什么。

  4. 我已经将 的定义funcs移到了最开始。它在哪里 jison 只是没有把它放在最终文件中的正确位置。

这是最终文件:

%{var funcs = {
    pow: function(a, b) { return Math.pow(a, b); },
    test: function(a) { return a*2; }
  }
%}

/* lexical grammar */
%lex

%%

\s+                   /* skip whitespace */
[0-9]+("."[0-9]+)?\b  return 'NUMBER'
[a-zA-Z]+             return 'NAME'
","                   return ','
"*"                   return '*'
"("                   return '('
")"                   return ')'
<<EOF>>               return 'EOF'
.                     return 'INVALID'

/lex

%start expressions

%% /* language grammar */
expressions
    : e EOF
      { console.log($1); return $1; }
    ;

expression_list
    : expression_list ',' e
      { $$ = $1.concat([$3]); }
    | e
      { $$ = [$1]; }
    ;

e
    : e '*' e
        {$$ = $1*$3;}
    | '(' e ')'
        {$$ = $2;}
    | NUMBER
        {$$ = Number(yytext);}
    | NAME '(' expression_list ')'
        {$$ = funcs[$NAME].apply(undefined, $expression_list);}
    ;
于 2014-10-30T20:02:34.500 回答
1

您需要在第一个生产中为expression_list. 默认操作只是复制$1$$,这意味着附加的值被丢弃。

于 2014-10-30T19:43:09.893 回答