0

(使用 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)+ .*? ';' ;

(换句话说,使“配对”成为解析器规则并用就地定义替换 Var/Val 片段)

根据我有限的理解,我认为这种更改“改进”了一些事情,因为我有效地删除了之前可匹配的最长可能标记(Pair+),但我仍然对为什么名称/值现在完全丢失感到困惑而且我也(显然!)仍然不清楚创建令牌的推荐方式,以确保它们不会太贪婪。

为什么现在只有分号被拾起?不理解这是我觉得我仍然缺少一些基本内容的原因之一。(但如果你不能从我的频繁编辑中看出,我一直在思考这个问题,并且阅读了很多其他以前发布的问题和答案,以免问一个愚蠢的问题,但我真的很难过。 )

感谢您的任何指导!

4

1 回答 1

0


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

下面给出的是 SampleObjectLexer.g4 的内容:

lexer grammar SampleObjectLexer;

OBJECTDECLARATION       :       'object';
OBJECTNAME              :       'testobj'|'anotherobj';
OPEN                    :       '{';
CLOSE                   :       '}';
NEWLINE                 :       [\r\n]  ->      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;

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

于 2013-07-29T12:52:42.630 回答