Синтаксические анализаторы LR не могут обрабатывать неоднозначные грамматические правила. (Облегчил теорию еще в 1970-х годах, когда разрабатывались идеи).
C и C ++ допускают следующее утверждение:
x * y ;
Имеет два различных анализа:
- Это может быть объявление y, как указатель на тип x
- Это может быть умножение на x и y, отбрасывая ответ.
Теперь вы можете подумать, что последнее глупо и должно игнорироваться.
Большинство согласится с вами; Однако есть случаи, когда это может
иметь побочный эффект (например, если умножение перегружено). но это не главное.
Дело в том это два разных разбора, и поэтому программа
может означать разные вещи в зависимости от того, как этот должен был проанализирован.
Компилятор должен принять соответствующую информацию при соответствующих обстоятельствах и, при отсутствии какой-либо другой информации (например, знание типа x), должен собрать обе эти данные, чтобы впоследствии решить, что делать. Таким образом, грамматика должна позволять это. И это делает грамматику неоднозначной.
Таким образом, чистый анализ LR не может справиться с этим. Многие другие широко доступные генераторы синтаксических анализаторов, такие как Antlr, JavaCC, YACC или традиционный Bison, или даже синтаксические анализаторы в стиле PEG, не могут использоваться «чистым» способом.
Существует множество более сложных случаев (синтаксический синтаксический анализ шаблона требует произвольного просмотра, в то время как LALR (k) может смотреть вперед не более чем на k токенов), но для сброса pure LR требуется только один контрпример (или другие) разбор.
Большинство реальных синтаксических анализаторов C / C ++ обрабатывают этот пример, используя некоторые
вид детерминированного парсера с дополнительным хаком: они переплетаются с таблицей символов
коллекция ... так что к тому времени, когда "х" встречается,
синтаксический анализатор знает, является ли x типом или нет, и может таким образом
выбрать между двумя потенциальными анализами. Но парсер
что делает это не контекстно-свободным, и парсеры LR
(чистые и т. д.) (в лучшем случае) не зависят от контекста.
Можно обмануть и добавить семантические проверки времени сокращения для каждого правила в
парсерам LR, чтобы сделать это устранение неоднозначности. (Этот код часто не прост). Большинство других типов парсеров
есть некоторые средства для добавления семантических проверок в различных точках
при разборе, который может быть использован для этого.
И если вы обманываете достаточно, вы можете заставить парсеры LR работать на
С и С ++. Ребята из GCC сделали это на некоторое время, но дали
Я думаю, потому что они хотели
Лучшая диагностика ошибок.
Есть другой подход, который хорош и чист
и разбирает C и C ++ просто отлично без какой-либо таблицы символов
Взлом: GLR парсеры .
Это парсеры без контекста (фактически бесконечные
смотреть вперед). Парсеры GLR просто принимают оба парсинга,
создание "дерева" (на самом деле ориентированный ациклический граф, в основном древовидный)
это представляет неоднозначный анализ.
Пропуск после разбора может устранить неясности.
Мы используем эту технику в интерфейсах C и C ++ для наших
Реинжиниринг программного обеспечения DMS Tookit (по состоянию на июнь 2017 г.
они обрабатывают полный C ++ 17 в диалектах MS и GNU).
Они были использованы для обработки миллионов строк
больших систем C и C ++, с полными, точными разборками, производящими AST с полными деталями исходного кода. (См. AST для самого неприятного анализа C ++. )