Глава 2. Грамматики
Оглавление
В этой главе описываются безконтекстные грамматики, используемые в этом спецификации для определения лексической и синтаксической структуры программы.
Безконтекстная грамматика состоит из набора правил вывода. Каждое правило имеет абстрактный символ, называемый нетерминалом, в качестве левой части, и последовательность одного или более нетерминалов и терминалов в качестве правой части. Для каждой грамматики терминальные символы берутся из указанного алфавита.
Начиная с предложения, состоящего из одного выделенного нетерминала, называемого целевой символ, заданная безконтекстная грамматика определяет язык, а именно, множество возможных последовательностей терминальных символов, которые могут получиться в результате многократной замены любого нетерминала в последовательности правой частью правила, для которого этот нетерминал является левой частью.
Лексическая грамматика для языка программирования Java приведена в §3. Эта грамматика использует в качестве терминальных символов символы набора Unicode. Она определяет набор правил, начинающийся с целевого символа Вход (§3.5), которые описывают, как последовательности символов Unicode (§3.1) преобразуются в последовательность элементов входных данных (§3.5).
Эти элементы входных данных, с отброшенным пробелом (§3.6) и комментариями (§3.7), образуют терминальные символы для синтаксической грамматики языка программирования Java и называются токенами (§3.5). Эти токены — это идентификаторы (§3.8), ключевые слова (§3.9), литералы (§3.10), разделители (§3.11) и операторы (§3.12) языка программирования Java.
Синтаксическая грамматика для языка программирования Java приведена в главах 4, 6-10, 14 и 15. Эта грамматика использует токены, определённые лексической грамматикой, как терминальные символы. Она определяет набор правил, начиная с целевого символа CompilationUnit (§7.3), которые описывают, как последовательности токенов могут образовывать синтаксически корректные программы.
Глава 18 также содержит синтаксическую грамматику языка программирования Java, более подходящую для реализации, чем для изложения. Оба синтаксических грамматики описывают один и тот же язык.
Терминальные символы показаны в fixed width шрифте в правилах лексической и синтаксической грамматик, а также в этом документе, когда текст непосредственно ссылается на такой терминальный символ. Они должны появляться в программе точно так, как они написаны.
Нетерминальные символы показаны в курсиве. Определение нетерминала начинается с имени определяемого нетерминала, за которым следует двоеточие. Затем следует одна или несколько альтернативных правых частей для нетерминала на последующих строках.
Например, синтаксическое определение:
IfThenStatement:
if ( Expression ) Statement
указывает, что нетерминал IfThenStatement представляет собой токен if, за которым следует токен левой скобки, за которым следует Expression, за которым следует токен правой скобки, за которым следует Statement.
В качестве другого примера, синтаксическое определение:
ArgumentList:
Argument
ArgumentList , Argument
указывает, что ArgumentList может представлять собой либо один Argument, либо ArgumentList, за которым следует запятая, за которым следует Argument. Это определение ArgumentList является рекурсивным, то есть оно определяется через себя. Результатом является то, что ArgumentList может содержать любое положительное количество аргументов. Такие рекурсивные определения нетерминалов являются распространенными.
Индексированный суффикс "opt", который может появиться после терминального или нетерминального символа, указывает на необязательный символ. Альтернатива, содержащая необязательный символ, фактически определяет две правые части: одну, которая опускает необязательный элемент, и одну, которая его включает.
Это означает, что:
BreakStatement:
break Identifieropt ;
является удобным сокращением для:
BreakStatement:
break ;
break Identifier ;
и что:
BasicForStatement:
for ( ForInitopt ; Expressionopt ; ForUpdateopt ) Statement
является удобным сокращением для:
и т.д.
и т.д. (много повторений)
Таким образом, нетерминал BasicForStatement фактически имеет восемь альтернативных правых частей.
Очень длинная правая часть может быть продолжена на второй строке, существенно отступив эту вторую строку.
Например, синтаксическая грамматика содержит это производство:
ConstructorDeclaration:
ConstructorModifiersopt ConstructorDeclarator
Throwsopt ConstructorBody
что определяет одну правую часть для нетерминала ConstructorDeclaration.
Когда слова "один из" следуют за двоеточием в определении грамматики, они означают, что каждый из терминальных символов в следующей строке или строках является альтернативным определением.
Например, лексическая грамматика содержит производство:
ZeroToThree: один из
0 1 2 3
что является просто удобным сокращением для:
и т.д.
Когда альтернатива в лексическом производстве выглядит как токен, она представляет собой последовательность символов, которые составляют такой токен.
Таким образом, определение:
BooleanLiteral: один из
true false
в лексическом грамматическом производстве является сокращением для:
и т.д.
Правая часть лексического производства может указывать, что некоторые расширения недопустимы, используя фразу "но не" и затем указывая исключаемые расширения.
Например, это происходит в правилах для InputCharacter (§3.4) и Identifier (§3.8):
InputCharacter:
UnicodeInputCharacter но не CR или LF
Identifier:
IdentifierName но не Keyword или BooleanLiteral или NullLiteral
Наконец, некоторые нетерминальные символы описываются описательной фразой в римском шрифте в тех случаях, когда было бы непрактично перечислить все альтернативы.
Например:
RawInputCharacter:
любой символ Юникода
© Oracle and/or its affiliates. All rights reserved.
Licensed under the Oracle Technology Network License Agreement.