Antlr 4:在解析器中切换模式的方法

v0rl0n

我正在尝试使用Antlr4构建MVS JCL识别器。总体上进展顺利,但是我在处理* nix“ here docs”(内联文件)的MVS方面遇到了麻烦。我无法使用词法分析器模式在JCL和Here-doc内容之间切换,因此我正在寻找可以使用解析器级别的替代方法。

IBM MVS允许使用“流数据集”,类似于* nix here-docs。

例子:

这定义了一个三行内联文件,该文件以字符“ ZZ”终止,并且引用程序可以使用标签“ ANYNAME”进行访问:

//ANYNAME  DD *,SYMBOLS=(JCLONLY,FILEREF),DLM=ZZ
HEREDOC TEXT 1
HEREDOC TEXT 2
HEREDOC TEXT 3
ZZ
//NEXTFILE DD ...stuff...

ANYNAME 是程序可用来访问此文档内容的句柄。

DD * 是必填项,并通知MVS遵循此处的文档。

SYMBOLS=(JCLONLY,FILEREF) 是与此处文档的处理方式有关的可选详细信息。

DLM=ZZ也是可选的,它定义了here-doc终结符(默认终结符= /*)。

我需要能够在解析器级别处理该//ANYNAME...行(我有那个位),然后读取here-doc的内容,直到找到(可能是非默认的)here-doc终止符从某种意义上讲,这看起来像是词法分析器模式的机会-但目前,我正在解析器内工作,并且没有固定的终结器可以使用。

我需要有关如何切换模式以处理我的here-doc的指南,然后再次切换回以继续处理我的JCL。

接下来是我的语法的节略版本(到目前为止,实际的语法大约是2200行,并且是不完整的)。

感谢您的任何见解。感谢您的帮助,意见和建议。

/* the ddstmt parser rule should be considered the main entry point. It handles (at least):

           //ANYNAME  DD *,SYMBOLS=(JCLONLY,FILEREF),DLM=ZZ
    and    //         DD *,DLM=ZZ
    and    //ANYNAME  DD *,SYMBOLS=EXECSYS
    and    //ANYNAME  DD *

  I need to be able process the above line as JCL then read the here-doc content...

                   "HEREDOC TEXT 1"
                   "HEREDOC TEXT 2"
                   "HEREDOC TEXT 3"

  as either a single token or a series of tokens, then, after reading the here-doc 
  delimiter...

                   "ZZ"

 , go back to processing regular JCL again.

*/


    /* lexer rules: */

                LINECOMMENT3        :   SLASH SLASH STAR                            ;
                DSLASH              :   SLASH SLASH                                 ;
                INSTREAMTERMINATE   :   SLASH STAR                                  ;
                SLASH               :   '/'                                         ;
                STAR                :   '*'                                         ;
                OPAREN              :   '('                                         ;
                CPAREN              :   ')'                                         ;
                COMMA               :   ','                                         ;

                KWDD                :   'DD'                                        ;
                KWDLM               :   'DLM'                                       ;
                KWSYMBOLS           :   'SYMBOLS'                                   ;
                KWDATA              :   'DATA'                                      ;

                SYMBOLSTARGET       :   'JCLONLY'|'EXECSYS'|'CNVTSYS'               ;
                EQ                  :   '='                                         ;
                APOST               :   '\''                                        ;
                fragment
                SPC                 :   ' '                                         ;
                SPCS                :   SPC+                                        ;
                NL                  :   ('\r'? '\n')                                ;
                UNQUOTEDTEXT        :   (APOST APOST|~[=\'\"\r\n\t,/() ])+          ;


    /* parser rules: */

                label               :   unquotedtext
                                    ;
                separator           :   SPCS
                                    ;

        /* handle crazy JCL comment rules - start */
                    partcomment         :   SPCS partcommenttext NL
                                        ;
                    partcommenttext     :   ((~NL+?)?)
                                        ;
                    linecomment         :   LINECOMMENT3 linecommenttext NL
                                        ;
                    linecommenttext     :   ((~NL+?)?)
                                        ;
                    postcommaeol        :   ( (partcomment|NL) linecomment* DSLASH SPCS )?
                                        ;
                    poststmteol         :   ( (partcomment|NL) linecomment* )?
                                        ;
        /* handle crazy JCL comment rules - end */

                ddstmt              :   DSLASH (label|) separator KWDD separator dddecl
                                    ;
                dddecl              :   ...
                                    |   ddinstreamdecl
                                    |   ...
                                    ;
                ddinstreamdecl      :   (STAR|KWDATA) poststmteol ddinstreamopts
                                    ;
                ddinstreamopts      :    ( COMMA postcommaeol ddinstreamopt poststmteol )*
                                    ;
                ddinstreamopt       :    (   ddinstreamdelim
                                         |   symbolsdecl
                                         )
                                    ;
                ddinstreamdelim     :   KWDLM EQ unquotedtext
                                    ;
                symbolsdecl         :   KWSYMBOLS EQ symbolsdef
                                    ;
                symbolsdef          :   OPAREN symbolstarget ( COMMA symbolsloggingdd )? CPAREN
                                    |   symbolstarget
                                    ;
                symbolstarget       :   SYMBOLSTARGET
                                    ;
                symbolsloggingdd    :   unquotedtext
                                    ;
                unquotedtext        :   UNQUOTEDTEXT
                                    ;
山姆·哈威尔

您的词法分析器需要能够在开始分析操作之前标记整个文档。从解析器内部控制词法分析器的任何尝试都是无尽噩梦的秘诀。PHP Lexer的以下片段显示了谓词如何与lexer模式结合使用,以使用用户定义的定界符检测字符串的结尾。关键部分是记录开始定界符,然后对照它在行的开头检查标记。

PHP_NOWDOC_START
    :   '<<<\'' PHP_IDENTIFIER '\'' {_input.La(1) == '\r' || _input.La(1) == '\n'}?
        -> pushMode(PhpNowDoc)
    ;

mode PhpNowDoc;

    PhpNowDoc_NEWLINE : NEWLINE -> type(NEWLINE);

    PHP_NOWDOC_END
        :   {_input.La(-1) == '\n'}?
            PHP_IDENTIFIER ';'?
            {CheckHeredocEnd(_input.La(1), Text);}?
            -> popMode
        ;

    PHP_NOWDOC_TEXT
        :   ~[\r\n]+
        ;

标识符实际上记录在的自定义替代中NextToken()(此处显示为C#目标):

public override IToken NextToken()
{
    IToken token = base.NextToken();
    switch (token.Type)
    {
    case PHP_NOWDOC_START:
        // <<<'identifier'
        _heredocIdentifier = token.Text.Substring(3).Trim('\'');
        break;

    case PHP_NOWDOC_END:
        _heredocIdentifier = null;
        break;

    default:
        break;
    }

    return token;
}

private bool CheckHeredocEnd(int la1, string text)
{
    // identifier
    //  - or -
    // identifier;
    bool semi = text[text.Length - 1] == ';';
    string identifier = semi ? text.Substring(0, text.Length - 1) : text;
    return string.Equals(identifier, HeredocIdentifier, StringComparison.Ordinal);
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Antlr 4:在解析器中切换模式的方法

来自分类Dev

ANTLR 4解析器语法

来自分类Dev

ANTLR4解析器问题

来自分类Dev

使用ANTLR 4的配置解析器

来自分类Dev

antlr4解析器可以看到匹配的打开和关闭文本模式吗?

来自分类Dev

antlr4-tsql解析器:忽略未知语句

来自分类Dev

ANTLR v4 C#:解析器::使用{}

来自分类Dev

Antlr4-多行文件解析器-

来自分类Dev

ANTLR4语法解析器问题

来自分类Dev

ANTLR4解析器规则粒度

来自分类Dev

ANTLR4解析器规则冲突

来自分类Dev

ANTLR:忽略解析器中的语句

来自分类Dev

Antlr 解析器测试 Python

来自分类Dev

ANTLR 解析缺少元素

来自分类Dev

Python ANTLR4示例-解析器似乎无法正确解析

来自分类Dev

Antlr4 解析器未正确解析重新分配语句

来自分类Dev

Antlr4解析日期

来自分类Dev

任何等效于“ not” scala解析器组合器的antlr4吗?

来自分类Dev

ANTLR 4中的词法分析器和解析器规则中“ \ n”的歧义引用

来自分类Dev

分别使用ANTLR解析器和Lexer

来自分类Dev

运行时Antlr 4.5解析器错误

来自分类Dev

不明确的ANTLR解析器规则

来自分类Dev

Antlr生成的解析器中输入不匹配

来自分类Dev

分别使用ANTLR解析器和Lexer

来自分类Dev

模棱两可的ANTLR解析器规则

来自分类Dev

ANTLR 4.7.1 生成的解析器中的问题

来自分类Dev

ANTLR4解析器规则以及其他解析器规则作为参数(元规则)

来自分类Dev

从ANTLR4解析器获取第一元数据和后续元数据

来自分类Dev

无法使Antlr4解析器遵循隐式乘法的运算顺序