我正在尝试构造一个用于解析模板语言的antlr语法。该语言可嵌入任何文本中,并且边界标记为打开/关闭标记:{{
/ }}
。所以有效的模板如下所示:
foo {{ someVariable }} bar
应忽略foo
和bar
,并且应解析{{
和}}
标记内的部分。我发现this question基本上有问题的答案,但标签只有一个{
和}
。我试图修改语法以匹配2个打开/关闭字符,但是一旦我这样做,BUFFER
规则就会消耗所有字符,也包括开始和结束括号。永远不会调用LD
规则。
当分隔符有2个字符时,有没有人知道为什么antlr词法分析器在Buffer
规则中使用所有标记,但是当它们只有一个字符时不会使用分隔符?
grammar Test;
options {
output=AST;
ASTLabelType=CommonTree;
}
@lexer::members {
private boolean insideTag = false;
}
start
: (tag | BUFFER )*
;
tag
: LD IDENT^ RD
;
LD @after {
// flip lexer the state
insideTag=true;
System.err.println("FLIPPING TAG");
} : '{{';
RD @after {
// flip the state back
insideTag=false;
} : '}}';
SPACE : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};
IDENT : (LETTER)*;
BUFFER : { !insideTag }?=> ~(LD | RD)+;
fragment LETTER : ('a'..'z' | 'A'..'Z');
答案 0 :(得分:2)
您可以匹配任何字符一次或多次,直到您通过在括号{{
中包含谓词来提前( ... )+
(参见演示中的BUFFER
规则)。
演示:
grammar Test;
options {
output=AST;
ASTLabelType=CommonTree;
}
@lexer::members {
private boolean insideTag = false;
}
start
: tag EOF
;
tag
: LD IDENT^ RD
;
LD
@after {insideTag=true;}
: '{{'
;
RD
@after {insideTag=false;}
: '}}'
;
BUFFER
: ({!insideTag && !(input.LA(1)=='{' && input.LA(2)=='{')}?=> .)+ {$channel=HIDDEN;}
;
SPACE
: (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;}
;
IDENT
: ('a'..'z' | 'A'..'Z')+
;
请注意,最好将BUFFER
规则作为语法中的第一个词法分析器规则:这样,它将成为第一个尝试的令牌。
如果您现在解析"foo {{ someVariable }} bar"
,则会创建以下AST:
答案 1 :(得分:0)
这样的语法不适合你的需求吗?我不明白为什么BUFFER需要那么复杂。
grammar test;
options {
output=AST;
ASTLabelType=CommonTree;
}
@lexer::members {
private boolean inTag=false;
}
start
: tag* EOF
;
tag
: LD IDENT RD -> IDENT
;
LD
@after { inTag=true; }
: '{{'
;
RD
@after { inTag=false; }
: '}}'
;
IDENT : {inTag}?=> ('a'..'z'|'A'..'Z'|'_') 'a'..'z'|'A'..'Z'|'0'..'9'|'_')*
;
BUFFER
: . {$channel=HIDDEN;}
;