Ерунда эти все инструменты. Кроме каких-нибудь студентов, или там аспирантов, ими никто серьёзно не пользуется. Я имею в виду, что если взять какой-нибудь серьёзный широко известный компилятор, то можно обнаружить, что там внутри всё very custom, а не very classic.
burik писал(а):Каждое правило (как уже писал Хакер) можно реализовать в виде функции, которой в качестве параметра передается входной поток токенов. Функция эта может просто возвращать булевское значение (подходит ли входной поток под правило), может возвращать и некоторый объект (например, AST дерево, дерево разбора и т.п.).
Я такого никогда не говорил. Я совершенно другое говорил. Я говорил, что должно быть семейство функций (с каждой из которых может быть, а а может и не быть ассоциирована доп. таблица). Каждая парочка функция + таблица — по моей терминологии «роутер».
Диспетчер вызыват роутер. Роутер получает указатель (или не указатель) на контекст процессинга. Контекст всецело зависит от задачи решаемой сейчас конструкцией из множества роутеров. У каждого роутера задача примитивна: посмотреть на контекст и, в зависимости от него, вернуть адрес следующего роутера, которого разгребать это всё дальше. Роутер при этом может изменить что-то в контексте (например передвинуть какой-нибудь указатель/счётчик в контексте на единичку вверх (или не вверх, а вниз, или не на единичку), или просто добавить что-нибудь куда-нибудь (какой-нибудь элемент в какой-нибудь список). Я это называю — побочный эффект работы роутера.
В общем, роутер получает контекст, смотрит на него, делает сайд-эффект (опционально) и возвращает информацию о том, какой роутер должен разгребать всё это дальше. То есть да, роутер может вернуть указатель на самого себя и тогда он будет вызван ещё раз.
Сам процесс обработки кода разбивается на этапы-слои. Каждая конструкция из роутеров обрабатывает только свой слой.
Самую большую глупость из данной области, которую я только видел, и которую постоянно вижу там или иначе: стремление написать одну единственную функцию, которая сделают всю работу сразу. То есть получит на вход некоторый код, а на выходе сразу даст дерево разбора и вспомогательне таблицы/словари.
Это шизофренично. Разбивайте задачу на слои. Делайте компоненты, которые получают поток сущностей (ни в коем случае речь не о токенах, речь об абстрактных сущностях в контексте программирования вообще), и выдают поток сущностей. Делая редкие малые изменения или даже, в каких то случаях, не делая вообще никаких изменений. Своеобразный приём из Unix-Way: куча мелких программ, которые делают одну маленькую задачу, но делают её хорошо. А вы потом берёте эти программы, и организуете конвеер:
- Код: Выделить всё
cat input_data | tool1 | tool2 | tool3 | tool4 | tool5 | tool6 | > output_data
Для тех, кто не понял намёка: я абсолютно не не имею в виду, что вы должны писать компоненты разбора в виде отдельных маленьких программ, которые бы потом запускали в конвейере используя пайпы. Я о том, что у вас должна быть такая же архитектура разбора, состоящая из компонентов, который принимают вывод предыдущего компонента, и дают свой вывод на вход следующему компоненту. Все компонененты должны быть изолированы друг-от-друга на уровне кода (вообще говоря, они не кому не должны, но если у вас так — вы на правильном пути).
У вас не должно возникать вопроса о том, как написать функцию, которая из исходного кода сгенерирует дерево разбора.
У вас должен возникнуть вопрос о том, как написать функцию, которая делает 1-ый этап, 2-ой этап, 3-ий этап, 4-ый этап... и так далее, сколько этапов вы у себя сделаете.
Решение каждого этапа — сложная, но интересная задача, и каждый этап будет использовать отличные от других принципы функциониварояни.
А вот если у вас возникнет вопрос о том «как написать функцию, которая из исходного кода сгенерирует дерево разбора», то ответ будет таким: взять исходные данные и применить к ним последовательно все этапные функции, которые у вас там есть в проекте.
_______
Что касается вообще подхода, как «взять исходный код, и, пусть и поэтапно, но сделать из него дерево разбора». Вот VB и VBA вообще не используют этот подход. Эти продукты никогда не пробегают по коду и не разбирают их в дерево. Вместо этого они перестраивают дерево по мере правки кода.
Да и нет там дерева, как такового. Есть пресловутые этапы. Часть этапов выполняется по мере правки кода в среде (номера которых ближе к единице). Часть этапов выполняется при нажатии кнопки «Run» или «Compile».
[url=bbs.vbstreets.ru/viewtopic.php?f=9&t=43832]Почитай, как оно устроено[/url].
Разработчики VB/VBA имели смелость не только не использовать готовые неприятные инструменты ANTLR, Lex и Yacc. Они имели смелость заложить в свой продукт вообще такой принцип работы, который нигде в мире больше не используется.
Это сделало VB/VBA — продуктом, в котором
очень быстрое, самое быстрое из всего, что есть, время компиляции больших проектов.
И это же сделало VB/VBA — продуктом, в котором
очень медленное время загрузки больших проектов.
Потому что при компиляции практически ничего не делается (все изменения внутренних структур (деревьев, таблиц, словарей) происходят при правке кода, а не при нажатии кнопки «Compile»), и потому что при загрузке проекта всё это надо построить с нуля.
И знаете, я ставлю 5 баллов за такое решение: ибо в процессе работы программиста ему приходится компилировать свой проект в своей среде разаработке в 10 или 100 раз чаще, чем открывать свой проект с своей среде разработки.