Объяснение и решение для предупреждения JavaCC "Выбор регулярного выражения: FOO никогда не может быть сопоставлено как: BAR"? - PullRequest
5 голосов
/ 27 апреля 2009

Я учу себя использовать JavaCC в хобби-проекте, и у меня есть простая грамматика для написания парсера. В состав парсера входит следующее:

TOKEN : { < DIGIT : (["0"-"9"]) > }
TOKEN : { < INTEGER : (<DIGIT>)+ > }
TOKEN : { < INTEGER_PAIR : (<INTEGER>){2} > }
TOKEN : { < FLOAT : (<NEGATE>)? <INTEGER> | (<NEGATE>)? <INTEGER>  "." <INTEGER>  | (<NEGATE>)? <INTEGER> "." | (<NEGATE>)? "." <INTEGER> > } 
TOKEN : { < FLOAT_PAIR : (<FLOAT>){2} > }
TOKEN : { < NUMBER_PAIR : <FLOAT_PAIR> | <INTEGER_PAIR> > }
TOKEN : { < NEGATE : "-" > }

При компиляции с JavaCC я получаю вывод:

Warning: Regular Expression choice : FLOAT_PAIR can never be matched as : NUMBER_PAIR

Warning: Regular Expression choice : INTEGER_PAIR can never be matched as : NUMBER_PAIR

Я уверен, что это простая концепция, но я не понимаю предупреждение, будучи новичком в генерации синтаксических анализаторов и регулярных выражениях.

Что означает это предупреждение (с точки зрения новичка, как вы можете получить)?

Ответы [ 4 ]

4 голосов
/ 27 апреля 2009

Я не знаю JavaCC, но я инженер-компилятор.

Правило FLOAT_PAIR неоднозначно. Рассмотрим следующий текст:

0.0

Это может быть FLOAT 0, за которым следует FLOAT .0; или это может быть FLOAT 0., за которым следует FLOAT 0; оба приводят к FLOAT_PAIR. Или это может быть один FLOAT 0.0.

Более важно, однако, что вы используете лексический анализ с композицией таким образом, который никогда не будет работать. Считайте это число:

12345

Это может быть проанализировано как INTEGER 12, INTEGER 345, что приведет к INTEGER_PAIR. Или это может быть проанализировано как INTEGER 123, INTEGER 45, другое INTEGER_PAIR. Или это может быть INTEGER 12345, другой токен. Проблема существует, потому что вам не требуется пробел между лексическими элементами INTEGER_PAIR (или FLOAT_PAIR).

Вы почти никогда не должны пытаться обрабатывать такие пары в лексере. Вместо этого вы должны обрабатывать простые числа (INTEGER и FLOAT) как токены и обрабатывать такие вещи, как отрицание и спаривание, в анализаторе, где с пробелами обращаются и удаляют.

(Например, как вы собираетесь обрабатывать "----42"? Это допустимое выражение в большинстве языков программирования, которое будет правильно рассчитывать множественные отрицания, но не будет обрабатываться вашим лексером.)

Также помните, что однозначные целые числа в вашем лексере не будут совпадать с INTEGER, они будут иметь вид DIGIT. Я не знаю правильный синтаксис для JavaCC, чтобы исправить это для вас, хотя. Вам нужно определить DIGIT не как токен, а просто что-то, что вы можете использовать в определениях других токенов; в качестве альтернативы, вставьте определение DIGIT ([0-9]) напрямую, где бы вы ни использовали DIGIT в своих правилах.

0 голосов
/ 28 апреля 2009

Благодаря ответу Барри Келли я пришел к следующему решению:

    SKIP : { < #TO_SKIP : " " | "\t" > }
    TOKEN : { < #DIGIT : (["0"-"9"]) > }
    TOKEN : { < #DIGITS : (<DIGIT>)+ > }
    TOKEN : { < INTEGER : <DIGITS> > }
    TOKEN : { < INTEGER_PAIR : (<INTEGER>) (<TO_SKIP>)+ (<INTEGER>) > }
    TOKEN : { < FLOAT : (<NEGATE>)?<DIGITS>"."<DIGITS> | (<NEGATE>)?"."<DIGITS> > } 
    TOKEN : { < FLOAT_PAIR : (<FLOAT>) (<TO_SKIP>)+ (<FLOAT>) > }
    TOKEN : { < #NUMBER : <FLOAT> | <INTEGER> > }
    TOKEN : { < NUMBER_PAIR : (<NUMBER>) (<TO_SKIP>)+ (<NUMBER>) >}
    TOKEN : { < NEGATE : "-" > }

Я совершенно забыл включить пробел, который используется для разделения двух токенов, я также использовал символ «#», который останавливает сопоставление токенов и просто используется в определении других токенов. Выше скомпилировано JavaCC без предупреждения или ошибки.

Однако, как отметил Барри, есть причины против этого.

0 голосов
/ 27 апреля 2009

Это, вероятно, означает, что для каждого FLOAT_PAIR вы просто получите токен FLOAT_PAIR, а не NUMBER_PAIR. Правило FLOAT_PAIR уже соответствует всем входным данным, и JavaCC не будет пытаться найти дальнейшие подходящие правила. Это было бы моей интерпретацией, но я не знаю JavaCC, поэтому возьмите его с крошкой соли.

Может быть, вы можете как-то указать, что NUMBER_PAIR является основным производством и что вы не хотите получать другие токены в качестве результата.

0 голосов
/ 27 апреля 2009

Я не использовал JavaCC, но возможно, что NUMBER_PAIR неоднозначен.

Я думаю, что проблема заключается в том, что одна и та же вещь может совпадать с FLOAT_PAIR и INTEGER_PAIR, поскольку FLOAT может совпадать с INTEGER.

Но это всего лишь предположение, никогда не видевшее синтаксиса JavaCC :)

...