Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > boost::spirit построение дерева из формулы


Автор: bsa 3.7.2009, 15:50
Есть набор сложных формул, кодирующих биты. Операции все логические:
Код
1 = 2 & 3 ^ (!5 | 4) #bit[1] = (bit[2] & bit[3]) ^ (!bit[5] | bit[4])
....
Хочу распарсить правую часть с помощью спирита. Взял пример калькулятора и немного его модифицировал:
Код
struct Calculator : boost::spirit::grammar< Calculator >
{
    Calculator() {}
    typedef unsigned Type;
    typedef boost::shared_ptr<Operation::Base<Type> > OperationPtr;

    struct ValueClosure : public boost::spirit::closure<ValueClosure, OperationPtr> {
        member1 value;
    };

    // Following is the grammar definition.
    template <typename ScannerT>
    struct definition {
        definition(Calculator const& self) {
            using namespace boost::spirit;
            using namespace phoenix;
    
            literal = int_p[bind(&definition::createBit, literal, arg1)];
            group = '(' >> expression[group.value = arg1] >> ')';
            factor = literal[factor.value = arg1] | group[factor.value = arg1];
            term = factor[term.value = arg1] >> *('!' >> factor[bind(&definition::createNot, term, arg1)]);

            expression
                = term[expression.value = arg1]
                >> *('&' >> term[bind(&definition::createAnd, expression, arg1)] )
                >> *('^' >> term[bind(&definition::createXor, expression, arg1)] )
                >> *('|' >> term[bind(&definition::createOr, expression, arg1)] )
                ;

            //statement = expression[bind(&calculator::do_print)(self, arg1)] >> end_p;
        }

        boost::spirit::rule<ScannerT> const& start() const { return statement; }
    private:
        boost::spirit::rule<ScannerT> statement;
        typedef boost::spirit::rule<ScannerT, ValueClosure::context_t> Context;
        Context expression, factor, group, literal, term;

        static void createBit(Context &context, Type n) {
            context.value = OperationPtr( new Operation::Bit<Type>(n) );
        }
        static void createNot(Context &context, OperationPtr op) {
            context.value = OperationPtr( new Operation::Not<Type>(op) );
        }
        static void createAnd(Context &context, OperationPtr op2) {
            context.value = OperationPtr( new Operation::And<Type>(context.value(), op2) );
        }
        static void createXor(Context &context, OperationPtr op2) {
            context.value = OperationPtr( new Operation::Xor<Type>(context.value(), op2) );
        }
        static void createOr(Context &context, OperationPtr op2) {
            context.value = OperationPtr( new Operation::Or<Type>(context.value(), op2) );
        }
    };
};
При попытке компиляции выдается страшная ошибка, что мол где-то внутри спирита void функция попыталась вернуть значение.
Проблема пропадает, если закоментировать все определения правил. Но смысла в этом нет.
Operation::Base - это абстрактный класс операции. Некоторые потомки принимают 1, а некоторые 2 параметра. В принципе, это несущественно. В принципе, Base - это нод дерева операций. Т.е. задача - построить дерево, которое будет обходиться каждый раз, когда мне то понадобится. Использование парсера для конечной обработки данных не подходит, так как данных очень много.

ошибки можно увидеть тут: http://pastebin.com/m1ad57c76

Автор: bsa 3.7.2009, 17:26
Проблема оказалась в bind...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)