Bood писал:
Я думаю, что это действительно имеет значение, скажем, если у нас есть и просто "если" за пределами режима, например<# /> если <# />, то если здесь будет совпадать с IF, а не с RAW, оно должно быть (той же длины, соответствует первому), верно?
Да, выправильно, хорошая мысльЕще немного подумав, что - это ожидаемое поведение AFAIK.Но, похоже, все работает немного по-другому: правило RAW
имеет приоритет над правилами ID
и IF
, даже если поместить его в конец грамматики лексера, как вы можете видеть:
freemarker_simple.g
grammar freemarker_simple;
@lexer::members {
private boolean mmode = false;
private boolean rawAhead() {
if(mmode) return false;
int ch1 = input.LA(1), ch2 = input.LA(2), ch3 = input.LA(3);
return !(
(ch1 == '<' && ch2 == '#') ||
(ch1 == '<' && ch2 == '/' && ch3 == '#') ||
(ch1 == '$' && ch2 == '{')
);
}
}
parse
: (t=. {System.out.printf("\%-15s '\%s'\n", tokenNames[$t.type], $t.text);})* EOF
;
OUTPUT_START : '${' {mmode=true;};
TAG_START : '<#' {mmode=true;};
TAG_END_START : '</' ('#' {mmode=true;} | ~'#' {$type=RAW;});
OUTPUT_END : '}' {mmode=false;};
TAG_END : '>' {mmode=false;};
EQUALS : '==';
IF : 'if';
STRING : '"' ~'"'* '"';
ID : ('a'..'z' | 'A'..'Z')+;
SPACE : (' ' | '\t' | '\r' | '\n')+ {skip();};
RAW : ({rawAhead()}?=> . )+;
Main.java
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
freemarker_simpleLexer lexer = new freemarker_simpleLexer(new ANTLRStringStream("<#/if>if<#if>foo<#if>"));
freemarker_simpleParser parser = new freemarker_simpleParser(new CommonTokenStream(lexer));
parser.parse();
}
}
выведет на консоль следующее:
TAG_START '<#'
IF 'if'
TAG_END '>'
RAW 'if'
TAG_START '<#'
IF 'if'
TAG_END '>'
RAW 'foo'
TAG_START '<#'
IF 'if'
TAG_END '>'
Как видите, 'if'
и'foo'
маркированы как RAW
на входе:
<#/if>if<#if>foo<#if>
^^ ^^^