【发布时间】:2011-07-26 20:20:09
【问题描述】:
我正在尝试使用 Bison 在 C++ 中生成解析器。语法很好,但我在操作上遇到了一些麻烦。这是一个简单的示例:
statements
: statement
| statements statement;
据我所知,这是一件很正常的事情。我的问题是哪个先派生。例如,如果我的输入看起来像
statement statement statement statement
Bison 是否将我的行为称为
statement (statement (statement (statement))))
或
(((statement) statement) statement) statement
我正在尝试构建此处调用的规则的链接列表,并且我希望保持列表与输入的顺序相同。现在,我有
statements
: statement
{
$$ = $1;
}
| statements statement
{
dynamic_cast<ParsedFile::Statement*>($1)->Next = dynamic_cast<ParsedFile::Statement*>($2);
$$ = $1;
};
编辑:好的,所以我可以这样做:
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;
【问题讨论】:
-
@DeadMG:请注意,因为您将
$2附加到$1,然后“返回”$1到$$,您将重置相同下一次推导后节点的Next指针。如果您非常想要一个链表(为什么不是vector或deque?),您必须同时保留指向其头部和尾部的指针。 -
@larsmans:我没有使用向量或双端队列,因为我没有地方可以依赖它来存储它。堆栈中可能有多个
statements(C 样式语法),并且 Bison 并没有真正提供保持复杂容器的功能。实际上,想想看,我从来没有想过它们会是一个实际的堆栈,所以我可以将它存储在我的用户提供的参数中,并使用中间规则参数来推送和弹出它。