Boost.Spirit を使用して簡単な文法をコンパイルしようとしています。Arch Linux x86_64 で g++ 4.7.0 とブースト 1.49.0-1.1 を使用しています。
ここでの最終的な目標はアセンブラです。それぞれ 1 つのクラスを持つ複数のオペランドがあります。すべてのオペランド型がまとめて 1 つのboost::variant
型に格納されます。
direct
文法のbase_typeでもある場合、このサンプルをルールまでコンパイルすることに成功しましたが、ルールを導入するoperand
(そしてそれをベースタイプにする)と、g ++ 4.7.0は次のように不平を言います:
example.cpp:61:7: required from ‘Grammar<Iterator>::Grammar() [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >]’
example.cpp:76:21: required from here
/usr/include/boost/spirit/home/qi/detail/attributes.hpp:23:63: error: no matching function for call to ‘DirectOperand::DirectOperand()’
/usr/include/boost/spirit/home/qi/detail/attributes.hpp:23:63: note: candidates are:
example.cpp:20:12: note: DirectOperand::DirectOperand(const DirectValue&)
example.cpp:20:12: note: candidate expects 1 argument, 0 provided
example.cpp:16:7: note: DirectOperand::DirectOperand(const DirectOperand&)
example.cpp:16:7: note: candidate expects 1 argument, 0 provided
DirectOperand
セマンティックアクションはコンストラクターでそれを呼び出す必要があるため、 のデフォルトコンストラクターを探す必要がある理由がわかりません。
を含む多くのバリエーションを試しました
operand = directOp[_val = _1];
次のように、タイプを「強制」するヘルパー関数を作成することさえできます。
static Operand makeDirectOperand( const DirectOperand& op ) { return op; }
// ...
operand = directOp[&makeDirectOp];
しかし、私が何をしても、デフォルトのコンストラクターが欠落していると不平を言います。
ゼロ引数のコンストラクターを実際に定義したところ、それがコンパイルされていることがわかりましたが、それDirectOperand::value_
は割り当てたデフォルト値から決して変化しませんでした。
これがコードです。できる限り短いです。
#include <cstdint>
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_uint.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/variant.hpp>
typedef std::uint16_t DataWord;
typedef boost::variant<std::string, DataWord> DirectValue;
class DirectOperand {
private:
DirectValue value_;
public:
explicit DirectOperand( const DirectValue& value ) :
value_( value ) {}
const DirectValue& value() const { return value_; }
};
// For example purposes, but there will be multiple operand types
// here.
typedef boost::variant<DirectOperand> Operand;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
struct Grammar : qi::grammar<Iterator, Operand(), ascii::space_type> {
Grammar() : Grammar::base_type( operand ) {
using qi::lexeme;
using ascii::char_;
using qi::uint_parser;
using namespace qi::labels;
uint_parser<DataWord, 16, 1, 4> uhex_p;
uint_parser<DataWord, 10, 1, 5> uint_p;
word =
char_( "a-zA-Z._" ) [_val += _1]
>> *char_( "a-zA-Z0-9._" ) [_val += _1]
;
number = (
"0x" >> uhex_p
| uint_p
)
[_val = _1]
;
direct %= ( word | number );
directOp %= direct;
// This would be ( directOp | indirectOp | etc)
operand %= directOp;
}
qi::rule<Iterator, DataWord(), ascii::space_type> number;
qi::rule<Iterator, std::string()> word;
qi::rule<Iterator, DirectValue(), ascii::space_type> direct;
qi::rule<Iterator, DirectOperand(), ascii::space_type> directOp;
qi::rule<Iterator, Operand(), ascii::space_type> operand;
};
int main() {
std::string line;
typedef std::string::iterator iterator_type;
typedef Grammar<iterator_type> Grammar;
Grammar grammar {};
}