Вопросы по грамматике / теории парсеров - PullRequest
3 голосов
/ 27 декабря 2011

Я недавно закончил свой первый анализатор / компилятор для специального языка программирования. У меня была некоторая свобода в спецификации этого языка, и в некоторых местах я изменил спецификацию, чтобы было легче разобрать; что в некоторых местах привело к некоторым (пока) незначительным улучшениям в самом языке. Может быть, я исправлю это в будущем v2; на данный момент я все еще перевариваю то, что узнал из этого процесса, и у меня есть несколько вопросов по этому поводу. Я никогда не проходил формальный курс по проектированию компиляторов, поэтому хочу убедиться, что мое понимание соответствует современному уровню в этой области.

  • В большинстве статей и учебников процесс разбора разбивается на два этапа: токенизация и лексический анализ. Затем обычно упоминается, что в большинстве реальных реализаций они обычно несколько взаимосвязаны, чтобы сделать реализацию проще. Мой собственный опыт был противоположным: смешивание их усложняло ситуацию, и я даже добавил третий проход. Я делаю первый проход, в котором я делаю минималистический токенинг, под которым я подразумеваю, что я определяю «токен» в его наиболее простой форме. Я экспериментировал с подходами, в которых, например, конструктор в целом был «токеном». Я отошел от этого подхода и теперь называю только «токены» вещами, которые являются основными строительными блоками программы. Затем я делаю лексический анализ, в котором я строю AST. Тогда мой третий проход - это (то, что я называю) структурный анализ, в котором я делаю, например, проверка типа, проверьте, соответствует ли количество аргументов, передаваемых функциям, сигнатурам этих функций и т. д. Не является ли это обычно частью «разбора», или не помещено в «лексический анализ», или почему литература предлагает в основном два пройти разбор подходов? (возможно, у меня есть четвертый проход, генерация кода, но это в основном отдельный процесс).

  • Мой лексер является (я думаю) рекурсивным спуском - у меня есть подпрограммы, которые соответствуют потокам токенов или возвращают false, когда они не могут, и затем пытаются сопоставить другое «правило», вплоть до обработки всех токенов , Эти подпрограммы рассчитывают максимум на 2 токена; насколько я понимаю, это означает, что у меня есть «LL (2) грамматика». Мой вопрос: какое значение имеет это число? Являются ли «LL (1) грамматики» как-то «лучше», чем грамматики с большим числом? Кроме того, почему возврат нежелателен? (или нет, и я просто неправильно понимаю?)

  • Почему классификация грамматик так важна? Все тексты начинаются с (как правило, довольно обширного) их объяснения, но, насколько я понимаю, вы не сможете реально изменить свойства грамматики, не внеся изменений в работу языка, который вы разрабатываете. Теперь я понимаю, что если вы хотите проанализировать существующий язык, классификация его структуры позволит вам доказать класс сложности результирующего синтаксического анализатора; но при разработке нового языка (imo) самое важное - это выразительность или другой вид соответствия поставленной цели, а производительность синтаксического анализатора для него имеет второстепенное значение. Хотя я понимаю, что эта последняя часть является дискуссионной, существуют ли практические причины при разработке нового языка внимательно следить за типом грамматики?

1 Ответ

4 голосов
/ 27 декабря 2011
  1. Думаю, вы немного путаете терминологию. Парсинг имеет дело только с переходом от источника к AST и делится на «этапы», а не «проходы». Использование слова «проход» подразумевает, что они выполняются последовательно, что в общем случае неверно.

    Причина, по которой на практике лексический анализ (то есть токенизация) и фактический синтаксический анализ взаимосвязаны, заключается в синтаксических особенностях целевого языка: синтаксис многих реальных языков лучше описать путем определения «контекстно-зависимых» токенов. Подумайте о языках с интерполяцией строк или определяемыми пользователем операторами.

  2. Таблица синтаксического анализа грамматик LL (k) растет экспоненциально с k в худшем случае, я полагаю, именно поэтому они получили плохое имя (для k> 1). Если вы вручную реализуете синтаксический анализатор с рекурсивным спуском, то это не имеет значения. Однако обратное отслеживание все еще плохо, поскольку может вызвать экспоненциальное время выполнения.

  3. Вы можете изменить грамматику, не затрагивая целевой язык. Обеспечение того, что грамматика попадает в определенный класс, позволяет вам использовать существующие инструменты (например, генераторы синтаксического анализатора LALR) и дает некоторую информацию о характеристиках времени выполнения синтаксического анализатора. Я согласен с тем, что при разработке языка не следует руководствоваться соображениями синтаксического анализа, хотя немного здравого смысла помогает, иначе вы получите неразборчивый беспорядок, такой как C ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...