Antlr无关输入

我有一个语法文件BoardFile.g4(仅限相关部分):

grammar Board; //Tokens GADGET : 'squareBumper' | 'circleBumper' | 'triangleBumper' | 'leftFlipper' | 'rightFlipper' | 'absorber' | 'portal' ; NAME : [A-Za-z_][A-Za-z_0-9]* ; INT : [0-9]+ ; FLOAT : '-'?[0-9]+('.'[0-9]+)? ; COMMENT : '#' ~( '\r' | '\n' )*; WHITESPACE : [ \t\r\n]+ -> skip ; KEY : [az] | [0-9] | 'shift' | 'ctrl' | 'alt' | 'meta' | 'space' | 'left' | 'right' | 'up' | 'down' | 'minus' | 'equals' | 'backspace' | 'openbracket' | 'closebracket' | 'backslash' | 'semicolon' | 'quote' | 'enter' | 'comma' | 'period' | 'slash' ; KEYPRESS : 'keyup' | 'keydown' ; //Rules file : define+ EOF ; define : board | ball | gadget | fire | COMMENT | key ; board : 'board' 'name' '=' name ('gravity' '=' gravity)? ('friction1' '=' friction1)? ('friction2' '=' friction2)? ; ball : 'ball' 'name' '=' name 'x' '=' xfloat 'y' '=' yfloat 'xVelocity' '=' xvel 'yVelocity' '=' yvel ; gadget : gadgettype 'name' '=' name 'x' '=' xint 'y' '=' yint ('width' '=' width 'height' '=' height)? ('orientation' '=' orientation)? ('otherBoard' '=' name 'otherPortal' '=' name)? ; fire : 'fire' 'trigger' '=' trigger 'action' '=' action ; key : keytype 'key' '=' KEY 'action' '=' name ; name : NAME ; gadgettype : GADGET ; keytype : KEYPRESS ; gravity : FLOAT ; friction1 : FLOAT ; friction2 : FLOAT ; trigger : NAME ; action : NAME ; yfloat : FLOAT ; xfloat : FLOAT ; yint : INT ; xint : INT ; xvel : FLOAT ; yvel : FLOAT ; orientation : INT ; width : INT ; height : INT ; 

这会生成词法分析器和解析器。 但是,当我对以下文件使用它时,它会给出以下错误:

 line 12:0 extraneous input 'keyup' expecting {, KEYPRESS} 

文件到解析:

board name = keysBoard gravity = 5.0 friction1 = 0.0 friction2 = 0.0

 # define a ball ball name=Ball x=0.5 y=0.5 xVelocity=2.5 yVelocity=2.5 # add some flippers leftFlipper name=FlipL1 x=16 y=2 orientation=0 leftFlipper name=FlipL2 x=16 y=9 orientation=0 # add keys. lots of keys. keyup key=space action=apple keydown key=a action=ball keyup key=backslash action=cat keydown key=period action=dog 

我在SO中经历了有关此错误的其他问题,但没有人帮助我。 我无法弄清楚出了什么问题。 为什么我收到此错误?

字符串"keyup"被标记为NAME标记:这就是问题所在。

您必须意识到词法分析器独立于解析器运行。 如果解析器试图匹配KEYPRESS令牌,则词法分析器不会“监听”它,而只是按照规则构造一个令牌:

  1. 匹配消耗最多字符的规则
  2. 如果有更多规则匹配相同数量的字符,请选择首先定义的规则

考虑这些规则,以及规则的顺序:

 NAME : [A-Za-z_][A-Za-z_0-9]* ; INT : [0-9]+ ; KEY : [az] | [0-9] | 'shift' | 'ctrl' | 'alt' | 'meta' | 'space' | 'left' | 'right' | 'up' | 'down' | 'minus' | 'equals' | 'backspace' | 'openbracket' | 'closebracket' | 'backslash' | 'semicolon' | 'quote' | 'enter' | 'comma' | 'period' | 'slash' ; KEYPRESS : 'keyup' | 'keydown' ; 

将在大多数KEY选项之前创建NAME令牌,并且将创建所有KEYPRESS选项。

并且由于INT匹配一个或多个数字并且在KEY之前定义,其也具有单个数字替代,因此很明显词法分析器将永远不会产生KEYKEYPRESS令牌。

如果您将NAMEINT规则移到KEYKEYPRESS规则下面,那么大多数令牌都将按照您的预期构建,这是我的猜测。

编辑

可能的解决方案如下:

 KEY : [az] | 'shift' | 'ctrl' | 'alt' | 'meta' | 'space' | 'left' | 'right' | 'up' | 'down' | 'minus' | 'equals' | 'backspace' | 'openbracket' | 'closebracket' | 'backslash' | 'semicolon' | 'quote' | 'enter' | 'comma' | 'period' | 'slash' ; KEYPRESS : 'keyup' | 'keydown' ; NAME : [A-Za-z_][A-Za-z_0-9]* ; SINGLE_DIGIT : [0-9] ; INT : [0-9]+ ; 

即我从KEY删除了[0-9]替代方案并引入了SINGLE_DIGIT规则(它放在INT规则之前 !)。

现在创建一些额外的解析器规则:

 integer : INT | SINGLE_DIGIT ; key : KEY | SINGLE_DIGIT ; 

并将解析器规则中所有出现的INT更改为integer (不要调用您的规则int :它是保留字)并将所有KEY更改为key

而且你可能也想在KEY做一些类似于NAME[az]替代方法(即单个小写字符现在永远不会被标记为NAME ,总是作为KEY )。