繁体   English   中英

如何定义基于 ANTLR4 缩进块的语法?

[英]How can I define an ANTLR4 indentation block based grammar?

我正在尝试使用 ANTLR4 定义一种语言来生成其解析器。 虽然该语言实际上有点复杂,但这是我希望解析器读取的文件的一个很小的有效示例,它触发了我试图解决的问题:

features \\ Keyword which initializes the "features" block
   Server
       mandatory \\ Relation word
           FileSystem
           OperatingSystem
       optional \\ Relation word
           Logging

特征词只是开始块,而必需可选是关系词。 剩下的词只是简单的词(在这种情况下称为特征)。 我想要的是使功能块的 Server 子项,然后是 Server 的子项和最后, FileSystem 和 OperatingSystem 的子项以及可选的 Logging 子项。

以下语法是我实现这种结构的尝试:

grammar MyGrammar;

tokens {
    INDENT,
    DEDENT
}

@lexer::header {
from antlr_denter.DenterHelper import DenterHelper
from UVLParser import UVLParser
}
@lexer::members {
class UVLDenter(DenterHelper):
    def __init__(self, lexer, nl_token, indent_token, dedent_token, ignore_eof):
        super().__init__(nl_token, indent_token, dedent_token, ignore_eof)
        self.lexer: UVLLexer = lexer

    def pull_token(self):
        return super(UVLLexer, self.lexer).nextToken()

denter = None

def nextToken(self):
    if not self.denter:
        self.denter = self.UVLDenter(self, self.NL, UVLParser.INDENT, UVLParser.DEDENT, True)
    return self.denter.next_token()

}

// parser rules
feature_model: features?;
features: 'features' INDENT child;

child: feature_spec INDENT relation* DEDENT;
relation: relation_spec INDENT child* DEDENT;

feature_spec: WORD ('.' WORD)*;
relation_spec: RELATION_WORD;

//lexer rules

RELATION_WORD: ('alternative' | 'or' | 'optional' | 'mandatory');

WORD: [a-zA-Z][a-zA-Z0-9_]*;

WS: [ \n\r]+ -> skip;
NL: ('\r'? '\n' '\t');

我正在使用antlr-denter来管理缩进和缩进。

然后,我在词法分析器中分别定义 RELATION_WORD 和 WORD。

最后,解析器规则尝试构建我之前描述的结构。 我希望功能词后跟一个孩子。 然后,任何子项都将成为一个特征规范,然后是 INDENT 和 DEDENT 之间的任意数量的关系。 关系是一个关系规范,后跟一组类似的孩子,这个循环无限重复,也会发生同样的情况。

但是,我无法让解析器正确读取此结构。 使用前面的示例作为输入,我必须成为 Server 的孩子,但不是可选的。 将示例更改为以下示例:

features
   Server
       mandatory
       optional
           Logging

强制和可选都被解释为强制的孩子。 它必须与 INDENT 和 DEDENT 解释有关才能正确找到块,但到目前为止我一直无法找到解决方案。

任何解决此问题的想法都将受到欢迎。 提前致谢!

尝试按如下方式更改您的childfeature规则:

child: feature_spec (INDENT relation* DEDENT)?;
relation: relation_spec (INDENT child* DEDENT)?;

解释:


正如@Kaby76 所提到的,打印出令牌流以了解您的解析器流如何查看令牌流非常有帮助。

我以前没有使用过 antlr-denter,但从它的插入方式来看,您似乎不会仅仅通过使用grun工具来获得令牌流。

作为替代,我尝试只组成 INDENT 和 OUTDENT 令牌(我分别使用了-><-

修改语法:

grammar MyGrammar;

// parser rules
feature_model: features?;
features: 'features' INDENT child;

child: feature_spec INDENT relation* DEDENT;
relation: relation_spec INDENT child* DEDENT;

feature_spec: WORD ('.' WORD)*;
relation_spec: RELATION_WORD;

//lexer rules

RELATION_WORD: ('alternative' | 'or' | 'optional' | 'mandatory');

WORD: [a-zA-Z][a-zA-Z0-9_]*;

WS: [ \n\r]+ -> skip;

// Temporary
//NL: ('\r'? '\n' '\t');
NL: ('\r'? '\n' '\t') -> skip;
INDENT: '->';
DEDENT: '<-';

并修改为输入文件以使用显式标记:

features
->Server
  ->mandatory
    optional
    ->Logging

只需进行此更改,您就会注意到示例中没有<-标记。

但是,现在我可以转储令牌流:

➜ grun MyGrammar tokens -tokens < MGIn.txt
[@0,0:7='features',<'features'>,1:0]
[@1,12:13='->',<'->'>,2:3]
[@2,14:19='Server',<WORD>,2:5]
[@3,28:29='->',<'->'>,3:7]
[@4,30:38='mandatory',<RELATION_WORD>,3:9]
[@5,47:48='->',<'->'>,4:7]
[@6,49:56='optional',<RELATION_WORD>,4:9]
[@7,69:70='->',<'->'>,5:11]
[@8,71:77='Logging',<WORD>,5:13]
[@9,78:77='<EOF>',<EOF>,5:20]

现在让我们尝试解析:

➜ grun MyGrammar feature_model -tree < MGIn.txt
line 4:9 mismatched input 'optional' expecting {WORD, '<-'}
line 5:20 mismatched input '<EOF>' expecting {'.', '->'}
(feature_model (features features -> (child (feature_spec Server) -> (relation (relation_spec mandatory) ->) (relation (relation_spec optional) -> (child (feature_spec Logging))) <missing '<-'>)))

因此,您的语法要求'mandatory' (作为RELATION_WORD )后跟INDENTDEDENT (不存在)。 这是有道理的,因为他们没有任何孩子,所以,似乎INDENT / DEDENT需要连接到是否有任何孩子:

让我们改变一下:

child: feature_spec (INDENT relation* DEDENT)?;
relation: relation_spec (INDENT child* DEDENT)?;

再试一次:

➜ grun MyGrammar feature_model -tree < MGIn.txt
➜ grun MyGrammar feature_model -tree < MGIn.txt
line 5:20 extraneous input '<EOF>' expecting {WORD, '<-'}
(feature_model (features features -> (child (feature_spec Server) -> (relation (relation_spec mandatory)) (relation (relation_spec optional) -> (child (feature_spec Logging))) <missing '<-'>)))

现在我们在 EOF 处缺少一个<- ( OUTDENT )。 对此的解决方案取决于 antlr-denter 是否关闭了<EOF>处的所有INDENT

假设是这样,我的假输入应该是这样的:

features
->Server
  ->mandatory
    optional
    ->Logging
    <-
  <-
<-

并且,我们再试一次:

grun MyGrammar feature_model -gui < MGIn.txt

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM