我正在使用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节点都是使用自动规则构建的。
答案 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迭代器的方法,我将不胜感激。