- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试使用 Antlr4 构建 MVS JCL 识别器。总体工作进展得相当顺利,但我在处理相当于 *nix“here docs”(内联文件)的 MVS 时遇到了麻烦。我无法使用词法分析器模式在 JCL 和此处文档内容之间进行翻转,因此我正在寻找可能使用解析器级别的替代方案。
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
也是可选的,它定义此处文档终止符(默认终止符 = /*
)。
我需要能够在解析器级别处理 //ANYNAME...
行(我有这一点),然后读取此处文档内容,直到我找到(可能是非默认的)here-doc 终止符。从某种意义上说,这看起来像是词法分析器模式的机会 - 但此时我正在解析器中工作,并且没有固定的终止符可供使用。
我需要有关如何切换模式来处理我的此处文档,然后再次切换回来继续处理我的 JCL 的指导。
下面是我的语法的大幅删节版本(到目前为止,实际语法大约有 2,200 行并且不完整)。
感谢您的任何见解。感谢您的帮助、意见和建议。
/* 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
;
最佳答案
您的词法分析器需要能够在解析操作开始之前对整个文档进行标记。任何从解析器内部控制词法分析器的尝试都会导致 future 无尽的噩梦。 PHP 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);
}
关于parsing - 安特尔 4 : Method for switching modes in parser,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27320692/
我是一名优秀的程序员,十分优秀!