简体   繁体   中英

Boost Semantic Actions causing parsing issues

I've been working with the Boost mini compiler example. Here is the root of the source code: http://www.boost.org/doc/libs/1_59_0/libs/spirit/example/qi/compiler_tutorial/mini_c/

The snippet that interests me is in statement_def.hpp

The problem I am having is that if you attach semantic actions, for example like such,

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

And subsequent run the mini_c compiler on a sample program like:

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

int main() {
    return foo(10);
}

It triggers the "Duplicate Function Error" found within the "compile.cpp" file (found using the above link). Here is that snippet for quick reference:

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

For the life of me, I can't figure out why.

I'm not really sure how to characterize this problem, but it seems that somehow whatever is sent to standard out is being picked up by the parser as valid code to parse (but that seems impossible in this scenario).

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).

The last and likely option is that probably I don't fully understand the minutiae of this example (or Boost for that matter), and that somewhere a pointer/reference/Iterator is being shifted to another memory location when it shouldn't (as a result of the SA), throwing the whole mini-compiler into disarray.

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

As unlikely as it seemed... it is indeed :) No magic occurs.

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).

You're not actually far off here. It's not so much "external" data, though. It's binding uninitialized data to the symbol table. And it actually tries to do that twice.

Step by step:

  1. Qi rules that have semantic actions don't do automatic attribute propagation by default. It is assumed that the semantic action will be in charge of assigning a value to the attribute exposed.

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

    在此输入图像描述

    Also: How Do Rules Propagate Attributes

  2. Because of this, the actual attribute exposed by the statement_ rule will be a default-constructed object of type ast::statement :

     qi::rule<Iterator, ast::statement(), skipper<Iterator> > statement_; 
  3. This type ast::statement is a variant, and a default constructed variant holds a default-constructed object of the first element type:

     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. Lo and behold, that object is of type variable_declaration !

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

    So, each time the statement_ rule matched, the AST will be interpreted as a "declaration of a variable with identifier name "" ". (Needless to say, the initializer ( rhs ) is also empty).

    The second time this declaration is encountered violates the rule that duplicate names cannot exist in the "symbol table".

HOW TO FIX?

You can explicitly indicate that you want automatic attribute propagation even in the presence of Semantic Actions.

Use operator%= instead of operator= to _assign the rule definition:

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

Now, everything will work again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM