Ваша основная проблема заключается в том, что вам нужно два токена предвидения, чтобы сделать то, что вы хотите - когда вход, который вы видели до сих пор, равен course
, а предвидение - OR_CONJ
, вы не знаете, уменьшать ли * От 1003 * до course_data
или сдвигаться без оглядки вперед на два токена после токена OR_CONJ
. Есть несколько способов справиться с этим
используйте генератор синтаксических анализаторов LR (2), LR (k) или GLR - с этим может справиться любой.
используйте взлом лексера, чтобы выполнить поиск - в основном, лексер возвращает два разных токена OR_CONJ
в зависимости от того, является ли следующий токен COURSE_NUMBER
или нет.
учитывает грамматику, чтобы избавиться от конфликта, что может привести к грамматике, которая анализирует что-то немного отличающееся от того, что вы хотите (требуются дополнительные проверки после анализа, чтобы отклонить некоторые недопустимые конструкции) и, как правило, делает грамматику гораздо сложнее понять.
Обратите внимание, что ваша грамматика в том виде, в котором она дана, также неоднозначно связана с тем, каким образом три или более курсов, связанных в одном утверждении, ассоциируются. Это легко исправить, переписав грамматику в более четкую леворекурсивную форму:
Rule 1 statement -> course
Rule 2 statement -> statement OR_CONJ course
Rule 3 course -> DEPT_CODE course_list
Rule 4 course -> DEPT CODE course_list OR_CONJ COURSE_NUMBER
Rule 5 course_list -> COURSE_NUMBER
Rule 6 course_list -> course_list , COURSE_NUMBER
Это также может быть переписано как праворекурсивное для генератора синтаксического анализатора LL, но у него все еще есть проблема просмотра с 2 токенами. Один из способов рефакторинга, чтобы он ушел, состоит в том, чтобы сделать COURSE_NUMBER
действительным course
и рекомбинировать его с предыдущим course
в последующем проходе (или выдать ошибку, если это первый course
в statement
). Тогда правило 4 становится:
Rule 4 course -> COURSE_NUMBER
и у вас нет конфликтов.