2012-02-03 13 views
3

私は小さなコンパイラプロジェクトでソースファイルを解析するためにBoost Spiritを使用しています。ASTに位置情報を付けるにはどうすればいいですか?

構文解析中にエラーが発生した場合は、エラーの位置を出力できますが、後のフェーズで、通常セマンティックチェックを実行するときにはどうすればよいですか?

ソースファイルは自動ルールを使用して抽象構文木に解析されます。 ASTノードに行と列の情報を追加したい。解析中に簡単に実現できる方法はありますか?

私はLexerでboost :: spirit :: classic :: position_iterator2を使用していて、このレクサーを文法に使用しています。

EDIT 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

私は数日を費やしています。スピリット・レックスを使用している小さなサンプルが役に立ちます。 – sehe

+0

Spirit ParserのSpirit Lexの使い方に関するサンプルを追加しました。これで十分だろうか? –

+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; 
}; 

それはうまく動作しますが、私はパーサーに位置イテレータを渡す必要があります。誰かがparse関数に渡されたIteratorからposition_iterator2イテレータを取得する方法を知っていれば、私は感謝します。

関連する問題