我正在尝试解析模板化语言,而且我无法正确解析标签之间可能出现的任意html。到目前为止,我所拥有的是什么建议?有效输入的一个例子是
{foo}{#bar}blah blah blah{zed}{/bar}{>foo2}{#bar2}This Should Be Parsed as a Buffer.{/bar2}
语法是:
grammar g;
options {
language=Java;
output=AST;
ASTLabelType=CommonTree;
}
/* LEXER RULES */
tokens {
}
LD : '{';
RD : '}';
LOOP : '#';
END_LOOP: '/';
PARTIAL : '>';
fragment DIGIT : '0'..'9';
fragment LETTER : ('a'..'z' | 'A'..'Z');
IDENT : (LETTER | '_') (LETTER | '_' | DIGIT)*;
BUFFER options {greedy=false;} : ~(LD | RD)+ ;
/* PARSER RULES */
start : body EOF
;
body : (tag | loop | partial | BUFFER)*
;
tag : LD! IDENT^ RD!
;
loop : LD! LOOP^ IDENT RD!
body
LD! END_LOOP! IDENT RD!
;
partial : LD! PARTIAL^ IDENT RD!
;
buffer : BUFFER
;
答案 0 :(得分:3)
您的词法分析器独立于解析器进行标记。如果您的解析器尝试匹配BUFFER
令牌,则词法分析器不会考虑此信息。在您的情况下输入如:"blah blah blah"
,词法分析器会创建3个IDENT
令牌,而不是单个BUFFER
令牌。
你需要“告诉”你的词法分析器,当你在标签里面时(即你遇到LD
标签),应该创建一个IDENT
标记,当你是在标记之外(即您遇到RD
标记),应创建BUFFER
标记而不是IDENT
标记。
为了实现这一点,您需要:
boolean
标志,用于跟踪您在标签内部或外部的事实。这可以在语法的@lexer::members { ... }
部分内完成; LD
- 或RD
- 标记后,boolean
标记。这可以在词法分析器规则的@after{ ... }
部分中完成; BUFFER
标记之前,检查您是否在标记之外。这可以通过在词法分析器规则的开头使用 semantic predicate 来完成。一个简短的演示:
grammar g;
options {
output=AST;
ASTLabelType=CommonTree;
}
@lexer::members {
private boolean insideTag = false;
}
start
: body EOF -> body
;
body
: (tag | loop | partial | BUFFER)*
;
tag
: LD IDENT RD -> IDENT
;
loop
: LD LOOP IDENT RD body LD END_LOOP IDENT RD -> ^(LOOP body IDENT IDENT)
;
partial
: LD PARTIAL IDENT RD -> ^(PARTIAL IDENT)
;
LD @after{insideTag=true;} : '{';
RD @after{insideTag=false;} : '}';
LOOP : '#';
END_LOOP : '/';
PARTIAL : '>';
SPACE : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};
IDENT : (LETTER | '_') (LETTER | '_' | DIGIT)*;
BUFFER : {!insideTag}?=> ~(LD | RD)+;
fragment DIGIT : '0'..'9';
fragment LETTER : ('a'..'z' | 'A'..'Z');
(请注意,您可能希望丢弃标记之间的空格,因此我添加了SPACE
规则并丢弃了这些空格)
使用以下类测试它:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
String src = "{foo}{#bar}blah blah blah{zed}{/bar}{>foo2}{#bar2}" +
"This Should Be Parsed as a Buffer.{/bar2}";
gLexer lexer = new gLexer(new ANTLRStringStream(src));
gParser parser = new gParser(new CommonTokenStream(lexer));
CommonTree tree = (CommonTree)parser.start().getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}
并且在运行主类之后:
java -cp antlr-3.3.jar org.antlr.Tool g.g
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar Main
java -cp antlr-3.3.jar org.antlr.Tool g.g
javac -cp antlr-3.3.jar *.java
java -cp .;antlr-3.3.jar Main
你会看到一些DOT源被打印到控制台,它对应于以下AST:
(使用graphviz-dev.appspot.com创建的图片)