I’m trying to use Bison to generate a parser, in C++. The grammar is fine, but I’m having some quick trouble with the actions. Here’s a simple sample:
statements
: statement
| statements statement;
As far as I know, this is a pretty normal thing to do. The question I have is which is derived first. For example, if I have an input which looks like
statement statement statement statement
does Bison call my actions as
statement (statement (statement (statement))))
or
(((statement) statement) statement) statement
I’m trying to construct a linked list of the rules invoked here, and I want to keep the list in the same order as was input. Right now, I’ve got
statements
: statement
{
$$ = $1;
}
| statements statement
{
dynamic_cast<ParsedFile::Statement*>($1)->Next = dynamic_cast<ParsedFile::Statement*>($2);
$$ = $1;
};
Edit: OK, so I could do something like this:
switch_statement
: SWITCH '(' expression ')'
{
auto Switch = p.Make<ParsedFile::SwitchStatement>();
Switch->Test = dynamic_cast<ParsedFile::Expression*>($3);
p.NewScope();
$$ = Switch;
}
'{' case_statements '}'
{
auto Switch = dynamic_cast<ParsedFile::SwitchStatement*>($5);
Switch->Cases = p.statements.top();
p.PopScope();
p.AddToCurrentScope(Switch);
};
default_statement
: DEFAULT ':'
{
auto Default = p.Make<ParsedFile::DefaultStatement>();
p.NewScope();
$$ = Default;
}
statements
{
auto Default = dynamic_cast<ParsedFile::DefaultStatement*>($3);
Default->Statements = p.statements.top();
p.PopScope();
p.AddToCurrentScope(Default);
};
case_statement
: CASE expression
{
auto case = p.Make<ParsedFile::CaseStatement>();
p->Value = dynamic_cast<ParsedFile::Expression*>($2);
p.NewScope();
$$ = case;
}
DOUBLE_COLON statements
{
auto Case = dynamic_cast<ParsedFile::CaseStatement*>($3);
Case->Statements = p.statements.top();
p.PopScope();
p.AddToCurrentScope(Case);
};
case_statements
: case_statement
| case_statements case_statement
| case_statements default_statement;
It associates to the left, i.e.
You can tell that this is the only possibility because this can be reduced to
statements statement, which is one of your productions. The other optionwould have to be reduced to
statement statements, which is not one of your productions. However, you can use this if you want right-associativity instead.Your code will not produce a linked list as-is, because after joining one statement with the other, you return a pointer to the first statement, so when the next statement comes around you’re overwriting the
Nextpointer of the first statement.Changing the order to right associative should solve this, but note that this will require linear parser stack space in the number of statements. If you expect many statements you should therefore consider building the linked list in reverse.