Я создаю lexer/parser, который должен принимать строки, принадлежащие к бесконечному набору языков.
Одна такая строка: "a <2L>AA <2U>a <2L>AA <2U>a</2U></2L></2U></2L>"
.Почему мой лексер/парсер JavaCC не принимает этот ввод?
Множество языков определяется следующим образом:
языка базы, L0
- Строка из L0 состоит из нескольких блоков, разделенных пробелами. Должен присутствовать хотя бы один блок.
- Блок представляет собой последовательность строчных букв без буквы (a-z).
- Перед первым блоком или после последнего пробела не допускается пробел.
- Число пробелов между блоками должно быть нечетным.
Пример строки, принадлежащей L0:
zyx abcba m xyzvv
Существует один символ пробела между zyx
и abcba
, существуют три пространства между abcba
и m
, и только один между m
и xyzvv
. В строке нет других символов пробела.
Язык L1
- Строка из L1 состоит из нескольких блоков, разделенных пробелами. Должен присутствовать хотя бы один блок.
- Существует два вида блоков. Блок первого типа должен быть четной последовательностью прописных букв (A-Z). Блок второго типа должен иметь форму
<2U>. . .</2U>
, где. . .
стоит для любой строки из L0. - Перед первым блоком или после последнего пробела не допускается пробел.
- Число пробелов между блоками должно быть нечетным.
Пример строки, принадлежащей к L1:
YZ <2U>abc zzz</2U> ABBA <2U>kkkkk</2U> KM
Обратите внимание, что пять пробелов отделить YZ
и <2U>abc zzz</2U>
, и три места делят abc
от zzz
. В противном случае в качестве разделителей используются одиночные пробелы. Нет места перед YZ
и не должно быть места KM
.
Язык L2
- Строка из L2 состоит из нескольких блоков, разделенных пробелами. Должен присутствовать хотя бы один блок.
- Существует два вида блоков. Блок первого типа должен быть чередованием последовательности строчных букв (a-z). Блок второго типа должен иметь форму
<2L>. . .</2L>
, где. . .
стоит для любой строки из L1. - Перед первым блоком или после последнего пробела не допускается пробел.
- Число пробелов между блоками должно быть нечетным.
Пример строки, принадлежащей L2:
abc <2L>AA ZZ <2U>a bcd</2U></2L> z <2L><2U>abcde</2U></2L>
Одиночных пространства используются в качестве разделителей внутри предложений, приведенных выше, но и любое другое нечетного число пространств также привело бы к действительным предложениям L2.
Языки L {2k + 1}, к> 0
- Строка из L {2k + 1} состоит из нескольких блоков, разделенных пробелами. Должен присутствовать хотя бы один блок.
- Существует два вида блоков. Блок первого типа должен быть четной последовательностью прописных букв (A-Z). Блок второго типа должен иметь форму
<2U>. . .</2U>
, где. . .
стоит для любой строки из L {2k}. - Перед первым блоком или после последнего пробела не допускается пробел.
- Число пробелов между блоками должно быть нечетным.
Языки L {2k + 2}, к> 0
- Строка из L {2k + 2} состоит из нескольких блоков, разделенных пространством символов. Должен присутствовать хотя бы один блок.
- Существует два вида блоков. Блок первого типа должен быть чередованием последовательности строчных букв (a-z). Блок второго типа должен иметь форму
<2L>. . .</2L>
, где. . .
стоит для любой строки из L {2k + 1}. - Перед первым блоком или после последнего пробела не допускается пробел.
- Число пробелов между блоками должно быть нечетным.
Код для моего лексического анализатора/синтаксического анализа выглядит следующим образом:
PARSER_BEGIN(Assignment)
/** A parser which determines if user's input belongs to any one of the set of acceptable languages. */
public class Assignment {
public static void main(String[] args) {
try {
Assignment parser = new Assignment(System.in);
parser.Start();
System.out.println("YES"); // If the user's input belongs to any of the set of acceptable languages, then print YES.
} catch (ParseException e) {
System.out.println("NO"); // If the user's input does not belong to any of the set of acceptable languages, then print NO.
}
}
}
PARSER_END(Assignment)
//** A token which matches any lowercase letter from the English alphabet. */
TOKEN :
{
< #L_CASE_LETTER: ["a"-"z"] >
}
//* A token which matches any uppercase letter from the English alphabet. */
TOKEN:
{
< #U_CASE_LETTER: ["A"-"Z"] >
}
//** A token which matches an odd number of lowercase letters from the English alphabet. */
TOKEN:
{
< ODD_L_CASE_LETTER: <L_CASE_LETTER>(<L_CASE_LETTER><L_CASE_LETTER>)* >
}
//** A token which matches an even number of uppercase letters from the English alphabet. */
TOKEN:
{
< EVEN_U_CASE_LETTERS: (<U_CASE_LETTER><U_CASE_LETTER>)+ >
}
//* A token which matches the string "<2U>" . */
TOKEN:
{
< OPEN_UPPER: "<2U>" >
}
//* A token which matches the string "</2U>". */
TOKEN:
{
< CLOSE_UPPER: "</2U>" >
}
//* A token which matches the string "<2L>". */
TOKEN:
{
< OPEN_LOWER: "<2L>" >
}
//* A token which matches the string "</2L>". */
TOKEN:
{
< CLOSE_LOWER: "</2L>" >
}
//* A token which matches an odd number of white spaces. */
TOKEN :
{
< ODD_WHITE_SPACE: " "(" "" ")* >
}
//* A token which matches an EOL character. */
TOKEN:
{
< EOL: "\n" | "\r" | "\r\n" >
}
/** This production matches strings which belong to the base language L^0. */
void Start() :
{}
{
LOOKAHEAD(3)
<ODD_L_CASE_LETTER> (<ODD_WHITE_SPACE> <ODD_L_CASE_LETTER>)* <EOL> <EOF>
|
NextLanguage()
|
LOOKAHEAD(3)
NextLanguageTwo()
|
EvenLanguage()
}
/** This production matches strings which belong to language L^1. */
void NextLanguage():
{}
{
(<OPEN_UPPER> (PseudoStart()) <CLOSE_UPPER>)+ (<ODD_WHITE_SPACE> UpperOrPseudoStart())* <EOL> <EOF>
|
(<EVEN_U_CASE_LETTERS>)+ (<ODD_WHITE_SPACE> UpperOrPseudoStart())* <EOL> <EOF>
}
/** This production matches either an even number of uppercase letters, or a string from L^0, encased within the tags <2U> and </2U>. */
void UpperOrPseudoStart() :
{}
{
<EVEN_U_CASE_LETTERS>
|
<OPEN_UPPER> (PseudoStart()) <CLOSE_UPPER>
}
/** This production matches strings from L^0, in a similar way to Start(); however, the strings that it matches do not have EOL or EOF characters after them. */
void PseudoStart() :
{}
{
<ODD_L_CASE_LETTER> (<ODD_WHITE_SPACE> <ODD_L_CASE_LETTER>)*
}
/** This production matches strings which belong to language L^2. */
void NextLanguageTwo() :
{}
{
(<ODD_L_CASE_LETTER>)+ (<ODD_WHITE_SPACE> LowerOrPseudoNextLanguage())* <EOL> <EOF>
|
(<OPEN_LOWER> PseudoNextLanguage() <CLOSE_LOWER>)+ (<ODD_WHITE_SPACE> LowerOrPseudoNextLanguage())* <EOL> <EOF>
}
/** This production matches either an odd number of lowercase letters, or a string from L^1, encased within the tags <2L> and </2L>. */
void LowerOrPseudoNextLanguage() :
{}
{
<ODD_L_CASE_LETTER>
|
<OPEN_LOWER> PseudoNextLanguage() <CLOSE_LOWER>
}
/** This production matches strings from L^1, in a similar way to NextLanguage(); however, the strings that it matches do not have EOL or EOF characters after them. */
void PseudoNextLanguage() :
{}
{
(<OPEN_UPPER> (PseudoStart()) <CLOSE_UPPER>)+ (<ODD_WHITE_SPACE> UpperOrPseudoStart())*
|
(<EVEN_U_CASE_LETTERS>)+ (<ODD_WHITE_SPACE> UpperOrPseudoStart())*
}
/** This production matches strings which belong to any of the languages L^{2k + 2}, where k > 0 (the infinite set of even languages). */
void EvenLanguage() :
{}
{
(<ODD_L_CASE_LETTER>)+ (<ODD_WHITE_SPACE> EvenLanguageAuxiliary())* <EOL> <EOF>
|
(CommonPattern())+ (<ODD_WHITE_SPACE> EvenLanguageAuxiliary())* <EOL> <EOF>
}
/** This production is an auxiliary production that helps when parsing strings from any of the even set of languages. */
void EvenLanguageAuxiliary() :
{}
{
CommonPattern()
|
<ODD_L_CASE_LETTER>
}
void CommonPattern() :
{}
{
<OPEN_LOWER> <EVEN_U_CASE_LETTERS> <ODD_WHITE_SPACE> <OPEN_UPPER> <ODD_L_CASE_LETTER> (<ODD_WHITE_SPACE> CommonPattern())+ <CLOSE_UPPER> <CLOSE_LOWER>
}
Несколько раз сейчас, я ввожу строку "a <2L>AA <2U>a <2L>AA <2U>a</2U></2L></2U></2L>"
.
Однако каждый раз на терминале печатается NO
.
Я просмотрел свой код несколько раз, проверяя порядок, в котором, по-моему, должна быть проанализирована строка ввода; но я не смог найти ошибок в моей логике или причинам, почему строка не принимается.
Могу ли я получить некоторые предложения относительно того, почему это не принято, пожалуйста?
Если вы не готовы, чтобы описать язык, по крайней мере, насколько это дает грамматики это трудно понять, как кто-то может вам помочь. – EJP
@EJP: извините за это. Я не понимал, что это вызовет такую трудность. Я немедленно отредактирую свои вопросы. – CKKOY
Вы пробовали какие-либо опции отладки JavaCC? Я бы предложил, чтобы вы сделали это, чтобы увидеть, где ваши ожидания и реальность расходятся. –