我是antlr的新手,我正在努力制作简单的语法,但我不能成功。 我想解析这种文件:
BEGIN HEADER
CharacterSet "CP1252"
END HEADER
BEGIN DSJOB
test "val"
END DSJOB
BEGIN DSJOB
test "val2"
END DS
JOB
我正在使用这种语法:
grammar Hello;
dsxFile : headerDeclaration? jobDeclaration* EOF;
headerDeclaration : 'BEGIN HEADER' param* 'END HEADER';
jobDeclaration : 'BEGIN DSJOB' subJobDeclaration* param* 'END DSJOB';
subJobDeclaration : 'BEGIN DSSUBJOB' param* 'END DSSUBJOB';
headParam
: ( 'CharacterSet'
| 'name'
) StringLiteral
;
// ANNOTATIONS
param : PNAME PVALUE;
PNAME :StringCharacters;
PVALUE :StringCharacters;
// STATEMENTS / BLOCKS
//block
// : '{' blockStatement* '}';
// LEXER
// Keywords
ABSTRACT : 'abstract';
ASSERT : 'assert';
BOOLEAN : 'boolean';
BREAK : 'break';
BYTE : 'byte';
CASE : 'case';
CATCH : 'catch';
CHAR : 'char';
CLASS : 'class';
CONST : 'const';
CONTINUE : 'continue';
DEFAULT : 'default';
DO : 'do';
DOUBLE : 'double';
ELSE : 'else';
ENUM : 'enum';
EXTENDS : 'extends';
FINAL : 'final';
FINALLY : 'finally';
FLOAT : 'float';
FOR : 'for';
IF : 'if';
GOTO : 'goto';
IMPLEMENTS : 'implements';
IMPORT : 'import';
INSTANCEOF : 'instanceof';
INT : 'int';
INTERFACE : 'interface';
LONG : 'long';
NATIVE : 'native';
NEW : 'new';
PACKAGE : 'package';
PRIVATE : 'private';
PROTECTED : 'protected';
PUBLIC : 'public';
RETURN : 'return';
SHORT : 'short';
STATIC : 'static';
STRICTFP : 'strictfp';
SUPER : 'super';
SWITCH : 'switch';
SYNCHRONIZED : 'synchronized';
THIS : 'this';
THROW : 'throw';
THROWS : 'throws';
TRANSIENT : 'transient';
TRY : 'try';
VOID : 'void';
VOLATILE : 'volatile';
WHILE : 'while';
// Boolean Literals
BooleanLiteral : 'true' | 'false';
// Character Literals
fragment
SingleCharacter
: ~['\\] ;
// String Literals
StringLiteral
: '"' StringCharacters? '"'
;
fragment
StringCharacters
: StringCharacter+
;
fragment
StringCharacter
: ~["\\]
;
// Separators
LPAREN : '(';
RPAREN : ')';
LBRACE : '{';
RBRACE : '}';
LBRACK : '[';
RBRACK : ']';
SEMI : ';';
COMMA : ',';
DOT : '.';
// Operators
ASSIGN : '=';
GT : '>';
LT : '<';
BANG : '!';
TILDE : '~';
QUESTION : '?';
COLON : ':';
EQUAL : '==';
LE : '<=';
GE : '>=';
NOTEQUAL : '!=';
AND : '&&';
OR : '||';
INC : '++';
DEC : '--';
ADD : '+';
SUB : '-';
MUL : '*';
DIV : '/';
BITAND : '&';
BITOR : '|';
CARET : '^';
MOD : '%';
ADD_ASSIGN : '+=';
SUB_ASSIGN : '-=';
MUL_ASSIGN : '*=';
DIV_ASSIGN : '/=';
AND_ASSIGN : '&=';
OR_ASSIGN : '|=';
XOR_ASSIGN : '^=';
MOD_ASSIGN : '%=';
LSHIFT_ASSIGN : '<<=';
RSHIFT_ASSIGN : '>>=';
URSHIFT_ASSIGN : '>>>=';
//
// Additional symbols not defined in the lexical specification
//
AT : '@';
ELLIPSIS : '...';
//
// Whitespace and comments
//
WS : [ \t\r\n\u000C]+ -> skip
;
COMMENT
: '/*' .*? '*/' -> skip
;
LINE_COMMENT
: '//' ~[\r\n]* -> skip
;
但我仍然遇到这个问题:
第1行:0输出不匹配'BEGIN HEADER \ r \ n \ tCharacterSet'期待 {,'BEGIN HEADER','开始DSJOB'}(dsxFile BEGIN HEADER \ r \ n \ tCharacterSet“CP1252”\ r \ nEND HEADER \ r \ nBEGIN DSJOB \ r \ n \ ttest“val”\ r \ nEND DSJOB)
有人能解释一下这是什么意思吗?它似乎无法跳过\ r \ t。
感谢您的帮助!
答案 0 :(得分:2)
问题是您的输入未按预期标记。这是因为词法分析器尽可能多地匹配输入。因此,如果您查看PNAME
规则:
PNAME : StringCharacters;
fragment StringCharacter
: ~["\\]
;
然后您会注意到输入"BEGIN HEADER\n CharacterSet "
与该规则匹配。
这是错误信息:
不匹配的输入&#39; BEGIN HEADER \ r \ n \ tCharacterSet&#39;期待{,&#39; BEGIN HEADER&#39;,&#39; BEGIN DSJOB&#39;}
告诉我:找到了令牌'BEGIN HEADER\r\n\tCharacterSet '
,而解析器需要其中一个令牌'BEGIN HEADER'
或'BEGIN DSJOB'
。
您可能需要在该类中添加空格,制表符和换行符:~["\\ \t\r\n]
(但由您自行决定)
此外,词法分析器独立于解析器运行(解析器对生成的令牌没有影响)。词法分析器只是尝试匹配尽可能多的字符,并且只要有两个(或更多)规则匹配相同的字符,首先定义的规则&#34;胜出&#34;。根据这个逻辑,然后从以下规则:
PNAME : StringCharacters;
PVALUE : StringCharacters;
很明显规则PVALUE
永远不会匹配(只有PNAME
,因为首先定义了grammar Hello;
dsxFile : headerDeclaration? jobDeclaration* EOF;
headerDeclaration : BEGIN HEADER param* END HEADER;
jobDeclaration : BEGIN DSJOB subJobDeclaration* param* END DSJOB;
subJobDeclaration : BEGIN DSSUBJOB param* END DSSUBJOB;
param : PNAME pvalue;
pvalue : STRING /* other alternaives here? */;
STRING : '"' ~["\r\n]* '"';
BEGIN : 'BEGIN';
END : 'END';
HEADER : 'HEADER';
DSJOB : 'DSJOB';
DSSUBJOB : 'DSSUBJOB';
WS : [ \t\r\n\u000C]+ -> skip;
COMMENT : '/*' .*? '*/' -> skip;
LINE_COMMENT : '//' ~[\r\n]* -> skip;
// Be sure to put this rule _after_ the rules BEGIN, END, HEADER, ...
// otherwise this rule will match those keywords instead
PNAME : ~["\\ \t\r\n]+;
。
以下是解析示例输入的方法:
{{1}}
当然,您需要更改它以完全满足您的需求,但这只是一个开始。