导致解析问题的增强语义操作

Boost Semantic Actions causing parsing issues

我一直在使用 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" 文件中找到的 "Duplicate Function Error"(使用上面的 link 找到)。这是供快速参考的片段:

    if (functions.find(x.function_name.name) != functions.end())
    {
        error_handler(x.function_name.id, "Duplicate function: " + x.function_name.name);
        return false;
    }

对于我的生活,我不明白为什么。

我不太确定如何描述这个问题,但似乎以某种方式发送到标准输出的任何内容都被解析器拾取为要解析的有效代码(但在这种情况下这似乎是不可能的)。

另一种可能性是语义操作以某种方式将外部数据绑定到一个符号 table,它再次被认为是最初解析的输入文件的一部分(当它不应该是)。

最后一个可能的选择是,我可能不完全理解这个例子(或 Boost 的细节)的细节,并且 pointer/reference/Iterator 在某处被转移到另一个内存位置时不应该(作为 SA 的结果),使整个迷你编译器陷入混乱。

[...] it seems that somehow whatever is sent to standard out is being picked up by the parser as valid code to parse

虽然看起来不太可能......确实是 :) 没有魔法发生。

Another possibility is the semantic action is somehow binding external data to a symbol table, where it is again considered to be part of the originally-parsed input file (when it shouldn't be).

其实你离这里并不远。不过,"external" 数据并不多。它将 未初始化的 数据绑定到符号 table。它实际上尝试了两次。

一步一步:

  1. 默认情况下,具有语义操作的 Qi 规则不进行自动属性传播。 假定语义动作将负责为暴露的属性赋值。

    This is the root cause. See documentation: Rule/Expression Semantics

    Also: How Do Rules Propagate Attributes

  2. 因此,statement_ 规则公开的实际属性将是类型 ast::statement:

    的默认构造对象
    qi::rule<Iterator, ast::statement(), skipper<Iterator> > statement_;
    
  3. 这个类型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;
    
  4. 瞧瞧,那个对象的类型是variable_declaration

    struct variable_declaration {
        identifier lhs;
        boost::optional<expression> rhs;
    };
    

    因此,每次 statement_ 规则匹配时,AST 将被解释为 "declaration of a variable with identifier name """。 (不用说,初始化器(rhs)也是空的)。

    第二次遇到这个声明违反了"symbol table".

  5. 中不能存在重名的规则

如何修复?

即使存在语义操作,您也可以明确指出您希望自动传播属性。

使用 operator%= 而不是 operator= _assign 规则定义:

    statement_ %=
            variable_declaration [print_this_declaration]
        |   assignment
        |   compound_statement
        |   if_statement
        |   while_statement
        |   return_statement
        ;

现在,一切都会恢复正常。