在ANTLR4中白色空间很重要时处理空白行

时间:2018-02-06 19:48:28

标签: grammar antlr4

这可能是一个新问题,因为我没有很多ANTLR经验,但我做了很多研究和故障排除,并没有找到解决方案,所以求助。我正在尝试为一个非常奇怪的格式文件(PCGEN开源角色扮演游戏角色编辑器)编写一个解析器,我计划将其用于多种用途,其中最重要的是学习ANTLR。我知道我有想要在LEX和Parse上工作的所有东西,除了它在空白行时会停止解析。我知道我可以添加一行来丢弃所有空格,但文件格式是这样的,字符串没有真正引用,并且空格通常很重要,所以应该忽略的唯一空格是一个完全空白的行。当我运行Lexer时,它会为整个文件提供令牌,所以我认为Parser会处理令牌而不关心它们来自哪里,所以我错过了一些简单的东西。这是我的意见的开始:

PCGVERSION:2.0

# System Information
CAMPAIGN:Advanced Player's Guide|CAMPAIGN:Ultimate Magic|CAMPAIGN:Ultimate Combat
VERSION:6.07.05
ROLLMETHOD:3|EXPRESSION:2d6+6
PURCHASEPOINTS:N

这是我目前的语法:

grammar PCG;

pcgFile     :   lines=line+;

line        :   statement (NEWLINE | EOF)
            ;

statement   :   KEYWORD ASSIGN
            |   KEYWORD ASSIGN YES_NO
            |   KEYWORD ASSIGN TEXT
            |   KEYWORD ASSIGN VERSIONNUM
            |   KEYWORD ( ASSIGN INT )+
            |   KEYWORD ASSIGN INT
            |   KEYWORD ASSIGN SUB_START statement SUB_END
            |   statement SEP statement
            ;


NEWLINE         :       '\r\n' | 'r' | '\n' ; 
YES_NO          :       ('Y'|'N');
KEYWORD         :       [A-Z]+; 
INT             :       [0-9]+; 
TEXT            :       ~(':'|'|'|'\r'|'\n'|'['|']')+; 
ASSIGN          :       ':'; 
SEP             :       '|';

COMMENT         :       '#' ~[\r\n]*->skip ; 
VERSIONNUM      :       ([0-9]+ ('.' [0-9]+)?)
                |       ('.' [0-9]+)
                |       ([0-9]+ ('.' [0-9]+) ('.' [0-9]+)?)
                ; 

ROLL            :       INT [dD] INT (('+'|'-') INT)?;

SUB_START       :       '['; 
SUB_END         :       ']';

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:0)

您需要在语句之间允许超过1个新行。通过删除rule and rewriting来执行此操作:

pcgFile : NEWLINE* statement ( NEWLINE+ statement )* NEWLINE* EOF;

主要问题是您的词法分析器将# System InformationTEXT令牌匹配。每当2个或更多规则匹配相同数量的字符时,首先定义的规则将" win" * 。这就是TEXT。当您在COMMENT之前放置TEXT时,它会起作用:

grammar PCG;

pcgFile     :   NEWLINE* statement ( NEWLINE+ statement )* NEWLINE* EOF;

statement   :   KEYWORD ASSIGN
            |   KEYWORD ASSIGN YES_NO
            |   KEYWORD ASSIGN TEXT
            |   KEYWORD ASSIGN VERSIONNUM
            |   KEYWORD ( ASSIGN INT )+
            |   KEYWORD ASSIGN INT
            |   KEYWORD ASSIGN SUB_START statement SUB_END
            |   statement SEP statement
            ;

NEWLINE         :       '\r\n' | 'r' | '\n' ;
YES_NO          :       ('Y'|'N');
KEYWORD         :       [A-Z]+;
INT             :       [0-9]+;
COMMENT         :       '#' ~[\r\n]* ->skip ;
TEXT            :       ~(':'|'|'|'\r'|'\n'|'['|']')+;
ASSIGN          :       ':';
SEP             :       '|';

VERSIONNUM      :       ([0-9]+ ('.' [0-9]+)?)
                |       ('.' [0-9]+)
                |       ([0-9]+ ('.' [0-9]+) ('.' [0-9]+)?)
                ;

ROLL            :       INT [dD] INT (('+'|'-') INT)?;

SUB_START       :       '[';
SUB_END         :       ']';

请注意~(':'|'|'|'\r'|'\n'|'['|']')+是危险的:它可以轻松匹配很多角色。

* 因为词法分析器的工作原理如此,12之类的输入将永远不会被标记为VERSIONNUM标记,因为INT匹配此标记也会{ {1}}。通过这样做来修复它:

VERSIONNUM