如何用位置信息注释AST?

时间:2012-02-03 14:18:09

标签: c++ boost-spirit

我正在使用Boost Spirit来解析一个小编译器项目中的源文件。

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

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

我在我的Lexer中使用了boost :: spirit :: classic :: position_iterator2,然后在我的语法中使用了这个lexer。

谢谢

编辑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节点都是使用自动规则构建的。

1 个答案:

答案 0 :(得分: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获取position_iterator2迭代器的方法,我将不胜感激。