Java 将解析树转换为XML
我有一个编译过的语法,我想用它将输入序列转换成XML。请注意,在我的例子中,我有一个包含许多规则的非常大的语法,我希望避免重写代码中的每个语法规则 我将用一个例子来避免混淆。让我们来看看下面的语法Java 将解析树转换为XML,java,xml,parsing,tree,antlr4,Java,Xml,Parsing,Tree,Antlr4,我有一个编译过的语法,我想用它将输入序列转换成XML。请注意,在我的例子中,我有一个包含许多规则的非常大的语法,我希望避免重写代码中的每个语法规则 我将用一个例子来避免混淆。让我们来看看下面的语法 grammar expr; prog: stat+ ; stat: expr NEWLINE | ID '=' expr NEWLINE | NEWLINE ; expr: expr ('*'|'/') expr | INT | ID | '(' expr ')' ; ID : [
grammar expr;
prog: stat+ ;
stat: expr NEWLINE
| ID '=' expr NEWLINE
| NEWLINE
;
expr: expr ('*'|'/') expr
| INT
| ID
| '(' expr ')'
;
ID : [a-zA-Z]+ ; // match identifiers
INT : [0-9]+ ; // match integers
NEWLINE:'\r'? '\n' ; // return newlines to parser (is end-statement signal)
WS : [ \t]+ -> skip ; // toss out whitespace
grammar str;
expr:
STRING expr # exprString
| LR_BRACKET expr RR_BRACKET expr # exprParenthesis
| LR_STRING_BRACKET expr RR_BRACKET expr # exprRule
| <EOF> # exprEnd
| EOF_MARK # exprEOF
| # exprEpsilon
;
EOF_MARK: '<EOF>' ;
LR_STRING_BRACKET: '(' ~[ ()]+;
LR_BRACKET: '(';
RR_BRACKET: ')';
STRING: ~[ ()]+;
SPACE: [ \t\r\n]+ -> skip; // toss out whitespace
输入顺序
A = 10
B = A * A
预期产出
<prog>
<stat>
A =
<expr> 10
</expr>
\r\n
</stat>
<stat>
B =
<expr>
<expr>A</expr>
*
<expr> A</expr>
</expr>
\r\n
</stat>
</prog>
我随后将其转换为上面所示的XML(我使用简单的通用代码处理任何语法)。我觉得这种方法很愚蠢。没有到字符串树
,是否可以解决此问题?我希望避免重写访问者中的每个语法规则。(我有几百个)
编辑
我基本上需要将某种通用的ParseTree序列化为XML格式。主要目标是,我不必为每个规则用Java编写特殊的序列化方法。您可以利用ANTLR4的访问者功能。根据您使用的工具,您可能需要在生成类的过程中添加 为了更好地工作,我添加了一些:
prog
:stat+EOF
;
斯达
:expr NEWLINE#exprStat
|ID“=”expr换行符#assignStat
|换行符#清空状态
;
expr
:lhs=expr op=(“*”|“/”)rhs=expr#multExpr
|INT#intExpr
|ID#idExpr
|“('expr')”#nestedExpr
;
您的访问者可能是这样的:
公共类XmlVisitor扩展了exprBaseVisitor{
@凌驾
公共字符串visitProg(exprParser.ProgContext ctx){
StringBuilder=新的StringBuilder(“”);
对于(exprParser.StatContext stat:ctx.stat()){
builder.append(super.visit(stat));
}
返回builder.append(“”.toString();
}
@凌驾
公共字符串visitexpstat(exprParser.ExprStatContext ctx){
返回“expr”;
}
@凌驾
公共字符串visitAssignStat(exprParser.AssignStatContext ctx){
返回“+ctx.ID()+”=“+super.visit(ctx.expr())+”\\r\\n”;
}
@凌驾
公共字符串visitertystat(exprParser.EmptyStatContext ctx){
返回“\\r\\n”;
}
@凌驾
公共字符串visitMultExpr(exprParser.MultExprContext ctx){
return“+super.visit(ctx.lhs)+ctx.op.getText()+super.visit(ctx.rhs)+”;
}
@凌驾
公共字符串visitIntExpr(exprParser.IntExprContext ctx){
返回“+ctx.INT().getText()+”;
}
@凌驾
公共字符串visitIdExpr(exprParser.IdExprContext ctx){
返回“+ctx.ID().getText()+”;
}
@凌驾
公共字符串visitnestedxpr(exprParser.NestedExprContext ctx){
返回“+super.visit(ctx.expr())+”;
}
}
要测试此访问者,请运行以下代码:
String source=“A=10\nB=A*A\n”;
exprLexer lexer=新的exprLexer(CharStreams.fromString(source));
exprParser parser=newexprparser(newcommontokenstream(lexer));
ParseTree=parser.prog();
字符串xml=newXMLVisitor().visit(树);
System.out.println(xml);
将打印:
A=10\r\nB=A*A\r\n
我创建了一个ANTLR语法,它读取由ParseTree.toString树
方法生成的LISP样式树。项目是可访问的。它有以下几个部分
语法
grammar expr;
prog: stat+ ;
stat: expr NEWLINE
| ID '=' expr NEWLINE
| NEWLINE
;
expr: expr ('*'|'/') expr
| INT
| ID
| '(' expr ')'
;
ID : [a-zA-Z]+ ; // match identifiers
INT : [0-9]+ ; // match integers
NEWLINE:'\r'? '\n' ; // return newlines to parser (is end-statement signal)
WS : [ \t]+ -> skip ; // toss out whitespace
grammar str;
expr:
STRING expr # exprString
| LR_BRACKET expr RR_BRACKET expr # exprParenthesis
| LR_STRING_BRACKET expr RR_BRACKET expr # exprRule
| <EOF> # exprEnd
| EOF_MARK # exprEOF
| # exprEpsilon
;
EOF_MARK: '<EOF>' ;
LR_STRING_BRACKET: '(' ~[ ()]+;
LR_BRACKET: '(';
RR_BRACKET: ')';
STRING: ~[ ()]+;
SPACE: [ \t\r\n]+ -> skip; // toss out whitespace
语法str;
表达式:
字符串表达式#表达式字符串
|左括号表达式右括号表达式右括号表达式
|LR_字符串_括号表达式RR_括号表达式#表达式
|#exprEnd
|EOF#U标记#清除
|#exprEpsilon
;
EOF_标记:“”;
LR_字符串_括号:'('~[()]+;
左括号:'(';
右括号:‘)’;
字符串:~[()]+;
空格:[\t\r\n]+->skip;//去掉空格
strxmltvisitor.java
public class strXMLVisitor extends strBaseVisitor<String> {
@Override
public String visitExprString(strParser.ExprStringContext ctx)
{
return ctx.STRING().getText() + super.visit(ctx.expr());
}
@Override
public String visitExprParenthesis(strParser.ExprParenthesisContext ctx) {
return "(" + super.visit(ctx.expr(0)) + ")" + super.visit(ctx.expr(1));
}
@Override
public String visitExprRule(strParser.ExprRuleContext ctx) {
String value = ctx.LR_STRING_BRACKET().getText().substring(1);
return "<" + value + ">" + super.visit(ctx.expr(0)) + "</" + value + ">" + super.visit(ctx.expr(1));
}
@Override
public String visitExprEnd(strParser.ExprEndContext ctx) {
return "";
}
@Override
public String visitExprEOF(strParser.ExprEOFContext ctx) {
return "";
}
@Override
public String visitExprEpsilon(strParser.ExprEpsilonContext ctx) {
return "";
}
}
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
public class main {
public static void main(String[] args) throws Exception {
// create a CharStream that reads from standard input
ANTLRInputStream input = new ANTLRInputStream(System.in);
// create a lexer that feeds off of input CharStream
strLexer lexer = new strLexer(input);
// create a buffer of tokens pulled from the lexer
CommonTokenStream tokens = new CommonTokenStream(lexer);
// create a parser that feeds off the tokens buffer
strParser parser = new strParser(tokens);
ParseTree tree = parser.expr(); // begin parsing at init rule
String xml = "<?xml version=\"1.0\"?>" + new strXMLVisitor().visit(tree);
System.out.println(xml);
}
}
公共类strXMLVisitor扩展strBaseVisitor{
@凌驾
公共字符串visitexpstring(strParser.ExprStringContext ctx)
{
返回ctx.STRING().getText()+super.visit(ctx.expr());
}
@凌驾
公共字符串visitexpr括号(strParser.ExprParenthesisContext ctx){
返回“(“+super.visit(ctx.expr(0))+”)”+super.visit(ctx.expr(1));
}
@凌驾
公共字符串visitexprule(strParser.ExprRuleContext ctx){
字符串值=ctx.LR_字符串_括号().getText().substring(1);
返回“+super.visit(ctx.expr(0))+”+super.visit(ctx.expr(1));
}
@凌驾
公共字符串visitExprEnd(strParser.ExprEndContext ctx){
返回“”;
}
@凌驾
公共字符串visitexprof(strParser.ExprEOFContext ctx){
返回“”;
}
@凌驾
公共字符串visitexpresilon(strParser.ExprEpsilonContext ctx){
返回“”;
}
}
main.java
public class strXMLVisitor extends strBaseVisitor<String> {
@Override
public String visitExprString(strParser.ExprStringContext ctx)
{
return ctx.STRING().getText() + super.visit(ctx.expr());
}
@Override
public String visitExprParenthesis(strParser.ExprParenthesisContext ctx) {
return "(" + super.visit(ctx.expr(0)) + ")" + super.visit(ctx.expr(1));
}
@Override
public String visitExprRule(strParser.ExprRuleContext ctx) {
String value = ctx.LR_STRING_BRACKET().getText().substring(1);
return "<" + value + ">" + super.visit(ctx.expr(0)) + "</" + value + ">" + super.visit(ctx.expr(1));
}
@Override
public String visitExprEnd(strParser.ExprEndContext ctx) {
return "";
}
@Override
public String visitExprEOF(strParser.ExprEOFContext ctx) {
return "";
}
@Override
public String visitExprEpsilon(strParser.ExprEpsilonContext ctx) {
return "";
}
}
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
public class main {
public static void main(String[] args) throws Exception {
// create a CharStream that reads from standard input
ANTLRInputStream input = new ANTLRInputStream(System.in);
// create a lexer that feeds off of input CharStream
strLexer lexer = new strLexer(input);
// create a buffer of tokens pulled from the lexer
CommonTokenStream tokens = new CommonTokenStream(lexer);
// create a parser that feeds off the tokens buffer
strParser parser = new strParser(tokens);
ParseTree tree = parser.expr(); // begin parsing at init rule
String xml = "<?xml version=\"1.0\"?>" + new strXMLVisitor().visit(tree);
System.out.println(xml);
}
}
import org.antlr.v4.runtime.*;
导入org.antlr.v4.runtime.tree.*;
公共班机{
公共静态void main(字符串[]args)引发异常{
//创建从标准输入读取的字符流
AntlInputStream输入=新的AntlInputStream(System.in);
//创建一个lexer,该lexer从输入字符流中获取信息
strLexer lexer=新strLexer(输入);
//创建从lexer提取的令牌缓冲区
CommonTokenStream令牌=新的CommonTokenStream(lexer);
//创建一个以令牌缓冲区为源的解析器
strParser parser=新的strParser(令牌);
ParseTree=parser.expr();//从init规则开始解析
字符串xml=”“+新strXMLVisitor().visit(树);
System.out.println(xml);
}
}
一旦准备好antlr4(以及类路径中的引用),就可以使用以下命令来运行它:
antlr4 -visitor str.g4
javac *.java
java main < file
antlr4-visitor str.g4
javac*.java
java主文件
文件必须包含LISP树格式的输入,结果是标准输出上的XML