Boost Spirit, как получить доступ к дочерним узлам (листьям) из родительских узлов

Я хотел бы оценить логическое выражение, такое как a = b & s ‹9 или просто a = b, только с оператором сравнения (без логического оператора, такого как |, & и!). У нас может быть следующий AST:

            =
           / \
          /   \
          a    b 

or

               &
              / \  
             /   \
            =     <
           / \    /\
          /   \  /  \
          a    b s   9   

Узлы листьев - это значения. Родителем узлов выхода всегда является оператор сравнения, например =,! =, ‹,>,> =,‹ =. Родителем узлов сравнения являются логические операторы |, & и!. Я хотел бы получить доступ к узлам значений (листьям) из их родительского узла, а затем передать эти значения другой функции (которая будет реализована позже). Шаг синтаксического анализа в порядке.

Как получить доступ к узлам значений (листьям) из их родительского узла. Я использую примеры по адресу: Как вычислить логическое выражение в Spirit < / а>

и синтаксический анализатор логических выражений (грамматики) в c ++ Это код оценки взят из этих ссылок:


    struct eval : boost::static_visitor<bool>
{
    eval() {}

    //
    bool operator()(const var& v) const
    {
        std::cout<<"feuille:\n"<<v<<std::endl;
        return true;
    }

    bool operator()(const binop<op_and>& b) const
    {
        recurse(b.oper1) && recurse(b.oper2);
    }
    bool operator()(const binop<op_or>& b) const
    {
        recurse(b.oper1) || recurse(b.oper2);
    }
    bool operator()(const unop<op_not>& u) const
    {
        return !recurse(u.oper1);
    }

    //------------adding others operators----------------------------
    bool operator()(const binop<op_equal>& u) const
    {
        // will be implemented later
        return true;
    }

    bool operator()(const binop<op_not_equal>& u) const
    {
       // will be implemented later
        return true;
    }

    bool operator()(const binop<op_less>& u) const
    {
        // will be implemented later
        return true;
    }

    bool operator()(const binop<op_less_equal>& u) const
    {
        // will be implemented later
        return true;
    }

    bool operator()(const binop<op_greater>& u) const
    {
        // will be implemented later
        return true;
    }
    bool operator()(const binop<op_greater_equal>& u) const
    {
        // will be implemented later
        return true;
    }


Спасибо. Любые предложения приветствуются.


person user2891256    schedule 18.10.2013    source источник


Ответы (1)


Вы смотрели на другие перегрузки оценки для существующих операторов? Вы заметили, как они получили значение своих операндов (которые на самом деле могут быть подвыражениями)?

Возьмем для примера двоичный код или:

bool operator()(const binop<op_or>& b) const
{
    return recurse(b.oper1) || recurse(b.oper2);
}

Как видите, он просто применяет || к значению обоих операндов. Это значение не найдено в AST [1]. Итак, мы рассматриваем каждый операнд как выражение и просто рекурсивно вызываем для него метод eval.

Поскольку тип выражения является вариантом, вызов eval фактически применяет посетителя к варианту, а я уже написал полезную оболочку, которая делает это, поэтому recurse легко:

private:
template<typename T>
    bool recurse(T const& v) const 
    { return boost::apply_visitor(*this, v); }

Итак, не зная остальной части вашей грамматики, но предполагая, что вы расширили ее в том же духе, что и существующая грамматика:

bool operator()(const binop<op_equal>& u) const {
    return recurse(b.oper1) == recurse(b.oper2);
}

было бы примерно правильно. Обратите внимание, что с помощью умного макроса вы можете сделать это очень быстро:

struct eval : boost::static_visitor<value> {

    // terminal
    value operator()(const var& v) const {
        std::cout<<"feuille:\n"<<v<<std::endl;
        return true; // TODO get value from var
    }

    // unary operator
    value operator()(const unop<op_not>& u) const { return !recurse(u.oper1); }

    /*
     * binary operators
     */
#define EXPR_DEF_BINOP(tag, op) \
    value operator()(const binop<tag>& u) const { \
        return recurse(b.oper1) op recurse(b.oper2); \
    }

    EXPR_DEF_BINOP(op_and,           &&)
    EXPR_DEF_BINOP(op_equal,         ==)
    EXPR_DEF_BINOP(op_greater,       >)
    EXPR_DEF_BINOP(op_greater_equal, >=)
    EXPR_DEF_BINOP(op_less,          <)
    EXPR_DEF_BINOP(op_less_equal,    <=)
    EXPR_DEF_BINOP(op_not_equal,     !=)
    EXPR_DEF_BINOP(op_or,            ||)

#undef EXPR_DEF_BINOP

  private:
    template<typename T>
        value recurse(T const& v) const 
        { return boost::apply_visitor(*this, v); }
};

Еще несколько примечаний:

  • Я добавил TODO к функции оценки листового узла
  • Я поменял тип на valuebool). Это потому, что ваша грамматика поддерживает небулевы выражения, иначе операторы <= и >= не имели бы смысла. [2], поэтому у вас будут значения разных типов (тоже ):

    using value = variant<bool, int32_t>;
    

    Остальное я оставлю тебе


[1] Помните, что AST = абстрактное синтаксическое дерево: это представление источника 1: 1. («Половина исключения» будут литералами, хотя вы все равно должны указать оценщику, как использовать значение литерала.)

[2] возможно

  • a<b может означать !a && b
  • a>b может означать !b && a
  • a!=b может означать a XOR b
  • a==b может означать !(a XOR b)
person sehe    schedule 18.10.2013
comment
Полезный! Мне интересно, как примеры логических выражений могут поддерживать Unicode. Я пробовал: - person user2891256; 19.10.2013
comment
Полезный! Мне интересно, как примеры логических выражений могут поддерживать Unicode. Я пробовал использовать: template ‹typename It, typename Skipper = qi :: standard_wide› в функции оценки (см. Исходные ссылки) вместо template ‹typename It, typename Skipper = qi :: space_type›. Спасибо. - person user2891256; 19.10.2013
comment
Вы не можете просто заменить шкипера на кодировку (IIRC standard_wide - это даже пространство имен?). Вместо этого просто ищите информацию . Unicode имеет мало общего с логическими выражениями. Да и с wstring, если на то пошло. Это выглядело довольно ясно - person sehe; 19.10.2013