我一直在使用 Boost mini 编译器示例。这是源代码的根: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 的结果),使整个迷你编译器陷入混乱。
[...] 似乎以某种方式发送到标准输出的任何内容都被解析器拾取为要解析的有效代码
尽管看起来不太可能...但确实如此:) 没有魔法发生。
另一种可能性是语义动作以某种方式将外部数据绑定到符号表,它再次被认为是最初解析的输入文件的一部分(当它不应该是时)。
其实你离这里并不远。不过,这并不是那么多“外部”数据。它具有约束力未初始化的数据到符号表。它实际上尝试这样做两次。
一步步:
-
默认情况下,具有语义操作的 Qi 规则不会执行自动属性传播。这是assumed语义动作将负责为暴露的属性分配一个值。
这是根本原因. See 文档:规则/表达式语义
![enter image description here](https://i.stack.imgur.com/v9dn4.png)
Also: 规则如何传播属性
-
因此,暴露的实际属性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
name ""
”。(不用说,初始化器(rhs
) 也是空的)。
第二次遇到此声明违反了“符号表”中不能存在重复名称的规则。
怎么修?
即使存在语义操作,您也可以明确指示您希望自动传播属性。
Use operator%=
代替operator=
_分配规则定义:
statement_ %=
variable_declaration [print_this_declaration]
| assignment
| compound_statement
| if_statement
| while_statement
| return_statement
;
现在,一切都会恢复正常。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)