Вообщем решил разобраться с тем, каким должен быть нормальный компилятор и попробовать свой написать. Не расчитываю на что-то настоящее, но для начала хотя бы вывод дерева разбора в ASCII.
Собственно мне в GNU компиляторе C и pcc не нравится выделенный отдельно препроцессор(cpp). Стандарт C99 вообще описывает директивы препроцессора как часть языка.
Глянул тут на описание компиляторов Plan 9 from Bell Labs. Собственно в Plan 9 есть отдельный препроцессор, но он компиляторами не используется. Компиляторы используют встроенный препроцессор, совмещенный с лексическим анализом(как и предполагает стандарт). В gcc препроцессор выделен в отдельную стадию до лексического анализа, при этом остается #pragma для обработки компилятором. Если бы не #pragma, то можно было бы разделить стадии, но из-за нее в лексическом анализаторе частично дублируется функциональность препроцессора. Это вообще выглядит как хак, и я больше доверяю Bell Labs, как разработчикам языка C.
Собственно сама статья, которую я читаю: http://cm.bell-labs.com/sys/doc/compiler.html Тут вот описывается, каким образом директивы препроцессора удалось встроить в парсер на yacc:
>5.1. Parsing > >The first pass is a YACC-based parser [Joh79]. Declarations are interpreted immediately, building a block structured symbol table. Executable statements are put into a parse tree and collected, without interpretation. At the end of each procedure, the parse tree for the function is examined by the other passes of the compiler. > >The input stream of the parser is a pushdown list of input activations. The preprocessor expansions of macros and #include are implemented as pushdowns. Thus there is no separate pass for preprocessing.
У меня небольшие проблемы с переводом второго абзаца. pushdown list - это стек или что? Что такое input activations, pushdown и pushdown list?