2011-07-26 24 views
1

我正尝试使用Bison在C++中生成解析器。语法很好,但是我在操作上遇到了一些麻烦。这里有一个简单的例子:在Bison中的操作顺序

statements 
: statement 
| statements statement; 

据我所知,这是一个非常正常的事情。我的问题是首先得出的。举例来说,如果我有一个看起来像

statement statement statement statement 

不野牛叫我的行动为

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; 
}; 

编辑:OK,所以我可以做这样的事情:

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; 
+0

为什么downvote? – Praetorian

+0

@DeadMG:请注意,因为您将'$ 2'追加到'$ 1',然后通过'$$'返回$ 1',您将在下一次派生后重置同一个节点的下一个指针。如果你非常想要一个链表(为什么不是'vector'或'deque'?),你必须保持指针的头部和尾部。 –

+0

@larsmans:我没有使用vector或deque,因为我没有地方存储它,我可以依赖它。堆栈中可能有多个“语句”(C风格语法),而Bison并没有真正提供在复杂容器周围的保留。其实,想一想,我从来没有想过它们会成为一个实际的堆栈,所以我可以将它存储在用户提供的参数中,并使用中间规则参数来推送和弹出它。 – Puppy

回答

4

它关联到左侧,即

(((statement) statement) statement) statement 

你可以告诉这是唯一的可能性,因为这可能会减少到statements statement,这是您的作品之一。另一种选择

statement (statement (statement (statement)))) 

将不得不减少到statement statements,这是一个你的作品的。但是,如果您想要右关联性,则可以使用此功能。

你的代码,是因为与其他加盟一个语句后,将返回一个指向第一语句,所以当下面的语句来临时你覆盖Next指针不会产生链表的第一个声明。

将顺序更改为正确联想应解决此问题,但请注意,这将需要语句数量中的线性解析器堆栈空间。如果你期望很多陈述,你应该考虑建立链接列表。

+0

感谢您的输入。我编辑了我的OP,以反映针对同一问题的不同策略 - 我会很感激您的回应。如果没有,那么我会接受你的答案,因为它回答了原来的问题。 – Puppy

+0

@DeadMG:我倾向于避免在动作中编写有状态代码,因为它可能很难遵循事物的顺序。考虑以'$$ = foo($ 1,$ 2)'的形式编写你的动作。顺序与你写'foo(foo(foo(bar(first),second),third),fourth)'相同。 – hammar

+0

我需要那种范围的东西,以确定正确的范围使用。以另一种方式做我认为不可行的方式。然而,对于无表达式的无范围构造,它们将在功能上而非状态上构建。 – Puppy