仅在 ANTLR 语法的一部分显式处理换行符
Handle newlines explicitly only in part of an ANTLR grammar
我目前正在为必须转换为较新标准的旧专有标记语言开发解析器。为此,我正在使用 ANTLR 4。
该结构由由特定起始符及其相关终止符分隔的块组成(例如 {
... }
、<
... >
, INPUT
... END
).在每个块中,元素按行指定,以换行符分隔;实际上,只有在某些地方需要这些换行符才能理解代码的含义。
例如:
< ID
SOME_VAR "optional modifier string"
$anEnvironmentVariable
"a constant string"
"another constant" "with its optional modifier"
>
解析器规则如下
field
: OPEN_ANGLED_BRACKET row_id
((ENVIRONMENT_VAR | DQUOTE_STR | VAR) DQUOTE_STR?)+
CLOSED_ANGLED_BRACKET
;
// [...]
WHITESPACE
: [ \t\r\n] -> skip
;
可以很容易地解析上面的例子,但是因为忽略了换行符,所以它实际上无法区分双引号字符串是常量(意味着它在行的开头)还是修饰符字符串(后面同一行中的前一个 variable/constant)。
我实际上可以像这样明确地处理换行符:
field
: OPEN_ANGLED_BRACKET row_id NEWLINE
((ENVIRONMENT_VAR | DQUOTE_STR | VAR) DQUOTE_STR? NEWLINE)+
CLOSED_ANGLED_BRACKET NEWLINE
;
// [...]
WHITESPACE
: [ \t] -> skip
;
NEWLINE
: '\r'? '\n'
| '\r'
;
但是我必须明确地处理换行符在语法的其余部分中的任何地方,使它复杂化很多!
有什么方法可以将明确的换行符限制在有角度的括号内,在其他地方跳过它"automatically"?
你可以在这里使用lexical modes。您必须定义单独的词法分析器和解析器语法才能使用词法模式。
每当您在词法分析器中遇到 ENVIRONMENT_VAR
、VAR
或 DQUOTE_STR
(连续的第一个值)时,您就会更改词法模式。在这个新的词法模式中,你匹配 3 个东西:字符串、空格(你跳过)和换行(你也跳过,在这个标记之后,你改回默认模式)。这一切听起来可能有点含糊,所以这里有一个简短的演示:
文件:MarkupLexer.g4
lexer grammar MarkupLexer;
ENVIRONMENT_VAR : '$' VAR -> mode(MODIFIER_MODE);
VAR : [a-zA-Z_]+ -> mode(MODIFIER_MODE);
DQUOTE_STR : STR -> mode(MODIFIER_MODE);
OPEN_ANGLED_BRACKET : '<';
CLOSED_ANGLED_BRACKET : '>';
SPACES : [ \t\r\n] -> skip;
fragment STR : '"' ~["\r\n]* '"';
mode MODIFIER_MODE;
MODIFIER_MODE_SPACES : [ \t] -> skip;
MODIFIER_MODE_NL : [\r\n]+ -> skip, mode(DEFAULT_MODE);
MODIFIER_MODE_STRING : STR;
解析器将如下所示:
文件:MarkupParser.g4
parser grammar MarkupParser;
options {
tokenVocab=MarkupLexer;
}
field
: OPEN_ANGLED_BRACKET row_id row+ CLOSED_ANGLED_BRACKET
;
row
: (ENVIRONMENT_VAR | DQUOTE_STR | VAR) MODIFIER_MODE_STRING?
;
row_id
: VAR
;
当您解析输入时:
< ID
SOME_VAR "optional modifier string"
$anEnvironmentVariable
"a constant string"
"another constant" "with its optional modifier"
>
你将得到如下解析树:
我想提出一个不使用词法分析器模式的解决方案(因为我发现它们很难看),因此修改了 Bart 的语法:
grammar SOGrammar;
start:
OPEN_ANGLED_BRACKET ROW_ID ROW* CLOSED_ANGLED_BRACKET
;
VAR: [a-zA-Z_]+;
ENVIRONMENT_VAR: '$' VAR;
DQUOTE_STR: '"' .*? '"';
OPEN_ANGLED_BRACKET: '<';
CLOSED_ANGLED_BRACKET: '>';
ROW_ID: VAR LINEBREAK;
ROW:
(ENVIRONMENT_VAR | DQUOTE_STR | VAR) (SPACE* DQUOTE_STR)? LINEBREAK
;
SPACE: [ \t] -> skip;
LINEBREAK: [\r\n] -> skip;
这里的想法是,一行可以完全在我们可以控制空格的词法分析器中处理。
解析树是:
我目前正在为必须转换为较新标准的旧专有标记语言开发解析器。为此,我正在使用 ANTLR 4。
该结构由由特定起始符及其相关终止符分隔的块组成(例如 {
... }
、<
... >
, INPUT
... END
).在每个块中,元素按行指定,以换行符分隔;实际上,只有在某些地方需要这些换行符才能理解代码的含义。
例如:
< ID
SOME_VAR "optional modifier string"
$anEnvironmentVariable
"a constant string"
"another constant" "with its optional modifier"
>
解析器规则如下
field
: OPEN_ANGLED_BRACKET row_id
((ENVIRONMENT_VAR | DQUOTE_STR | VAR) DQUOTE_STR?)+
CLOSED_ANGLED_BRACKET
;
// [...]
WHITESPACE
: [ \t\r\n] -> skip
;
可以很容易地解析上面的例子,但是因为忽略了换行符,所以它实际上无法区分双引号字符串是常量(意味着它在行的开头)还是修饰符字符串(后面同一行中的前一个 variable/constant)。
我实际上可以像这样明确地处理换行符:
field
: OPEN_ANGLED_BRACKET row_id NEWLINE
((ENVIRONMENT_VAR | DQUOTE_STR | VAR) DQUOTE_STR? NEWLINE)+
CLOSED_ANGLED_BRACKET NEWLINE
;
// [...]
WHITESPACE
: [ \t] -> skip
;
NEWLINE
: '\r'? '\n'
| '\r'
;
但是我必须明确地处理换行符在语法的其余部分中的任何地方,使它复杂化很多!
有什么方法可以将明确的换行符限制在有角度的括号内,在其他地方跳过它"automatically"?
你可以在这里使用lexical modes。您必须定义单独的词法分析器和解析器语法才能使用词法模式。
每当您在词法分析器中遇到 ENVIRONMENT_VAR
、VAR
或 DQUOTE_STR
(连续的第一个值)时,您就会更改词法模式。在这个新的词法模式中,你匹配 3 个东西:字符串、空格(你跳过)和换行(你也跳过,在这个标记之后,你改回默认模式)。这一切听起来可能有点含糊,所以这里有一个简短的演示:
文件:MarkupLexer.g4
lexer grammar MarkupLexer;
ENVIRONMENT_VAR : '$' VAR -> mode(MODIFIER_MODE);
VAR : [a-zA-Z_]+ -> mode(MODIFIER_MODE);
DQUOTE_STR : STR -> mode(MODIFIER_MODE);
OPEN_ANGLED_BRACKET : '<';
CLOSED_ANGLED_BRACKET : '>';
SPACES : [ \t\r\n] -> skip;
fragment STR : '"' ~["\r\n]* '"';
mode MODIFIER_MODE;
MODIFIER_MODE_SPACES : [ \t] -> skip;
MODIFIER_MODE_NL : [\r\n]+ -> skip, mode(DEFAULT_MODE);
MODIFIER_MODE_STRING : STR;
解析器将如下所示:
文件:MarkupParser.g4
parser grammar MarkupParser;
options {
tokenVocab=MarkupLexer;
}
field
: OPEN_ANGLED_BRACKET row_id row+ CLOSED_ANGLED_BRACKET
;
row
: (ENVIRONMENT_VAR | DQUOTE_STR | VAR) MODIFIER_MODE_STRING?
;
row_id
: VAR
;
当您解析输入时:
< ID
SOME_VAR "optional modifier string"
$anEnvironmentVariable
"a constant string"
"another constant" "with its optional modifier"
>
你将得到如下解析树:
我想提出一个不使用词法分析器模式的解决方案(因为我发现它们很难看),因此修改了 Bart 的语法:
grammar SOGrammar;
start:
OPEN_ANGLED_BRACKET ROW_ID ROW* CLOSED_ANGLED_BRACKET
;
VAR: [a-zA-Z_]+;
ENVIRONMENT_VAR: '$' VAR;
DQUOTE_STR: '"' .*? '"';
OPEN_ANGLED_BRACKET: '<';
CLOSED_ANGLED_BRACKET: '>';
ROW_ID: VAR LINEBREAK;
ROW:
(ENVIRONMENT_VAR | DQUOTE_STR | VAR) (SPACE* DQUOTE_STR)? LINEBREAK
;
SPACE: [ \t] -> skip;
LINEBREAK: [\r\n] -> skip;
这里的想法是,一行可以完全在我们可以控制空格的词法分析器中处理。
解析树是: