смотри документацию.
Лексер, который бьёт исходный код на список токенов самописный. Пытался использовать генераторы, но не разобрался. Не смог написать грамматику с всеми диагностиками. Да и просто не понял как хранить и актуализировать позицию (line:col)
Тогда, если у тебя игрушка: просто добавь в структуру токена тестовое поле со значением токена.
Да поле-то добавить можно. Осталось его когда-то как-то заполнить. Получается, что после фазы lex, будет какая-то фаза (как она называется? Что можно о ней почитать?) когда буду пробегаться по всему массиву токенов и вычислять «значения токенов» для литералов (а для не литералов и не нужно) и, собственно, заполнять само это поле
Вы, когда лексему выделяете, Вы уже знаете её положение в коде и её длину. А больше ничего и не нужно
Эм. Мне вот уже нужно для препроцессора) Например, чтобы осуществить раскрытие макроса. Да и сама директива (напр. #if), тоже может содержать некоторое выражение с числовыми литералами
Хорошо. А как это меняет положение лексемы в коде?
Именно, что совершенно никак. По типу, положению токена в коде (и по его длине) я не могу понять, например, этот идентификатор надо не трогать, или это вызов макроса и нужно совершить определённые действия
Отлично, это и не надо в лексере понимать. Тогда что вызывает проблему?
Но ведь ваш препроцессор видит только исходный код или нет? Не понимаю, когда ваш лексер проходит по коду после препроцессора он вычисляет как-то начало и конец лексемы или берет их как есть, т.е. как увидел в новом коде? В таком случае можно сделать чтобы у препроцессора были свои лексемы со своими значениями, а уже у лексера основного языка - свои. Ну и можно оптимизировать т.е. заставить препроцессор обновлять последовательность лексем, а не генерировать заново с чистого листа. Копировать значения два раза неэффективно, если так хочется владеющих лексем, то можно и правда отдельным проходом уже после отработки всех лексеров. В литературе этот шаг, насколько я знаю, не выделяют, можно отнести это к деталям реализации лексера.
> Василий: Тогда, если у тебя игрушка: просто добавь в структуру токена тестовое поле со значением токена. >> Я: Да поле-то добавить можно. Осталось его когда-то как-то заполнить. Получается, что после фазы lex, будет какая-то фаза (как она называется? Что можно о ней почитать?) когда буду пробегаться по всему массиву токенов и вычислять «значения токенов» для литералов (а для не литералов и не нужно) и, собственно, заполнять само это поле >>> Alex: Вы, когда лексему выделяете, Вы уже знаете её положение в коде и её длину. А больше ничего и не нужно Вот на это я и отвечаю, что к сожалению «больше ничего и не нужно» не получается, ибо, например, нужно знать, что там за идентификатор. И спрашиваю в какой фазе вычисляются эти «значения токенов». Как она называется (aka что загуглить) и что можно об этом почитать?
1. Нету понятия "значение токена" 2. Начать читать книгу дракона 3. Фаза называется лексический анализ 4. К фазе синтаксического анализа вся необходимая информация у Вас есть
Разбитие на лексеммы - обычно лексический анализ, анализ лексемм - синтаксический, а после всего - семантический
Так, предполагается, что фаза препроцессора идет после лексера. Вроде же так и делают, нет? Сначала, лексер выдаёт список токенов, а потом над ним колдует препроцессор. Вы, вот вижу, наоборот предлагаете...
Обычно наоборот (для простых лексеров). Сложные делать пока не стоит
1. Не подскажите, какой термин используют для этого понятия? 2. Да, спасибо. Все никак не собирусь. Хотя, боюсь, там несколько другая архитектура нежели чем у меня 3. Вы предлагаете в фазе лексического анализа и бить исходный текст на послеовательность токенов, и вычислять "значения токенов". Уже писал выше, что кажется, многие генераторы именно так и делают 4. Круто. Мне правда, еще до фазы препроцесора это нужно. Но это уже детали
Да? Мне прям в этом же чате, если не ошибаюсь, говорили вот как я написал. Что препрок принимает последовательность токенов и ими манипулирует. А дальше уже отдает на следюущие фазы
Крайне интересное утверждение)
1. Так я не понимаю, что Вы подразумеваете. Подозреваю, что имеется ввиду "лексема". 2. "архитектура" работы фронтенда почти не меняется уже лет 30-40. Если у Вас поменялась - следует задуматься. 3. Всё так делают, потому что иначе сделать как минимум проблематично
2. Подозреваю, "архитекутра" у разных компиляторов* разная. Особенно у не игрушечных
А как в принципе это можно сделать наоборот? Т.е. сначала препроцессор, а потом лексер. Мы в этом же чате пришли к выводу, что лучше писать один лексер «на все случаи» (а не два, один для препроцессора, другой для этого оутпута). И даже если мы пишем два лексера, все равно сначала идет стадия лексического анализа первого лексера, а потом уже препроцессор
Вот и я о чем. Когда смотришь на реальные компиляторы ("не игрушечные"), то и "архитектура" там какая "не правильная" может оказаться. Ни как в книжке
> Так, предполагается, что фаза препроцессора идет после лексера. Вроде же так и делают, нет? Это зависит от [спецификации] языка, между прочим. (Подозрительно) А Вы фазы со стадиями не путаете, случайно? Фазы идут строго друг за другом только концептуально, если что — обычно preprocessor, lexer, parser и первый этап "семантического" анализа работают одновременно, просто вызывая друг друга. > Хотя, боюсь, там несколько другая архитектура нежели чем у меня Послушайте доброго совета: пока Вы новичок — делайте так как там написано, потому что на всех прочих путях Вас ждёт СТРАДАНИЕ. ;) Не то чтобы делать иначе невозможно (и возможно, и делают), но для этого нужен опыт/знания и особые потребности.
1. А могу ли у Вас спросить, что такое стадии в этой дихотомии (стадии vs фазы)? Когда читал стандарт Си мне показалось, что фазы это вообще некий абстракт. Декларация намерений. А точнее некоторый объяснительный конструкт, который нужен только для объяснения гарантий, который данный язык дает программисту. А уж внутри как сделано, черт знает. Что, впрочем, не удивительно, с учетом что это спецификация языка, а не компилятора) 2. Да, большое спасибо за совет касательно пути обучения. Надеюсь, когда-то я именно так и поступлю, и у меня получится нормальный, обычный компилятор, который берет и компилирует исходный код в исполняемый (ну или хотя бы в байт код какой-нибудь широко используемой машины) Пока что, однако, столкнулся с тем, что даже лексер проще написать свой (благо спасибо за assembly-like синтаксис), чем разбираться в существующих генераторах лексеров. Но, признаюсь, очень хотелось чтоб все было как у серьезных дядек на lex & yacc
"архитектура" как раз таки одна (уж не знаю, что Вы поджтим словом подразумеваете). Для отдельных стадий могут различаться подходы и алгоритмы
Как вам уже сказали - не смотрите. Делайте по книге - научитесь правильно. А неправильно вас пацаны в подворотне на галере и сами научат
По препроцессору - очень зависит от того, какой у вас препроцессор. Если смотреть в Си, то там фаза препроцессировпния идёт до лексического анализа (хотя технически и встроена в лексер). Иногда могут быть сложные препроцессор, работающие на дас, но Вам этого не нужно
Ну не все же такие. OCaml по классической, книжной схеме сделан. И вполне себе работает.
> 1. А могу ли у Вас спросить, что такое стадии в этой дихотомии (стадии vs фазы)? Я имел в виду, что стадии — это то, что в самом деле деле следует друг за другом (впрочем, в русском языке эти слова могут быть синонимами, так что...). > Когда читал стандарт Си мне показалось Это же понятия не из стандарта C, а из общей архитектуры компиляторов. Но да, "фаза" — это некий абстракт. По идее, реализация фаз как стадий всегда должна быть принципиально возможна (более того, результат работы транслятора должен быть по сути неотличим от того, как если бы они там были). Т.е., если бы это были стадии (как это работает концептуально): 0. [Примитивные] preprocessors: выполнили текстовые подстановки макросов в исходном коде, получили текст с "раскрытыми" макросами, исходный текст выкинули. 1. Лексический анализ: преобразовали текст с "раскрытыми" макросами в "поток" (или даже массив, для non-directional parsers) tokens, сам текст выкинули. 2. Синтаксический анализ (parsing): преобразовали массив токенов в Concrete Syntax Tree (parse tree), массив лексем выкинули. 3. CST postprocessing / создание AST: преобразовали CST в AST (проходом по нему), CST выкинули. 4. Семантический анализ: проходом по AST собрали полезную для дальнейших этапов информацию (таблица символов и т.п.) и преобразовали в какое-то (или какие-то) начальное представление, удобное для последующей обработки. Где-то между этими пунктами может быть более продвинутый preprocessor. На практике почти все эти фазы работают одновременно, опять-таки. > Надеюсь, когда-то я именно так и поступлю Т.е. Вы хотите совета не слушать, а таки страдать. :( Что ж, дело-то Ваше. Напоследок хотел бы Вам напомнить всяко относящуюся к делу поговорку "чем меньше проектируешь, тем больше программируешь". > что даже лексер проще написать свой (благо спасибо за assembly-like синтаксис) Речь-то была не об этом (вполне возможно, что lexer и в самом деле легче написать свой), а об общей архитектуре... > очень хотелось чтоб все было как у серьезных дядек на lex & yacc Кхе-кхе: https://t.me/CompilerDev/120030
Обсуждают сегодня