Adding functions to bison/jison calculator language

喜欢而已 提交于 2019-12-10 21:18:24

问题


I'm trying to expand the Jison calculator example with some simple functions. I'm rather new to parsing and bison/jison, but this is a bit of what I have so far:

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

The problem is that functions are only getting one argument passed to them. For example:

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

In fact, if you console.log the arguments of pow, it appears b isn't even defined. Why isn't it parsing the whole expression list before sending it to the function?


回答1:


The following code does what you asked for. Salient points:

  1. The rules for expression_list now build an actual list of values to be used with the functions being called.

  2. The list built by expression_list are passed to apply so that they become the arguments of the function being called (undefined is there as the first argument to set the value of this to undefined).

  3. I've added a console.log instruction to the actions for expression so that I'd see what is going on when I run the resulting parser at the command line.

  4. I've moved the definition of funcs to the very start. Where it was jison was just not putting it in the right place in the final file.

Here's the final file:

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



回答2:


You need an action in the first production for expression_list. The default action just copies $1 to $$, which means that the appended value is discarded.



来源:https://stackoverflow.com/questions/26661565/adding-functions-to-bison-jison-calculator-language

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!