Size: a a a

Compiler Development

2020 December 13

dt

d t in Compiler Development
Xottab DUTY
Ладно, я когда в чат заходил, забыл чувство юмора включить.
Ну, мы можем и руку поднимать когда смеяться надо \0/
источник

XD

Xottab DUTY in Compiler Development
Привет. 🙂

Вообще, как я посмотрел, там может даже и не понадобится кросс-компилятор, у меня есть идейка как это можно организовать...
источник

XD

Xottab DUTY in Compiler Development
Но это только как временное решение сойдёт, потому что в модах на сталкер изменённые шейдеры могут быть и с ними уже могут проблемы возникнуть, поэтому кросс-компилятором будет надёжнее. (при условии, что он будет полноценно HLSL поддерживать)
источник

D

Danya in Compiler Development
Berkus Decker
ну да, ему форвард декларации были не нужны - все решалось при линковке)
А сейчас разве не так? Если нет форвард декларации, то первое использование функции им является
источник

BD

Berkus Decker in Compiler Development
Danya
А сейчас разве не так? Если нет форвард декларации, то первое использование функции им является
почти все реализации сейчас ругаются на отсутствие прототипов функций перед их первым использованием
источник

D

Danya in Compiler Development
Berkus Decker
почти все реализации сейчас ругаются на отсутствие прототипов функций перед их первым использованием
А это стандартное? И если да, то с какого? 89, 99?
источник

BD

Berkus Decker in Compiler Development
Danya
А сейчас разве не так? Если нет форвард декларации, то первое использование функции им является
нельзя сейчас просто сказать в файле int main() { return strlen("hello world"); }
источник

Miss Очепятка... in Compiler Development
Berkus Decker
почти все реализации сейчас ругаются на отсутствие прототипов функций перед их первым использованием
Очевидно язык старый значит библиотек много и дружить их как-то надо.
источник

dt

d t in Compiler Development
@Xottab_DUTY, начни с этого:
источник

dt

d t in Compiler Development
Переслано от d t
Про однопроходнось: мои первые пятнадцать компиляторов - https://blog.sigplan.org/2019/07/09/my-first-fifteen-compilers.
источник

dt

d t in Compiler Development
Мои первые пятнадцать компиляторов

Компиляторы — сложные программы, переводящие некоторую программу из исходного языка в конечный. Обычно, программу обрабатывают несколькими проходами. Каждый проход может: изменять программу — к примеру, преобразовывать замыкания; оптимизировать — например избавляться от неиспользуемого кода; или же анализировать — и результат анализа будет использован в последующих проходах оптимизаций и изменений.

Нам ясно — чем больше в компиляторе проходов, тем он сложней устроен. К примеру в классической работе "Из system f в типизированный ассемблер" сказано что компилятор "к одной программе может применять вплоть до 20 проходов. Проводя такие сложные изменения и анализ, как преобразование продолжений и замыканий, распаковку значений, и т.д.". 20 проходов должны казаться нам чем-то внушительным — так и есть. А возможно ли упростить разработку компиляторов, приняв, что они должны состоять из большого множества простейших проходов, выполняющих что-то одно?

Подход nanopass
Мой самый первый компилятор переводил scheme в язык ассемблера x86-64, и был написан за один курс института. Но я написала не просто один компилятор, их было пятнадцать, по одному на каждую неделю семестра. Компилятор первой недели на вход получал чуть ли не язык ассемблера — только со скобками, а выдавал asm x86-64. В последующие недели, добавляя проходов к компилятору предшествующей недели, получали компиляторы, выдающие тот же язык ассемблера, но получающие немного более высокоуровневый язык.

По окончанию курса, у меня был компилятор из значительного подмножества scheme в язык ассемблера x86-64, состоящий из сорокатрех маленьких проходов. Каждый следующий проход выдавал чуть более низкоуровневый язык, или же тот же что и предыдущий, просто анализировав или оптимизировав исходный язык.

Сорокатрехпроходный компилятор за пятнадцать недель возможен лишь потому, что для разработки компилятора мы использовали подход nanopass. При таком подходе компилятор строится из простейших проходов, получающих и выдающих определенные языки. Для этого используется фреймворк c доступным исходным кодом, с DSL, эффективно описывающим промежуточные языки и, проходы, переводящие один такой язык в другой.

