ANTLR (Lexer): отделить произвольные идентификаторы от ключевых слов - PullRequest
0 голосов
/ 27 апреля 2020

Я пытаюсь создать (простой) Lexer для файлов bat / cmd (для окраски синтаксиса). В рамках этой задачи мне нужно отделить ключевые слова от (произвольных) идентификаторов. Но согласно этот ответ ANTLR старается, чтобы самый длинный матч выиграл у более коротких. Моя грамматика пока выглядит так

lexer grammar CmdLexer;

Identifier
    : IdentifierNonDigit
      (  IdentifierNonDigit
      |  Digit
      )+
    ;

Number
    : Digit+
    ;

fragment IdentifierNonDigit
    : [a-zA-Z_\u0080-\uffff]
    ;

fragment Digit
    : [0-9]
    ;

Punctuation
    : [\u0021-\u002f\u003a-\u0040\u005b-\u0060\u007b-\u007f]+
    ;

Keyword
    : A P P E N D
    | A T
    | A T T R I B
    | B R E A K
    | C A L L
    | C D
    | C H C P
    | C H D I R
    | C L S
    | C O L O R
    | C O P Y
    | D A T E
    | D E L
    | D I R
    | D O
    | E C H O
    | E D I T
    | E N D L O C A L
    | E Q U
    | E X I S T
    | E X I T
    | F C
    | F O R
    | F T Y P E
    | G O T O
    | G E Q
    | G T R
    | I F
    | I N
    | L E Q
    | L S S
    | M D
    | M K D I R
    | M K L I N K
    | M O R E
    | M O V E
    | N E Q
    | N O T
    | N U L
    | P A T H
    | P A U S E
    | P O P D
    | P U S H D
    | R D
    | R E N
    | R E N A M E
    | S E T
    | S E T L O C A L
    | S H I F T
    | S T A R T
    | T I T L E
    | T R E E
    | T Y P E
    | W H E R E
    | W H O A M I
    | X C O P Y
    ;

fragment A:('a'|'A');
fragment B:('b'|'B');
fragment C:('c'|'C');
fragment D:('d'|'D');
fragment E:('e'|'E');
fragment F:('f'|'F');
fragment G:('g'|'G');
fragment H:('h'|'H');
fragment I:('i'|'I');
fragment J:('j'|'J');
fragment K:('k'|'K');
fragment L:('l'|'L');
fragment M:('m'|'M');
fragment N:('n'|'N');
fragment O:('o'|'O');
fragment P:('p'|'P');
fragment Q:('q'|'Q');
fragment R:('r'|'R');
fragment S:('s'|'S');
fragment T:('t'|'T');
fragment U:('u'|'U');
fragment V:('v'|'V');
fragment W:('w'|'W');
fragment X:('x'|'X');
fragment Y:('y'|'Y');
fragment Z:('z'|'Z');

Whitespace
    : [ \t]+
      -> skip
    ;

Newline
    : ( '\r' '\n'?
      | '\n'
      )
      -> skip
    ;

LineComment
    : ( '@'? R E M ~[\r\n]*
      | '@'? '::' ~[\r\n]*
      )
      -> skip
    ;

, но она всегда соответствует всему как Identifier, даже такие слова, как append или CALL. Я не вижу, как режимы могли бы решить эту проблему здесь, но как придать определенному правилу более высокий приоритет (здесь Keyword над другим (здесь Identifier)?

1 Ответ

3 голосов
/ 27 апреля 2020

Но в соответствии с этим ответом ANTLR старается, чтобы самый длинный матч выиграл у более коротких.

Это так, и это должно быть тем, что вы хотите. Обратите внимание, что это правило (так называемое правило максимального мунка) не имеет ничего общего с тем, сопоставляется ли append как ключевое слово или идентификатор. Это связано с тем, что appendix соответствует ключевому слову append, за которым следует идентификатор ix; или как единственный идентификатор appendix. Поскольку последнее, очевидно, является тем, что нужно в большинстве контекстов, полезно правило максимального жаворонка.

В данном случае важно то, что происходит, если несколько правил дают совпадение одинаковой длины. В этом случае ANTLR применяет правила, которые определены первыми в грамматике. Поэтому, если вы измените порядок своих определений так, чтобы Keyword предшествовал Identifier, правило Keyword будет иметь приоритет в тех случаях, когда оба правила приведут к совпадению одинаковой длины (и самое длинное совпадение все равно выиграет в случаи, когда это не так). Таким образом, ввод, такой как append appendix, будет маркирован как ключевое слово append, за которым следует идентификатор appendix, который должен быть тем, что вы хотите.

PS: я не уверен, где и как ваш лексер будет использоваться, но обычно вы хотите различать guish между разными ключевыми словами вместо одного правила, которое соответствует всем ключевым словам. Если токены будут использоваться в качестве входных данных для синтаксического анализатора, информация о том, что что-то является ключевым словом, не очень полезна, не зная, какое это ключевое слово.

...