添加bison / jison计算器语言的功能

时间:2014-10-30 19:20:27

标签: javascript parsing bison jison

我尝试使用一些简单的功能扩展Jison calculator example。我对解析和野牛/ 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似乎无法定义。为什么在将它发送到函数之前解析整个表达式列表呢?

2 个答案:

答案 0 :(得分:2)

以下代码执行您要求的操作。突出点:

  1. expression_list的规则现在构建了一个与要调用的函数一起使用的实际值列表。

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

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

  4. 我已将funcs的定义移至一开始。在哪里,jison只是没有把它放在最终档案中的正确位置。

  5. 这是最终文件:

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

答案 1 :(得分:1)

您需要在expression_list的第一个作品中执行操作。默认操作只是将$1复制到$$,这意味着将丢弃附加的值。