我是ANTLR(任何版本)的新手,我刚刚开始编写我的第一个语法文件。我使用IntelliJ IDE和ANTLR插件(v1.6)。
我的语法是
grammar TestGrammar;
testfile : message+ EOF;
message : timestamp WS id (NL | EOF);
timestamp : NumericLiteral;
id : NumericLiteral;
NumericLiteral : INTEGER | DECIMAL;
INTEGER : [+-]? [0-9]+;
DECIMAL : [+-]? [0-9]* '.' [0-9]+;
EXPONENT : [eE] [+-]? [0-9]+;
WS: (' ' | '\t')+;
NL: '\r'? '\n';
当我应用简单测试输入时
123 1231
123 1312
正确解析数据,但我在IntelliJ预览窗口中收到错误。 "无关输入'< EOF>'期待{< EOF>,NL}"
我做错了什么? EOF似乎被正确检测到...如果我在最后一行添加NL,那么文件被正确解析但我需要确保最终的NL是可选的。
格式的其他详细信息:
我们正在对数据格式进行逆向工程,所以我会诚实地说,我们并不知道会有什么约束!我们目前的理解是:
我们已经看到了遵循这些模式的文件的证据,因此我们知道它们是有效的输入。
答案 0 :(得分:4)
在你的语法中,你明确指出了一个新的行'必须结束一条线。这里的问题是:'新线是'在语言message
部分的末尾?关于白色空间也会出现同样的问题。它们是语言的一部分吗?如果没有,您可以跳过它们:
WS: (' ' | '\t') -> skip;
NL: '\r'? '\n' -> skip;
然后,您可以简化message
规则:
message: timestamp id;
如果你真的需要保留行尾:
NL: '\r'? '\n';
您可以在message
规则的末尾添加此令牌作为可选:
message: timestamp id NL?;
这适用于您的示例,但会失败:
123 1231
123 1312
两行之间的\n
将产生错误。似乎最有希望的解决方案是第一个(使用简化的NL
规则跳过WS
和message
)但是,此条目将匹配为OK:
123 1231 123 1312
它将生成两个message
规则上下文。
总而言之,在您的示例中,为了给您提供构建语法的最佳方法,我们必须知道输入语言的限制。
<强>&LT;编辑&gt;
关于您的意见,有两种解决方案。您可以确定您的文件格式正确,并且想法是在没有约束的情况下提取文件的信息,或者您处于动态状态,您必须确保输入文件符合语法(以便同时删除&#34 ;坏文件&#34;)。
我非常确定您是第一种情况(正如您所说的那样正在执行逆向工程),因此您可能希望从文件中创建CST以提取信息。在这种情况下,考虑到您的输入文件总是很好,您不必费心检查NL
末尾是否存在messages
(通过构造,文件总是有一个{ {1}}逐行)。在这种情况下,您可以跳过您不需要的所有内容。语法变成了:
message
该语法将识别
grammar TestGrammar;
testfile : message+ EOF;
message : timestamp id;
timestamp : NumericLiteral;
id : NumericLiteral;
NumericLiteral : INTEGER | DECIMAL;
INTEGER : [+-]? [0-9]+;
DECIMAL : [+-]? [0-9]* '.' [0-9]+;
EXPONENT : [eE] [+-]? [0-9]+;
WS: (' ' | '\t')+ -> skip;
NL: '\r'? '\n' -> skip;
以及
123 1231
123 1312
但也
123 1231
(as many as \n you want between them)
123 1312
但是,如果输入文件格式不正确,使用此语法,您将无法排除它们。如果你需要确保一行只有一条消息,你应该使用Raz Friman提出的略微修改的语法版本:
123 1231 123 1312 (-> this will produce two messages as expected)
用这个语法:
grammar TestGrammar;
testfile : (message? NL)* message EOF;
message : timestamp id;
timestamp : NumericLiteral;
id : NumericLiteral;
WS: [\t ]+ -> skip;
NL: '\r'? '\n';
NumericLiteral : INTEGER | DECIMAL;
INTEGER : [+-]? [0-9]+;
DECIMAL : [+-]? [0-9]* '.' [0-9]+;
EXPONENT : [eE] [+-]? [0-9]+;
将被识别,而:
123 1231
(as many as \n you want between them)
123 1312
会抛出错误。
答案 1 :(得分:0)
如果您需要确保Newlines的约束,您可以让根文件检查最终的“消息”规则,然后应用EOF规则。
这个语法发布在下面:
testfile : (message NL)* message EOF;
message : timestamp id;
timestamp : NumericLiteral;
id : NumericLiteral;
WS: [\t ]+ -> channel(HIDDEN);
NL: '\r'? '\n';
NumericLiteral : INTEGER | DECIMAL;
INTEGER : [+-]? [0-9]+;
DECIMAL : [+-]? [0-9]* '.' [0-9]+;
EXPONENT : [eE] [+-]? [0-9]+;