variables in yy seems to be reset back to initial value, is it expected behavior?
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?
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.
Thanks for the explanation.