为什么无法识别定义的令牌?



(使用antlr-4.1-complete.jar)

我是ANTLR4的新手,创建了一个简单的语法来测试我所学到的东西。我发现结果令人困惑,我觉得一定有一些基本概念我(通过我所有的阅读)没能理解。

这是我定义的语法:

grammar Gm;
// parser RULES
gmModel
    : obj+
    EOF
    ;
obj : objItem nameItem begin pairs end ;
objItem : OBJDECL ;
nameItem : OBJNAME ;
begin : OPEN ;
end : CLOSE ;
pairs : Pair+ ;
// LEXER RULES
OBJDECL : 'object' ;
OBJNAME : 'anotherobj' | 'testobj';
OPEN : '{' ;
CLOSE : '}' ;
fragment Var : ID_START (ID_CONT)+ ; // variable names start with an alpha
fragment Val : .*? ';' ; // values can be anything; capture everything up to the semicolon
Pair : Var Val ;
// fragments
fragment ID_START : [a-zA-Z] ;
fragment ID_CONT : [-_a-zA-Z0-9] ;
WS : [ t]+ -> skip ;

这是我用作输入的文件。每个对象都有一定数量的名称值组。大多数时候,它是一对-只有一个值(空格/制表符分隔),但有时,名称后面有两个值,这就是它捕获到分号的原因

object testobj {
    testvar testval;
    v_B 1234.9876;
}
object anotherobj {
    name o611;
    phases "CN";
    v_A 2401.7771;
    groupid OBJTEST;
    timeslice 1 hour;
}

尽管我定义了

OBJDECL : 'object' ;

作为Lexer规则,它不被识别为令牌(TestRig基本上显示了几个文本球)。我甚至把它放在第一位,因为我读到第一个定义的令牌优先。我还读到使用了尽可能长的令牌,也许这就是这里发生的事情,但在这种情况下,我无法理解如何定义可以匹配长度不可预测的字符串的有用令牌。

如果您能提供任何帮助,我们将不胜感激!

此外,经过更多修改后的最后一条评论:如果我做了以下两个更改,标记化是正确的,除了每对只由分号组成(内容去了哪里?)

pairs : Pair+ ;
->
pairs : pair+ ;

Pair : Var Val ;
->
pair : ID_START (ID_CONT)+ .*? ';' ;

(换句话说,使"pair"成为一个解析器规则,并用原位定义替换Var/Val片段)

根据我有限的理解,我认为这一变化"改善"了事情,因为我有效地删除了之前(Pair+)可匹配的最长的令牌,但我仍然不清楚为什么名称/值现在完全缺失,而且我(显然!)仍然不清楚创建令牌的推荐方式,以确保它们不会太贪婪。

为什么现在只有分号被选中?不理解这一点是我觉得我仍然错过了一些基本的东西的原因之一。(但如果你从我频繁的编辑中看不出来,我一直在思考这个问题,并阅读了很多以前发布的其他问题和答案,以避免问一个愚蠢的问题,但我真的很困惑。)

感谢您的指导!


你说得对"最长的正则表达式在这里匹配"。因此,当你处理长度未知的文本时,你可以利用词汇模式。可能是以下语法可以正确解析您的文本。

以下是SampleObjectLexer.g4:的内容

lexer grammar SampleObjectLexer;
OBJECTDECLARATION       :       'object';
OBJECTNAME              :       'testobj'|'anotherobj';
OPEN                    :       '{';
CLOSE                   :       '}';
NEWLINE                 :       [rn]  ->      skip;
WHITESPACE              :       [ t]   ->      skip;
Var                     :       ID_START (ID_CONT)+ -> pushMode(VALMODE);
fragment ID_START       :       [a-zA-Z];
fragment ID_CONT        :       [a-zA-Z0-9_-]+;
mode VALMODE;
Val                     :       .*?';' -> popMode;

以下是SampleObjectParser.g4 的内容

parser grammar SampleObjectParser;
options {tokenVocab = SampleObjectLexer;}
gmModel :       obj+;
obj     :       OBJECTDECLARATION OBJECTNAME OPEN pair+ CLOSE;
pair    :       Var Val;

我们在lexer语法中所做的是,每当我们匹配令牌Var时,我们指示Antlr lexer移动到VALMODE,在其中我们匹配值,并使用popMode返回到默认模式。由于默认模式不知道令牌Val(以前是最长的正则表达式),现在在默认模式下,lexer可以匹配诸如"object"、"testobj"等令牌,。

相关内容

  • 没有找到相关文章

最新更新