zaach / jison

Bison in JavaScript.
http://jison.org
4.34k stars 448 forks source link

variables in yy seems to be reset back to initial value, is it expected behavior? #327

Open nnabuuu opened 8 years ago

nnabuuu commented 8 years ago

Here is a very simple example to re-produce this issue:

/* description: Reproduce the issue. */

/* lexical grammar */
%lex
%{
    yy.someArray3 = [];
    yy.someValue2 = 'someValue';
%}
%%

"a"+                   return 'A'
"b"+                   return 'B'
\s+                   /* skip whitespace */
<<EOF>>               return 'EOF'

/lex

/* operator associations and precedence */

%start ab 

%% /* language grammar */

ab
    : c d EOF
    {return $1 + $2;}
    ;

c
    : A
        {

            yy.someValue = $1;
            yy.someValue2 = $1;
            yy.someArray = [$1];
            yy.someArray2 = [];
            yy.someArray2.push($1);
            yy.someArray3.push($1);
            console.log(yy);
            $$ = $1;
        }
    ;

d
    : B
        { 
            console.log(yy);
            $$ = $1;
        }
    ;

When using this to parse "aaaaaaabb", the response is:

{ lexer:
   { yy: [Circular],
     _input: 'bb',
     done: false,
     _backtrack: false,
     _more: false,
     yyleng: 7,
     yylineno: 0,
     match: 'aaaaaaa',
     matched: 'aaaaaaa',
     yytext: 'aaaaaaa',
     conditionStack: [ 'INITIAL' ],
     yylloc: { first_line: 1, last_line: 1, first_column: 0, last_column: 7 },
     offset: 0,
     matches: [ 'aaaaaaa', index: 0, input: 'aaaaaaabb' ] },
  parser: { yy: {}, parseError: [Function: parseError] },
  someArray3: [ 'aaaaaaa' ],
  someValue2: 'aaaaaaa',
  someValue: 'aaaaaaa',
  someArray: [ 'aaaaaaa' ],
  someArray2: [ 'aaaaaaa' ] }
{ lexer:
   { yy: [Circular],
     _input: '',
     done: false,
     _backtrack: false,
     _more: false,
     yyleng: 2,
     yylineno: 0,
     match: 'bb',
     matched: 'aaaaaaabb',
     yytext: 'bb',
     conditionStack: [ 'INITIAL' ],
     yylloc: { first_line: 1, last_line: 1, first_column: 7, last_column: 9 },
     offset: 0,
     matches: [ 'bb', index: 0, input: 'bb' ] },
  parser: { yy: {}, parseError: [Function: parseError] },
  someArray3: [],
  someValue2: 'someValue',
  someValue: 'aaaaaaa',
  someArray: [ 'aaaaaaa' ],
  someArray2: [ 'aaaaaaa' ] }

Here you see, yy.someArray3 and yy.someValue2 is set back to the defined values.

Is this the expected behavior?

GerHobbelt commented 7 years ago

Yes.

The %{...%} block where you set up those values is invoked every time at the start of a rule reduction. In other words: think of that code chunk as being prefixed before every rule action code block.

As other rules will be 'reduced' (~ their action code chunks will be executed) after rule c: A gets reduced and before the parse finishes, you will effectively execute that %{...%} code chunk at the top a few more times, producing exactly the result you are seeing in your example.

nnabuuu commented 7 years ago

Thanks for the explanation.