LINUX.ORG.RU

Документация по написанию интерпретаторов


0

2

Вот заинтересовался (только для своего развития) попробовать написать тормоза ^W интерпретатор, язык c++, с чего начать? В гугле только 2 статьи каких то унылых (там какое то уныние через switch сделано). Какие книги? Можно на английском.



Последнее исправление: babusha (всего исправлений: 1)
Ответ на: комментарий от alexru

объявление переменной определяется раньше и обрабатывается в другой ветке правил
а вообще у себя в не очень сложном компиляторе сделал промежуточный проход, который на основе полученных уже данных модифицирует неоднозначные участки дерева

note173 ★★★★★
()
Ответ на: комментарий от note173

Когда в вышеприведенном куске парсер доходит до ';' возникает конфликт всертка-свертка и откуда-нибудь информацию по какому из правил сворачивать нужно получить. Дальше можно придумывать как именно ее получать - это уже не так важно, важно, что красивый теоретический процее в жизни разваливается.

Еще очень хорошее объяснение почему при разработке clang, например, был выбран метод ручного парсинга - это возможность сохранять промежуточную информацию. clang генерирует очень красивые и осмысленные сообщения об ошибках, с yacc и без невероятного гемороя так не сделать.

alexru ★★★★
()
Ответ на: комментарий от alexru

лексер получает идентификатор, если этот индентификатор есть в таблице с именами - значит это имя типа и лексер отдаёт токен «имя_типа», иначе - просто «идентификатор».

Ещё примеры труднорешаемых и труднораспарсиваемых вещей будут? Только умоляю, не нужно трогать С++

anonymous
()
Ответ на: комментарий от anonymous

«таблице с именами» следует читать как «таблице с именами типов»

anonymous
()
Ответ на: комментарий от alexru

> Еще очень хорошее объяснение почему при разработке clang, например, был выбран метод ручного парсинга - это возможность сохранять промежуточную информацию. clang генерирует очень красивые и осмысленные сообщения об ошибках, с yacc и без невероятного гемороя так не сделать.

Вы читаете мои мысли (или википедию?).

См. Пункт #4

http://www.linux.org.ru/jump-message.jsp?msgid=5926410&cid=5927459

anonymous
()
Ответ на: комментарий от anonymous

Я знаю как обычно решают эту проблему.

Необходимость семантического анализа в процессе синтаксического ведет к усложнению кода. Необходимость генерировать красивые сообщения об ошибках (еще раз, пример - clang) ведет к совершенно нечитаемым конструкциям в правилах для сверток.

Для примера предлагаю привести названия компиляторов, которые используют yacc. Не парсеров конфигов и прочей фигни, а компиляторов ЯП.

alexru ★★★★
()
Ответ на: комментарий от alexru

> Классический пример из Си: конструкция «zzz * a;» может быть просто выражением (умножение переменных «zzz» и «a»), а может быть объявлением переменной «a» как указателя типа «zzz»

По-моему, в руководстве по bison этот пример рекомендуется разбирать с помощью техники, известной как kludging :)

tailgunner ★★★★★
()
Ответ на: комментарий от alexru

Все правильно, лексер и парсер должны быть реализованы вместе. По крайней мере лексер дожен кое-что иметь от парсера. Мне как-то пиарили вот это: http://www.complang.org/kelbt/

dizza ★★★★★
()
Ответ на: комментарий от alexru

> Ну то-есть сами разработчики предлагают использовать костыли :)

Насколько я понимаю, это не вина bison - такова грамматика Си. Какой бы парсер ты не написал вручную, в нем будет аналогичное обращение к таблице символов.

tailgunner ★★★★★
()

на третьем курсе проходили такую замечательную вещь как «грамматики компьютерных языков»

пользовали древнюю как говно мамонта софтину «GRAM.EXE»

пример входного файла к ней

 Программа ::=  (_0_)
      program <_Name_>;
        [_ <_  Константы _> _]
        [_ <_ Переменные _> _]
      begin
        {_ <_ Операция _> _}
      end.      (_50_)              **

 Константы  ::=
   CONST  {_ <_Name_> (_1_) = <_Число_> (_2_) ; _} **

 Переменные ::=   VAR
   {_ <_Name_>(_3_) {_ ,<_Name_>(_4_)_} : <_Стандартный_тип_>(_5_) ; _} **

 Число           ::= ?_ <_Numb_> _|_ <_Real_> _? **
 Стандартный_тип ::= ?_   word   _|_   byte   _|_   char   _? **
 Операнд         ::= ?_ <_Name_> _|_ <_Numb_> _|_ <_Real_> _? (_10_) **
 Знак_Операции   ::= ?_  +  _|_  - _|_ * _|_  /  _? (_11_) **

 Выражение  ::=
    <_Операнд_> <_Знак_Операции_> <_Операнд_><_Знак_Операции _> <_Операнд_>
                  {_ <_Знак_Операции _> <_Операнд_> _} ; **

 Операция   ::= <_Name_> (_6_) := <_ Выражение_> **

TERRANZ ★★★★
()
Ответ на: комментарий от tailgunner

Насколько я понимаю, это не вина bison - такова грамматика Си.

Да, естественно. Просто такая фигня встречается в грамматиках многих распространенных языков. А в С++ такого вообще не пересчитать.

Это я к тому, что использование yacc - это хорошо, но нужно понимать какие ограничения это наложит.

Кроме того ручной разбор позволяет делать более быстрые парсеры, большая часть грамматики Си (все выраженя + еще по мелочи) может быть разобрана простым методом рекурсивного спуска, а для остальной части можно и медленные алогритмы применить.

alexru ★★★★
()
Ответ на: комментарий от alexru

> Для примера предлагаю привести названия компиляторов, которые используют yacc. Не парсеров конфигов и прочей фигни, а компиляторов ЯП.

gcc < 4.0

Необходимость семантического анализа в процессе синтаксического ведет к усложнению кода.

Полный семантический анализ не нужен, не сочиняйте

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.