我有一个语法文件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中经历了有关此错误的其他问题,但没有人帮助过我。我无法弄清楚出了什么问题。为什么我会收到此错误?
答案 0 :(得分:9)
字符串"keyup"
被标记为NAME
令牌:这就是问题所在。
您必须意识到词法分析器独立于解析器运行。如果解析器试图匹配KEYPRESS
令牌,则词法分析器不会“监听”它,而只是按照规则构造一个令牌:
考虑这些规则以及规则的顺序:
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' ;
将在大多数NAME
替代品之前创建KEY
令牌,并且将创建所有KEYPRESS
替代品。
由于INT
匹配一个或多个数字,并且在KEY
之前定义,它也有一个数字替换,很明显词法分析器永远不会产生KEY
或{ {1}}令牌。
如果您将KEYPRESS
和NAME
规则移到INT
和KEY
规则下面,那么大多数令牌都会按照您的预期构建,这是我的猜测。
可能的解决方案如下:
KEYPRESS
即。我从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]+ ;
中移除了[0-9]
替代方案,并引入了KEY
规则(在<{em> SINGLE_DIGIT
规则之前放置了。)。
现在创建一些额外的解析器规则:
INT
并将解析器规则中integer : INT | SINGLE_DIGIT ;
key : KEY | SINGLE_DIGIT ;
内所有出现的INT
更改为integer
(不要调用您的规则int
:它是保留字)并将所有KEY
更改为key
。
您可能还想在NAME
中执行与[a-z]
和KEY
替代相似的操作(即,单个小写字母现在永远不会被标记为NAME
,总是作为KEY
)。