Различные способы объявить LOOKAHEAD в JAVACC - PullRequest
0 голосов
/ 23 апреля 2020

Я понял грамматику Javacc, чтобы написать синтаксический анализатор, в котором я нашел строку, которая выглядит как

Options : { LOOKAHEAD=3; }

Мне было интересно, что такое LOOKAHEAD и есть ли другие способы объявить с нетерпением?

1 Ответ

1 голос
/ 23 апреля 2020

Параметры LOOKAHEAD - это количество токенов по умолчанию, которое будет использоваться для принятия решения о том, какой путь будет выбран в каждой точке выбора.

Эта конфигурация необходима для разрешения конфликтов выбора, поскольку javacc не поддерживает возврат.

Значение по умолчанию для опции LOOKAHEAD равно 1. Поэтому важно написать грамматика, которая подходит для LOOKAHEAD = 1, означая, что выбор будет решен, если заглянуть на один токен вперед.

Например:

Поскольку JavaCC является анализатором LL, если левый токен производственного правила повторяется, возникает конфликт выбора:

void PhoneNumber() : {} {​

(LocalNumber() | CountryNumber()) <EOF> ​

}​

void LocalNumber() : {} { ​

AreaCode() "-" <FOUR_DIGITS>  ​

}​

void CountryNumber() : {} {  ​

AreaCode() "-" <THREE_DIGIT> "-" <FOUR_DIGITS>   ​

}​

void AreaCode() : {} {   ​

 <THREE_DIGIT> ​

}

Обратите внимание, что и CountryNumber, и LocalNumber начинаются с терминала <THREE_DIGIT>, который вызывает конфликт выбора,

Это можно переписать с помощью подхода, называемого "левым факторингом".

void PhoneNumber() : {} {​

AreaCode() "-" (LocalNumber() | CountryNumber()) <EOF> ​

}​

void LocalNumber() : {} { ​

<FOUR_DIGITS>  ​

}​

void CountryNumber() : {} {  ​

<THREE_DIGIT> "-" <FOUR_DIGITS>   ​

}​

void AreaCode() : {} {   ​

 <THREE_DIGIT> ​

}

Для случая, когда это невозможно, используется спецификация Lookahead

Спецификации Lookahead бывают пяти типов:

  • Несколько токенов LOOKAHEAD
  • Syntacti c LOOKAHEAD
  • Комбинация нескольких токенов и Syntacti c LOOKAHEAD
  • Semanti c LOOKAHEAD
  • Вложенный Lookahead

Несколько токенов LOOKAHEAD

Это можно использовать с целым числом, переданным в методе LOOKAHEAD (k). Это можно сделать,

  • Local LOOKAHEAD

    void PhoneNumber (): {} {(LOOKAHEAD (3) LocalNumber () | CountryNumber ( ))}

  • Global LOOKAHEAD

    Параметры: {LOOKAHEAD = 3; }

Syntacti c LOOKAHEAD

В спецификации просмотра Syntacti c используется конструкция syntacti c в качестве распознавателя выбора.

При указании синтаксического предпросмотра без нескольких токенов на самом деле вы указываете syntacti c предвидение с бесконечным несколькими токенами.

Например: LOOKAHEAD (2147483647, LocalNumber ( ))

void PhoneNumber() : {} {​

(​
LOOKAHEAD(("A"|"B")+ AreaCode() "-" <FOUR_DIGITS>) LocalNumber() ​

| CountryNumber()​

) <EOF> ​

}

Комбинация нескольких токенов и Syntacti c LOOKAHEAD

Таким образом, мы могли бы ожидать ограниченное количество токенов до тех пор, пока syntacti c Взгляд будет удовлетворен в рамках указанного выбора.

void PhoneNumber() : {} {​

(​
LOOKAHEAD(10, ("A"|"B")+ AreaCode() "-" <FOUR_DIGITS>) LocalNumber() ​

| CountryNumber()​

) <EOF> ​

}

Семанти c СООБЩЕНИЕ

Семанти c упреждающее ожидание включает в себя встраивание логического выражения Java в грамматику в точке выбора.

Если логическое выражение оценивается как true, выбрано текущее расширение.

void PhoneNumber() : {} {​

(​
LOOKAHEAD({getToken(1).image.equals("123")}) ​
KeysvilleNumber() ​

| FarmvilleNumber()​

) <EOF> ​

}

Вложенный L ookahead

Вложенный lookahead происходит, когда одна директива lookahead перекрывает другую. В JavaCC вложенный syntacti c lookahead игнорируется, но не вложенный semanti c lookahead .

void Start() : {} {​

(​
LOOKAHEAD(Fullname()) Fullname() ​

| Douglas()​

) <EOF> ​

}​

void Fullname() : {} {​

( LOOKAHEAD(Douglas() Munro()) ​

 Douglas()​

| Douglas() Albert()​

)​

Munro() ​

}​

void Douglas() : {} { "Douglas" } ​

void Albert() : {} { "Albert" }}​

void Munro() : {} { "Munro" }}

Все примеры взяты из удивительной книги Создание парсеров с JavaCC Тома Коупленда

Надеюсь, это полезно, спасибо.

...