我一直在使用Boost迷你编译器示例。以下是源代码的根目录:http://www.boost.org/doc/libs/1_59_0/libs/spirit/example/qi/compiler_tutorial/mini_c/
我感兴趣的代码段位于statement_def.hpp
我遇到的问题是,如果你附加了语义动作,例如像
那样statement_ =
variable_declaration[print_this_declaration]
| assignment
| compound_statement
| if_statement
| while_statement
| return_statement
;
然后在示例程序上运行mini_c
编译器,如:
int foo(n) {
if (n == 3) { }
return a;
}
int main() {
return foo(10);
}
它触发"重复功能错误"在" compile.cpp"中找到文件(使用上面的链接找到)。以下是该片段的快速参考:
if (functions.find(x.function_name.name) != functions.end())
{
error_handler(x.function_name.id, "Duplicate function: " + x.function_name.name);
return false;
}
对于我的生活,我无法弄清楚原因。
我不确定如何表征这个问题,但似乎某种方式发送到标准输出的任何东西被解析器选为解析的有效代码(但在这种情况下似乎不可能)。
另一种可能性是语义动作以某种方式将外部数据绑定到符号表,其中它再次被认为是最初解析的输入文件的一部分(当它不应该是)时。
最后也可能的选择是,我可能不完全理解这个例子的细节(或者就此而言是Boost),以及某个地方指针/引用/迭代器被转移到另一个内存位置时不应该(作为SA的结果),让整个迷你编译器陷入混乱。
答案 0 :(得分:6)
[...]似乎以某种方式发送到标准输出的内容被解析器选为解析的有效代码
看起来不太可能......确实如此:)没有魔法发生。
另一种可能性是语义操作以某种方式将外部数据绑定到符号表,在那里它再次被认为是原始解析的输入文件的一部分(当它不应该定)。
你真的不在这里。然而,并非如此“外部”数据。它将未初始化的数据绑定到符号表。它实际上试图这样做两次。
一步一步:
默认情况下,具有语义操作的Qi规则不会执行自动属性传播。 假设 ,语义操作将负责为暴露的属性赋值。
因此,statement_
规则公开的实际属性将是ast::statement
类型的默认构造对象:
qi::rule<Iterator, ast::statement(), skipper<Iterator> > statement_;
此类型ast::statement
是变体,默认构造变量包含第一个元素类型的默认构造对象:
typedef boost::variant<
variable_declaration
, assignment
, boost::recursive_wrapper<if_statement>
, boost::recursive_wrapper<while_statement>
, boost::recursive_wrapper<return_statement>
, boost::recursive_wrapper<statement_list>
>
statement;
瞧,该对象的类型为variable_declaration
!
struct variable_declaration {
identifier lhs;
boost::optional<expression> rhs;
};
因此,每次statement_
规则匹配时,AST将被解释为“具有 identifier
名称""
”的变量声明。 (不用说,初始值设定项(rhs
)也是空的。)
第二次遇到此声明违反了“符号表”中不能存在重复名称的规则。
即使存在语义操作,您也可以明确指出您希望自动传播属性。
使用operator%=
代替operator=
来分配规则定义:
statement_ %=
variable_declaration [print_this_declaration]
| assignment
| compound_statement
| if_statement
| while_statement
| return_statement
;
现在,一切都会再次发挥作用。