2011-01-10 6 views
4

Я использовал Ци и Карму, чтобы выполнить некоторую обработку на нескольких небольших языках. Большинство грамматик довольно малы (20-40 правил). Я мог использовать autorules почти исключительно, поэтому мои деревья синтаксического анализа состоят исключительно из вариантов, структур и std :: векторов.Boost :: Spirit :: Qi autorules - избегание повторного копирования структур данных АСТ

Эта установка работает отлично подходит для общего случая:
1) разобрать что-то (Qi),
2) внести незначительные манипуляции к дереву синтаксического анализа (посетителя), и
3) выход что-то (карма).

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

Грамматика для s-выражение в стиле логических выражений, которые использует autorules ...

// Inside grammar class; rule names match struct names... 
pexpr %= pand | por | var | bconst; 
pand %= lit("(and ") >> (pexpr % lit(" ")) >> ")"; 
por %= lit("(or ") >> (pexpr % lit(" ")) >> ")"; 
pnot %= lit("(not ") >> pexpr >> ")"; 

... что приводит к синтаксический представление дерева, которое выглядит, как это ...

struct var { 
    std::string name; 
}; 
struct bconst { 
    bool val; 
}; 

struct pand; 
struct por; 
struct pnot;        

typedef boost::variant<bconst, 
         var, 
         boost::recursive_wrapper<pand>, 
         boost::recursive_wrapper<por>, 
         boost::recursive_wrapper<pnot> > pexpr; 
struct pand { 
    std::vector<pexpr> operands;      
}; 

struct por { 
    std::vector<pexpr> operands;      
}; 

struct pnot { 
    pexpr victim; 
}; 

// Many Fusion Macros here 

Пусть у меня есть дерево разбора, который выглядит примерно так:

 pand 
    /... \ 
    por  por 
/\ /\ 
var var var var 

(T он эллипсис "гораздо больше детей подобной формы для pand. средства)

Теперь предположим, что я хочу свести на нет каждый из por узлов, так что конечный результат:

 pand 
    /... \ 
    pnot  pnot 
    |  | 
    por  por 
/\ /\ 
var var var var 

Прямой подход будет для каждого por подзаголовок:
- создать pnot узел
(копии por в строительстве);
- переустановите соответствующий векторный слот в pand узел
(копия pnot узла и его por поддерева).

В качестве альтернативы, я мог бы построить отдельный вектор, а затем заменить (обменивать) векторный вектор pand, исключив второй раунд копирования.

Все это кажется громоздким по сравнению с представлением дерева на основе указателя, которое позволяет вставлять узлы pnot без копирования существующих узлов. Мой вопрос:

Есть ли способ избежать манипуляций с тяжелым деревом с использованием данных, соответствующих требованиям автовладельца? Должен ли я укусить пулю и просто использовать неавторатуры для создания АСТ на основе указателей (например, http://boost-spirit.com/home/2010/03/11/s-expressions-and-variants/)?

ответ

3

Копирование поддеревьев не должно быть таким дорогостоящим, как вы предполагаете, поскольку рекурсивный_вариант является по существу оберткой вокруг shared_ptr. Я считаю, что это не только лучшее, но и самое простое решение.

+1

Спасибо за понимание. Я не обратил внимания на вариант реализации.Я проверил быстрый эксперимент, чтобы проверить, какие операции вызывают копирование: - вставка узла между двумя существующими узлами вызывает постоянное количество копий ops (оно не растет с размером поддерева под вставкой); - наибольшее копирование вызвано изменением вектора С учетом сказанного может быть, что было бы неплохо иметь прямую поддержку, например, для узлов AST, основанных на пуле, не требующих шаблонных семантических действий. Одним из приятных свойств этой установки является то, что адреса узлов можно использовать как дешевый уникальный хеш. – phooji