2015-02-24 3 views
0

У меня есть эти правила LeXeR в моей ANTLR3 грамматике:разрешения Лексера правила конфликта необходимо

INTEGER:    DIGITS; 
FLOAT:     DIGITS? DOT_SYMBOL DIGITS ('E' (MINUS_OPERATOR | PLUS_OPERATOR)? DIGITS)?; 

HEXNUMBER:    '0X' HEXDIGIT+; 
HEXSTRING:    'X' '\'' HEXDIGIT+ '\''; 

BITNUMBER:    '0B' ('0' | '1')+; 
BITSTRING:    'B' '\'' ('0' | '1')+ '\''; 

NCHAR_TEXT:    'N' SINGLE_QUOTED_TEXT; 

IDENTIFIER:    LETTER_WHEN_UNQUOTED+; 

fragment LETTER_WHEN_UNQUOTED: 
    '0'..'9' 
    | 'A'..'Z' // Only upper case, as we use a case insensitive parser (insensitive only for ASCII). 
    | '$' 
    | '_' 
    | '\u0080'..'\uffff' 
; 

и

qualified_identifier: 
    IDENTIFIER (options { greedy = true; }: DOT_SYMBOL IDENTIFIER)? 
; 

Это работает в основном отлично подходит для очень специфических ситуаций, таких как вход t1.1_d, который, как предполагается, за исключением анализируется как 2 идентификатора, связанных с точкой. Случается, что .1 сопоставляется как float, хотя за ним следуют символы подчеркивания и буквы.

Понятно, откуда это взято: LETTER_WHEN_UNQUOTED содержит цифры, так что «1» может быть как целым числом, так и идентификатором. Но порядок правил должен позаботиться о том, чтобы разрешить это целое, как предполагалось (и обычно это делает).

Однако я недоумеваю, что вход t1.1_d заставляет правило поплавка вставлять и оценит некоторые указатели для решения этой проблемы. Как только я добавляю пробел после точки, все в порядке, но это, очевидно, не настоящее решение.

Когда я перемещаю правило IDENTIFIER перед остальными, у меня возникают новые проблемы, потому что после этого несколько других правил больше не могут быть сопоставлены. Перемещение правила FLOAT после правила IDENTIFIER также не устраняет проблему (но, по крайней мере, не создает новых проблем). В этом случае мы видим фактическую проблему: точка всегда соответствует правилу FLOAT, если непосредственно следовать цифре. Что я могу сделать, чтобы это не соответствовало моему делу?

+0

Вы можете включать в себя полную грамматику (то есть, включают в себя все маркеры/фрагменты ссылки в вашем примере)? Кроме того, жадные значения по умолчанию равны true, поэтому указание этого не должно быть необходимым. –

+0

Возможно, вы захотите сделать несколько редизайнов: в настоящее время 1234 - это как INTEGER, так и IDENTIFIER. Я не говорю, что это не сработает, но у меня болит голова. –

ответ

0

Проблема заключается в том, что лексер работает независимо от анализатора. При столкновении с входной строкой t1.1_d лексер сначала потребляет IDENTIFIER, оставив .1_d. Теперь вы хотите, чтобы он соответствовал DOT_SYMBOL, а затем IDENTIFIER. Тем не менее, лексер всегда будет соответствовать максимально возможному токену, что приведет к сопоставлению FLOAT .1.

Перемещение IDENTIFIER до FLOAT не помогает, потому что '.' не является допустимым символом IDENTIFIER и поэтому не может совпадать с входом вообще, когда он начинается с ..

Обратите внимание, что Java и co. не позволяют идентификаторам начинать с цифр, возможно, чтобы предотвратить эти проблемы.

Одним из возможных решений было бы изменить FLOAT правило требовать цифр перед запятой: FLOAT: DIGITS '.' DIGITS ...

+0

Хорошо, спасибо. Это то, что я тоже думал. Я думаю, что это просто плохой способ определить язык, позволяя ids начинать с числа. –