Nanopass впервые был описан в журнале ICFP в статье "nanopass. фреймворк для обучения построению компиляторов", а позднее и в JFP. Изначально он задумывался не только для обучения, но рецензенты из ICFP настаяли на таком описании, ведь они верили что подобные компиляторы обязательно будут медленными. Позже авторы переписали chez scheme используя nanopass, показав скорость компиляции, и описали это в статье "nanopass для разработки коммерческих компиляторов" (прим. пер. Изначально chez scheme самокомпилировался за три секунды, после переписывания — за шесть. Авторы сказали что время компиляции увеличелось в основном из-за более суровых оптимизаций, и в общем, теперь компилятор выдает более быстрый код).

Для меня nanopass — распростронение подхода комбинаторов парсеров на разработку компилятора в целом. С комбинаторами парсеров, парсер для сложного языка строится из множества маленьких парсеров, например парсеров чисел, знаков и т.п. Постепенно, дописывая парсер можно разбирать все более сложные языки. Но уже с самого начала у нас есть рабочий парсер. Также и с nanopass — с самого начала у нас есть компилятор, со временем способный обрабатывать более сложные языки.

=====
Плохо вычитанный перевод 1\3 статьи.
источник

dt

d t in Compiler Development
Если парсер тебе не очень интересен, то можешь отдать его на откуп специальному инструментарию.
источник

K

Kir in Compiler Development
TreeSitter-у, например
источник

BD

Berkus Decker in Compiler Development
Kir
TreeSitter-у, например
static void destroy_value(Rule *rule) {
 switch (rule->type) {
   case Rule::BlankType: return rule->blank_.~Blank();
   case Rule::CharacterSetType: return rule->character_set_.~CharacterSet();
   case Rule::StringType: return rule->string_ .~String();
   case Rule::PatternType: return rule->pattern_ .~Pattern();
   case Rule::NamedSymbolType: return rule->named_symbol_.~NamedSymbol();
   case Rule::SymbolType: return rule->symbol_ .~Symbol();
   case Rule::ChoiceType: return rule->choice_ .~Choice();
   case Rule::MetadataType: return rule->metadata_ .~Metadata();
   case Rule::RepeatType: return rule->repeat_ .~Repeat();
   case Rule::SeqType: return rule->seq_ .~Seq();
 }
}

огонь
источник

dt

d t in Compiler Development
@Xottab_DUTY, А где ссылка на проект?
источник

PS

Pavel Samolysov in Compiler Development
Не знал, что в с++ можно делать ретюрн и пробрасывать void. Прикольный хак, чтобы break не писать.
источник

BD

Berkus Decker in Compiler Development
Pavel Samolysov
Не знал, что в с++ можно делать ретюрн и пробрасывать void. Прикольный хак, чтобы break не писать.
д, всегда так делаю
источник

а

а это кто in Compiler Development
Pavel Samolysov
Не знал, что в с++ можно делать ретюрн и пробрасывать void. Прикольный хак, чтобы break не писать.
Значит ли это что у void в C++ всё-таки есть одно значение?
источник

K

Kir in Compiler Development
Berkus Decker
static void destroy_value(Rule *rule) {
 switch (rule->type) {
   case Rule::BlankType: return rule->blank_.~Blank();
   case Rule::CharacterSetType: return rule->character_set_.~CharacterSet();
   case Rule::StringType: return rule->string_ .~String();
   case Rule::PatternType: return rule->pattern_ .~Pattern();
   case Rule::NamedSymbolType: return rule->named_symbol_.~NamedSymbol();
   case Rule::SymbolType: return rule->symbol_ .~Symbol();
   case Rule::ChoiceType: return rule->choice_ .~Choice();
   case Rule::MetadataType: return rule->metadata_ .~Metadata();
   case Rule::RepeatType: return rule->repeat_ .~Repeat();
   case Rule::SeqType: return rule->seq_ .~Seq();
 }
}

огонь
Это не три-ситтер, по крайней мере это не тот три-ситтер, которого я знаю
источник

BD

Berkus Decker in Compiler Development
а это кто
Значит ли это что у void в C++ всё-таки есть одно значение?
это как return () // Unit
источник