На веб-сайте ANTLR описаны два подхода к реализации директив включения. Первый подход состоит в том, чтобы распознать директиву в лексере и включить файл лексически (поместив CharStream в стек и заменив его тем, который считывает новый файл); второй — распознать директиву в анализаторе, запустить вспомогательный анализатор для анализа нового файла и вставить AST, сгенерированный вспомогательным анализатором. Ни то, ни другое не совсем то, что мне нужно.
В языке, который я разбираю, распознавание директивы в лексере нецелесообразно по нескольким причинам:
- Не существует самостоятельного шаблона символов, который всегда означает «это директива включения». Например,
Include "foo";
на верхнем уровне — это директива включения, но вArray bar --> Include "foo";
илиConstant Include "foo";
словоInclude
является идентификатором. - Имя включаемого файла может быть задано в виде строки или идентификатора константы, и такие константы могут быть определены с помощью произвольно сложных выражений.
Итак, я хочу вызвать включение из парсера. Но чтобы выполнить включение, я не могу запустить вспомогательный парсер и соединить AST вместе; Я должен склеить жетоны. Блок может начинаться с {
в основном файле и заканчиваться на }
во включаемом файле. Файл, включенный в функцию, может даже закрыть определение функции и запустить новое.
Похоже, мне понадобится что-то вроде первого подхода, но на уровне TokenStreams вместо CharStreams. Это жизнеспособный подход? Сколько состояний мне нужно будет хранить в стеке и как заставить синтаксический анализатор переключаться обратно на исходный поток токенов, а не завершать работу, когда он достигает EOF? Или есть лучший способ справиться с этим?
==========
Вот пример языка, демонстрирующий, что блоки, открытые в основном файле, могут быть закрыты во включаемом файле (и наоборот). Обратите внимание, что #
перед Include
требуется, когда директива находится внутри функции, но необязательна снаружи.
основная.инф:
[ Main; print "This is Main!"; if (0) { #include "other.h"; print "This is OtherFunction!"; ];
другое.ч:
} ! end if ]; ! end Main [ OtherFunction;
Constant
. Определение, данноеConstant
, должно быть константой времени компиляции, поэтому никаких вызовов функций. В языке также нет текстовых операторов, поэтому нет конкатенации, но он может дублировать другую константу:Constant FOO "file.h"; Constant BAR FOO; Include BAR;
- person Jesse McGrew   schedule 24.08.2012Constant
вообще может иметь сколь угодно сложные выражения, так как она обычно используется с числами:Constant FOO (BAR + 5 * BAZ);
и т. д., поэтому обработкаConstant
в лексере нецелесообразна. - person Jesse McGrew   schedule 24.08.2012