2012-02-03 67 views
3

我正在使用Boost Spirit在一个小编译器项目中解析源文件。如何用位置信息注释AST?

如果在解析过程中出现错误,我可以打印错误的位置,但是在后期阶段我通常如何执行语义检查?

使用自动规则将我的源文件解析为抽象语法树。我想将行和列信息添加到AST节点中。在解析过程中有没有简单的方法来实现?

我在我的Lexer中使用boost :: spirit :: classic :: position_iterator2,然后在我的语法中使用这个词法分析器。

谢谢

编辑sehe:

词法分析器定义这样的:

typedef std::string::iterator base_iterator_type; 
typedef boost::spirit::classic::position_iterator2<base_iterator_type> pos_iterator_type; 
typedef boost::spirit::lex::lexertl::token<pos_iterator_type> Tok; 
typedef boost::spirit::lex::lexertl::actor_lexer<Tok> lexer_type; 

template<typename L> 
class SpiritLexer : public lex::lexer<L> { 
    //Token definitions 
} 

typedef lexer_type::iterator_type Iterator; 
typedef SpiritLexer<lexer_type> Lexer; 

的语法定义这样的:

struct EddiGrammar : qi::grammar<lexer::Iterator, ast::SourceFile()> { 
    EddiGrammar(const lexer::Lexer& lexer); 

    //Token definitions 
}; 

最后,这里是我如何解析源代码:

ast::SourceFile program 

std::ifstream in(file.c_str()); 
in.unsetf(std::ios::skipws); 

in.seekg(0, std::istream::end); 
std::size_t size(static_cast<size_t>(in.tellg())); 

in.seekg(0, std::istream::beg); 

std::string contents(size, 0); 
in.read(&contents[0], size); 

pos_iterator_type position_begin(contents.begin(), contents.end(), file); 
pos_iterator_type position_end; 

Lexer lexer; 
EddiGrammar grammar(lexer); 

bool r = spirit::lex::tokenize_and_parse(position_begin, position_end, lexer, grammar, program); 

在我的语法中,我通过引用一些词法分析符号来使用词法分析器。例如:

else_ %= 
     lexer.else_ 
    >> lexer.left_brace 
    >> *(instruction) 
    >> lexer.right_brace; 

我所有的AST节点都是使用自动规则构建的。

+0

我已经花了几天时间回来了。你正在使用Spirit Lex的一个小例子会很有帮助。 – sehe 2012-02-09 14:47:27

+0

我添加了关于如何使用Spirit Parser的Spirit Lex的示例。我希望这足够吗? – 2012-02-09 22:13:14

+0

我添加了关于该问题的基本解决方案的答案。 – 2012-02-26 18:26:03

回答

4

我找到了解决这个问题的方法。

我写了一个简单的终端解析器,只是获取当前位置并将其添加到AST节点。

这里是我写的解析器:

namespace boost { namespace spirit { 
    BOOST_SPIRIT_TERMINAL(position) 

    template <> 
    struct use_terminal<qi::domain, tag::position> : mpl::true_ {}; 
}} 

namespace boost { namespace spirit { namespace qi 
{ 
    struct position : primitive_parser<position> 
    { 
     position(const eddic::lexer::pos_iterator_type& position_begin) : position_begin(position_begin) {} 

     template <typename Context, typename Iterator> 
     struct attribute { 
      typedef eddic::ast::Position type; 
     }; 

     template <typename Iterator, typename Context 
      , typename Skipper, typename Attribute> 
      bool parse(Iterator& first, Iterator const& last 
        , Context& /*context*/, Skipper const& skipper, Attribute& attr) const 
     { 
      qi::skip_over(first, last, skipper); 

      auto& pos = position_begin.get_position(); 

      attr.theLine = position_begin.get_currentline(); 
      attr.file = pos.file; 
      attr.column = pos.column; 
      attr.line = pos.line; 

      return true; 
     } 

     template <typename Context> 
     info what(Context& context) const { 
      return info("position"); 
     } 

     const eddic::lexer::pos_iterator_type& position_begin; 
    }; 

    template <typename Modifiers> 
    struct make_primitive<tag::position, Modifiers> { 
     typedef position result_type; 
     result_type operator()(unused_type, eddic::lexer::Lexer const& lexer, unused_type) const 
     { 
      return result_type(lexer); 
     } 
    }; 
}}} 

,我用它来存储信息的结构:

struct Position { 
    std::string file; 
    std::string theLine; 
    int line; 
    int column; 
}; 

它运作良好,但我要的位置迭代器传递给解析器。如果有人知道从Iterator提供给parse函数的position_iterator2迭代器,我会很感激。