2016-04-15 2 views
0

Я создаю 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.
Я просмотрел свой код несколько раз, проверяя порядок, в котором, по-моему, должна быть проанализирована строка ввода; но я не смог найти ошибок в моей логике или причинам, почему строка не принимается.

Могу ли я получить некоторые предложения относительно того, почему это не принято, пожалуйста?

+0

Если вы не готовы, чтобы описать язык, по крайней мере, насколько это дает грамматики это трудно понять, как кто-то может вам помочь. – EJP

+0

@EJP: извините за это. Я не понимал, что это вызовет такую ​​трудность. Я немедленно отредактирую свои вопросы. – CKKOY

+1

Вы пробовали какие-либо опции отладки JavaCC? Я бы предложил, чтобы вы сделали это, чтобы увидеть, где ваши ожидания и реальность расходятся. –

ответ

0

Принимаются ли какие-либо из ваших входов? Я скопировал ваш код на свой компьютер и обнаружил, что любой правильный ввод (насколько я могу судить по определению вашего языка), он всегда выводит «НЕТ».

+0

есть. Например, строка '' YZ <2U> abc zzz ABBA <2U> kkkkk KM "принимается. Это строка, которая находится в L1, и она принимается на моем терминале. – CKKOY

+0

Очень странно, даже эта строка выводит «NO» на моем терминале, используя вашу точную программу. – fierynot

+0

Я попробую еще раз. Я не уверен, что происходит. – CKKOY

1

Следующие шаги помогли решить проблему.

  1. Выполните следующий код:
    javacc -debug_parser Assignment.jj
    javac Assignment*.java
  2. Затем запустить лексером/анализатор (набрав java Assignment), а затем ввести строку:
    "a <2L>AA <2U>a <2L>AA <2U>a</2U></2L></2U></2L>"
  3. Полученный след анализатора действий показывает, что на эту строку вызывается производство NextLangaugeTwo(), а не желаемое производство EvenLanguage().
  4. Прослеживание через NextLangaugeTwo() показывает, что оно соответствует первым восьми жетонам во входной строке.
  5. Таким образом, используя представление 9, хотя и неэффективно, вызывает ввод входной строки. То есть, изменить Start() производства путем изменения второго значения опережения (чуть выше вызова NextLanguageTwo()) от 3 до 9.
+1

Мне действительно не нравится предложение изменить вид с 3 до 9, если не будет анализа, чтобы показать, что нет строки, для которой потребуется 10.С другой стороны, рекомендуется использовать «debug_parser»; Я желаю, чтобы все с таким вопросом выполнили хотя бы этот базовый уровень расследования до публикации. –

+0

@ TheodoreNorvell Мне еще не удалось найти другой способ решения проблемы. Кроме того, это был первый случай, когда я узнал, что debug_parser может это сделать. Извините, если сообщение было неудобно. – CKKOY

+0

Оба 'NextLanguageTwo' и' EvenLanguage' могут начинаться с любого положительного количества токенов ' ', поэтому ясно, что любая конечная граница на просмотре будет недостаточной. Вы можете попробовать синтаксический просмотр. –

Смежные вопросы