2015-02-17 2 views
0

Я делаю дерево синтаксического анализа для простого интерпретатора. Вот код для узла в моем дереве разбора:Вектор динамического доступа C++ в векторе

struct rtok { 
    std::string type; 
    std::string val; 
}; 

struct rnode { 
    rtok tok; 
    vector<rnode> child; 
} node; 

vector<rnode> ptree; 

Как вы можете видеть, мое дерево разбора просто «вектор векторов». У меня также есть функции для вставки нового узла в дерево синтаксического разбора:

void add_term(rtok tok) { 
    rnode n; 
    n.tok = tok; 
    ptree.back().child.push_back(n); 
} 

Но проблема этой функции, она вставляет только элементы в ребенке вектор первого вектора. Т.е. как я могу заставить свою функцию динамически добавлять больше детей в дерево разбора? то есть Как я могу сделать свою функцию сделать что-то вроде этого:

ptree.back().child.back().child.back()...push_back(n) 

Если есть способ динамического добавления child.back(), что было бы здорово! Очевидно, я не думаю, что есть, но я надеюсь, что это иллюстрирует мою мысль.

+0

Пробовал ли вы использовать цикл или рекурсию? Я рекомендую. – user2079303

+0

@ user2079303 Я думал об этом, но я не был уверен, как бы я динамически добавлял «child.back()» в конец каждый раз, когда он зацикливался. – Francis

ответ

1

Вы хотите что-то вроде этого? Извините, если я неправильно понял ваш вопрос ..

struct rnode { 
    rtok tok; 
    vector<rnode> child; 
    rnode& back() { 
    // if our current node has empty child, return it 
    if (child.empty()) return *this; 
    // else recursive call this function for the last element of child vector of this node 
    else return child.back().back(); // use recursion to get the last non empty vector 
    } 
    rnode& unrolled_back() { 
    // get a pointer to the current struct 
    rnode* ptr = this; 
    // if the child has non empty vector, move pointer to its last element 
    while (!ptr->child.empty()) { 
     // get the address of the last element (we have checked that it has elements already) and assign it to ptr 
     ptr = const_cast<rnode*>(&(ptr->child.back())); 
    } 
    return *ptr; 
    } 
    void unrolled_push_back(const rnode& node) { 
    // get the last structure that has empty child vector 
    auto& last = unrolled_back(); 
    // add element to it's child 
    last.child.push_back(node); 
    } 

    void push_back(const rnode& node) { 
    if (child.empty()) child.push_back(node); 
    else return child.back().push_back(node); // use recursion to get the last non empty vector 
    } 
} node; 

int main() { 
    rnode node; 
    auto& r1 = node.back(); 
    assert(&r1 == &node); 
    node.push_back(rnode()); 
    node.push_back(rnode()); 
    auto& r2 = node.back(); 
    assert(&r2 == &(node.child.back().child.back())); 
    assert(!(&r2 == &(node.child.back()))); 
    return 0; 
} 

Note, howerever, что эта функция будет вылетать, если глубина рекурсии будет высоким, поскольку размер стека ограничен. Таким образом, можно получить stackoverflow.

+0

Насколько велика, по-вашему, дерево разбора должно быть до того, как произойдет переполнение стека? С его стороны интерпретатора, вы думаете, что «нормальные» программы будут разбивать его? – Francis

+0

@Francis вижу мое обновление, я добавил функции, развернутые в цикле. Безопасно использовать их, потому что у них нет рекурсии вообще. –

+0

Прошу прощения, если я прошу многого, потому что я очень ценю вашу помощь, но сможете ли вы кратко объяснить мне свой код? Я не знаком с C++. – Francis

Смежные вопросы