Я опишу алгоритм, который работает. Это время не должно быть слишком плохо. Вы можете заранее вычислить и это.
Я предполагаю, что не содержит нетерминалов (хотя, вероятно, его легко адаптировать к этому случаю) и что вы не знаете x , y или производную от a . Я также предполагаю, что ваша грамматика не содержит произведений, которые никогда не используются ни при каких производных (например, A → A ).aИксYaA → A
Основная проблема на самом деле заключается в том, чтобы проанализировать , так как вы хотите знать, в каких состояниях вы оказались, чтобы вы знали, что может последовать за a . Это не так просто, как вы не знаете х .aaИкс
Мы используем адаптацию алгоритма Эрли . Сначала вы захотите понять этот алгоритм. Наш алгоритм работает почти так же, за исключением того, что наши шаги инициализации и завершения отличаются.
Для инициализации, мы семена нашего первого набора с элементом Эрел для каждого вхождения (первом символе в ) в любом производстве вашей грамматики. Мы устанавливаем обратный указатель этого элемента на -1, недопустимое значение. Это важно в нашем измененном завершении. По сути, -1 означает «Я понятия не имею, где это производство было начато».a1a
Теперь мы выполняем алгоритм Эрли отдельно для каждого возможного такого начального элемента Эрли. Мы не можем просто сделать их все одновременно, так как парсинги могут мешать друг другу. Я не могу легко увидеть более быстрый метод, чем возврат назад здесь.
Для шага завершения нам нужно только сделать модификацию для обработки -1 обратного указателя. Поскольку мы завершили производство, происхождение которого мы не знаем, у нас проблемы. Тем не менее, метод , используемый для вычисления Наборы касательноL A L R ( 1 ) последующего по Pennello и DeRemer спасает нас: то , что нам здесь нужно в точности Наборы касательно последующего . Каждому предмету в этих наборах прогнозирования соответствует положение в грамматике, что, в свою очередь, соответствует возможному продолжению законченного производства.L A L R ( 1 )
К сожалению, я не вижу другого выбора, кроме как вернуться сюда еще раз. Для каждой позиции в наборе указателей вы выполняете шаг завершения с этой позицией и продолжаете анализ оттуда. Вы делаете это отдельно для каждого разбора. Обратите внимание, что если ваша грамматика , ваш взгляд вперед будет однозначно определять, в какую позицию вы должны пойти, поэтому вам не нужно возвращаться назад.L A L R ( 1 )
a
Изменить: я думаю, что я нашел метод, который устраняет большую часть накладных расходов, введенных при возврате. Мы связываем с каждым элементом Earley набор идентификаторов, которые являются строками, так как нам нужно будет использовать префиксы этих идентификаторов. При инициализации мы добавляем все начальные элементы в набор Earley и связываем уникальный идентификатор с каждым набором.
На этапах сканера и предиктора идентификаторы переносятся на новые элементы. Предметы Earley в том же наборе Earley, которые отличаются только по своим идентификаторам, объединяются путем объединения их идентификаторов. Обратите внимание, что мы можем выполнить шаги сканера и предиктора для этих новых элементов с идентификаторами, не выполняя этот шаг для каждого идентификатора отдельно.
L A L R ( 1 )
По сути, мы выполняем возврат с использованием этих идентификаторов, чтобы не выполнять двойную работу на этапах сканера и предиктора.