java - 反外来输入

标签 java antlr antlr4

我有一个语法文件 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 : [a-z] | [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 {<EOF>, 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 : [a-z] | [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 token ,并且将创建所有 KEYPRESS 替代项。

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

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

编辑

一个可能的解决方案如下:

KEY : [a-z] | '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

您可能还想做一些类似于 NAMEKEY 中的 [a-z] 替代项(即单个小写字符会现在永远不会标记为 NAME,始终标记为 KEY)。

关于java - 反外来输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23621660/

相关文章:

java - 在以下情况下最终会发生什么阻塞?

java - 将视频托管在服务器上并在jsp页面上播放

java - 在同一个mockControl中使用普通mock和NiceMock

parsing - ANTLR 中匹配多个词法分析器规则的字符

java - antlr4数组实现: getting values of elements

java - 使用 ANTLR 4 和 Java 为编译器构建的程序生成字节码

java - ChangeListener 作为私有(private)类

antlr - 如何构建 ANTLR Works 风格的解析树?

java - ANTLR 语法中的歧义

java - 在监听器中使用 ParserRuleContext 遍历 token - ANTLR4