Имею поток токенов, которые образовались при парсинге вложенных структур:
{
some;
{
some2;
}
some3;
}
вложенность неограничена. Как сделать так, чтобы лексер входил в рекурсию, парсил содержимое внутренного блока (он входит, когда видит левую скобку), но когда выходил (он при выходе попадает на следующий токен), пропускал содержимое внутреннего блока, а приступал к следующему за ним токену? Деревья тут при том, что я их строю из потока, после предобработки.
//вызов 2
lex("{
some2;
} // - тут он выходит
some3;
}")
Как сделать так, чтобы после выхода из вызова 2 и возвращении в вызов 1 он приступал к парсингу some3, а не снова к «{ some2; }»?
Решение лежит на поверности, но я его почему-то в упор не вижу.
он когда видит «{» входит в lex(оставшаяся часть строки). Потом, когда видит «}» выходит. И list->next становится токеном, следующим за «{» и «{»->next, в данном случае - some4
Я понял. Сделай отдельно лексер, который будет разбирать строку. Грубо говоря, функция get_next_token(). И парсер, который ей пользуется. Построение дерева получится само-собой.
а можно поинтересоваться, почему вы при входе во вложенную структуру (COMPLEX_STRUCT) не плюсуете struct_level, а при выходе минусуете? Впрочем, это не очень важно. Так же вы плюсуете в случае вложенной структуры (COMPLEX_STRUCT) struct_inside, однако минусуете его всегда. Я конечно не знаю, что у вас там за дерево строится, но, имхо, со счетчиками у вас беда.
>Как сделать так, чтобы лексер входил в екурсию, парсил содержимое внутренного блока
Задача и смысл существования лексера - бить вход на токены.
Парсингом должен заниматься парсер.
Куда более корректно вопрос звучал бы:
Какую грамматику должен реализовать парсер чтобы, он «пропускал содержимое внутреннего блока, а приступал к следующему за ним токену?»
Ну как-то так имхо. И ответ и код на поставленный вопрос довольно просты.
У тебя вроде бы логическая накладка:
раз: вложенность неограничена.
два:внутренного блока
три: пропускал содержимое внутреннего блока
пропускать содержимое какого из внутренних блоков?
Ого! Ты физическое АСТ построил!
Это практически необходимо???
Короче, походу не совсем верная последовательность действий, имхо.Я бы делал так:
1. сформировать вход для парсера
2. рекурсивно выделить в анализируемом потоке диапазон, соответствующий вложению
3. для каждого или некоторого из диапазонов выстроить дереао.
У тебя вроде как наоборот - ты сделал дерево и теперь не знаешь что с ним делать, ну в смысле - стопорнулся на алгоритме перехода к ближайшему листу из заданного узла.
Да, это практическая необходимость. Если делать 1-2-3, то это медленнее и больше памяти надо, вроде. Я пытаюсь совмещать все, значит надо просто передавать параметр указатель на следующую позицию, после выхода из рекурсии. Попробую так.
Лексеры (lex или что у тебя там) работают с регулярными(или т.н. автоматными) языками, то есть, грубо говоря с «плоскими», которые парсятся однопроходными DFA.
Что значит «слишком большой»?
Посмотри на свой код сначала, это же огромная и вообще ужасная и непонятная каша, просто понос из буковок какой-то.
А вообще, yacc/bison генерируют автоматы для LALR-парсеров - снаружи выглядит м.б. жестковато, но работает быстро(O(n) от размера ввода), быстрее чем тот хлам, который ты сделал, ну а по памяти там O(n) от глубины дерева разбора, что тоже не сильно много, учитывая что внутренние структуры парсеров небольшие.
Но если так приперло _не_использовать_ генератор парсеров(хотя это просто луддитство, так как генератор будет наилучшим выбором в твоем случае), то, если язык позволяет, можно задрочиться, привести грамматику к LL(1)-виду(left-factoring плюс устранение левой рекурсии), и написать простой предиктивный рекурсивно-нисходящий парсер по LL(1);
Но вот если язык к LL(1) не приводим, то придется написать рекурсивный нисходящий парсер с бэктрекингом(и это будет дико тормозить), либо с мемоизацией(т.н. packrat-парсер, и это будет дико жрать память), а ведь всего-то надо было взять генератор по LALR(1).
Просто пойми, по-другому твою задачу не решить никак.
Нельзя немножко подкрутить лексер и довести его до разбора такого текста, как у тебя.
Это все-равно что пытаться распарсить HTML регексами - в итоге выйдет куча говнокода(типа как твоя куча выше), которая либо просто не работает, либо криво велосипедит один из давно известных алгоритмов, для которого и так существует куча реализаций.
Вот прислушайся уж ко мнению, сделай одолжение. Разбор текста, содержащего структуру, это одна из моих основных специализаций, и с этим связан мой будущий стартап, для которого я уже сейчас пишу код.