как в C, NASM)? А точнее, что делать после токенизации и как хранить получившийся документ и перестановки (чтоб как С компилятор, получив сформированный препроцессором инпут, можно было в диагностиках писать, что откуда и почему expanded да ещё и с указанием настоящих позиций в тексте)
Можно почитать коммиты в chibicc, начиная примерно отсюда
О, спасибо! Попробую
Кстати, если тут стадии указаны в порядке, то получается, что препроцессор встроен во фронтенд компилятора, так как токенизация и одна и на препроцессор и на сам исходный текст для компилятора. Так же вроде не принято делать?
Кстати, если тут стадии указаны в порядке, то получается, что препроцессор встроен во фронтенд компилятора, так как токенизация и одна и на препроцессор и на сам исходный текст для компилятора. Так же вроде не принято делать?
Или можно здесь посмотреть https://github.com/romart/EduCC/blob/master/src/pp.c и задать вопросы где не понятно
Технически препроцессор это часть лексера, он получает на вход поток "raw" - токенов, преобразует его в другой поток и отдает в парсер. Правила преобразования можно определять самому с помощью макросов и директив
> препроцессор встроен во фронтенд компилятора а куда его еще встраивать, до парсера должны дойти токены уже после препроцессинга
а лексер это не часть фронтенда?
В GCC так и есть :)
Для фортрана. Для сишечки- нет
У меня сложилось впечатление, что в очень любят рассказывать про то что компилятор это что-то отдельное, парсер отдельно
Хотя в chibicc препроцессор отделен от лексера и парсера, это отдельный проход по потоку токенов вида (map expand raw_tokens). Так просто проще делать, не надо заморачиваться с лексическим стеком
Парсер - да. А вот препроцессор в современных компиляторах - часть парсера
В каких компиляторах это часть парсера? Может все-таки лексера?
Ок, лексера (я парсинг в более глобальном смысле имею ввиду). Но в том же гцц лексер и парсер несколько переплетены
потому что это СИ, и там иначе никак. Но это именно на уровне lexer-hack, и препроцессор к этмоу переплетению отношения не имеет
Я с этим и не спорю. Кстати, в clang, если я правильно понял, обошлись без lexer hack
ну как, выше головы не прыгнешь, там просто лексер выдает что-то общее типа ID кажется, а парсер сам у себя решает что это такое. В любом случае токен, определение типа которого задача лексера, определается в парсере по информации из семантики. Суть то та же
Суть да. Но сделано красивее
да, мне такой подход тоже нравится. Я в данном случае под "lexer hack" понимаю не конкретную реализацию а сам факт того что для правильного определения типа токена нужно залезать на уровень семантики сквозь парсер
А lcc для фортрана GNU-шную libcpp вызывает или пользуется препроцессором от EDG?
Хз. Никогда не проверял
А ведь надо бы :)
Получается, есть три сценария: 1. [препроцессор + компилятор] парсить исходный кода в rawTokens с учетом сразу и препроцессора, и компилятора. Тогда, эти токены скармливаем препроцессору он выдает некую другую последовательность токенов (с информацией о перестановках) и эти токены уже скармливаем в компилятор 2. [компилятор] получаем последовательность rawTokens токенов где, уже нет токенов препроцессор, но есть информация о перестановках и собственно компилируем 3. [только препроцессор] парсим в rawTokens с учетом только токенов для препроцессор и выдаем наружу (в виде простого потока (для человеков) или опять таки с релокациями для дальнейшего использования) Я думал сделать 2 и 3. А 1 реализовать через 2 > 3. А то если в 1 сразу парсить и для препроцессора, и для компилятора - то как-то сложно, наверное. И долго (если пользователю только препроцессор нужен, и может он его запускает для своих нужд каких-то (какие-то свои языки им собирает))
а зачем компилятору знать о том что там куда переставлялось? сам препроцессор может сказать, что и куда было expanded
диагностики как минимум выдать и отладочную информацию правильно построить
А cpp это что тогда?
ну да, можно конечно и так сделать, просто на практике оказывается удобнее делать все вместе. Но если вы хотите сделать сишный компилятор то сначала сделать без PP вполне допускается, потом просто допилите что нужно или внешний возмете как тут уже предлагалось
Запросто. Ибо в основном от университетских преподователей и слышал)
Есть CoCo, но обычно все пользуются ссишным, причем тем, что до стандарта был
Ммм? Не понял. В этом подходе компилятор получив последовательность rawTokens без информации о перестановках от препроцессора и захотев понять, что откуда expanded (например, для вывода диагностики) должен пойти в препроцессор (с чем? с ранее полученными rawTokens без информации о перестановках) и спросить, а помнишь ты вот что-то препроцесил, вспомни и скажи что и куда) Надо выходит таки где-то эту информацию хранить таки
Наверное. Это имел ввиду man7.org/linux/man-pages/man1/cpp.1.html
Потому что сишные макросы могут использоваться не только в си
Реальная история: когда-то для одной компании я написал ассемблер для VLIW-процессора. Но часть задач переложил на сторонний С-препроцессор. Пользователи были вполне довольны — не пришлось изучать новый синтаксис для создания макросов :)
Обсуждают сегодня