提升语义操作导致解析问题

Dyl*_*kin 3 c++ templates boost header boost-spirit-qi

我一直在使用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
            ;
Run Code Online (Sandbox Code Playgroud)

然后mini_c在一个示例程序上运行编译器,如:

int foo(n) {
    if (n == 3) { }
    return a;
}

int main() {
    return foo(10);
}
Run Code Online (Sandbox Code Playgroud)

它触发"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;
    }
Run Code Online (Sandbox Code Playgroud)

对于我的生活,我无法弄清楚为什么.

我不确定如何表征这个问题,但似乎无论如何发送到标准输出的任何东西都被解析器选为解析的有效代码(但在这种情况下似乎不可能).

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

最后也可能的选择是,我可能并不完全理解这个例子的细节(或者就此而言是Boost),并且当指针/引用/迭代器不应该转移到另一个内存位置时(如SA的结果,使整个迷你编译器陷入混乱.

seh*_*ehe 6

[...]似乎以某种方式发送到标准输出的任何东西被解析器拾取为解析的有效代码

尽管看起来不太可能......确实是:)没有魔法发生.

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

你真的不在这里.然而,并非如此"外部"数据.它将未初始化的数据绑定到符号表.它实际上试图做两次.

一步步:

  1. 具有语义动作的Qi规则默认不进行自动属性传播.这是假设的语义动作将负责将值分配给暴露的属性.

    这是根本原因.请参阅文档:规则/表达式语义

    在此输入图像描述

    另外:规则如何传播属性

  2. 因此,statement_规则公开的实际属性将是类型的默认构造对象ast::statement:

    qi::rule<Iterator, ast::statement(), skipper<Iterator> > statement_;
    
    Run Code Online (Sandbox Code Playgroud)
  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;
    
    Run Code Online (Sandbox Code Playgroud)
  4. 瞧,那个物体属于类型variable_declaration!

    struct variable_declaration {
        identifier lhs;
        boost::optional<expression> rhs;
    };
    
    Run Code Online (Sandbox Code Playgroud)

    因此,每次statement_规则匹配时,AST将被解释为"具有identifier名称的变量的声明""".(不用说,初始化器(rhs)也是空的).

    第二次遇到此声明违反了"符号表"中不能存在重复名称的规则.

怎么修?

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

使用operator%=而不是_ operator=分配规则定义:

    statement_ %=
            variable_declaration [print_this_declaration]
        |   assignment
        |   compound_statement
        |   if_statement
        |   while_statement
        |   return_statement
        ;
Run Code Online (Sandbox Code Playgroud)

现在,一切都会再次奏效.

  • 关于要点的代码:https://gist.github.com/sehe/5bb9891590a4cac3ee27,录制的直播在这里:https://www.livecoding.tv/video/troubleshooting-the-mini_c-compiler-tutorial/([experiment] (http://chat.stackoverflow.com/transcript/10?m=24182469#24182469)) (2认同)