我有一个编译的语法,我想用它来将输入序列转换成XML。请注意,在我的情况下,我有一个很大的语法,其中包含许多规则,并且我想避免在代码中覆盖每个语法规则。

我将使用一个示例来避免混淆。让我们有以下语法

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

输入序列
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>

对应于解析树

java - 将解析树转换为XML-LMLPHP

当前,我使用一种创建ParseTree的方法,并使用toStringTree方法生成以下字符串
(prog (stat A = (expr 10) \r\n) (stat B = (expr (expr A) * (expr A)) \r\n))

然后我将其转换为上面显示的XML(我使用适用于任何语法的简单通用代码)。我发现这种方法很假。没有toStringTree是否可以解决它?我想避免需要覆盖访问者中的每个语法规则。 (我有数百个)。

编辑

我基本上需要某种通用的ParseTree序列化为XML格式。主要目标是我不必为每个规则都用Java编写特殊的序列化方法。

最佳答案

这种方法可能适合您的需求。我为终端符号加上了额外的标记t,以提高可读性,同时也跳过了带有空格的符号。但是,如果需要的话,调整输出应该不是一个大问题。

final exprLexer lexer = new exprLexer(CharStreams.fromString("A=10\nB = A * A\n"));
final CommonTokenStream tokens = new CommonTokenStream(lexer);
final exprParser parser = new exprParser(tokens);
final ParseTree tree = parser.prog();
ParseTreeWalker.DEFAULT.walk(new exprBaseListener()
{
    final String INDENT = "    ";
    int level = 0;
    @Override
    public void enterEveryRule(final ParserRuleContext ctx)
    {
        System.out.printf("%s<%s>%n", indent(), parser.getRuleNames()[ctx.getRuleIndex()]);
        ++level;
        super.enterEveryRule(ctx);
    }

    @Override
    public void exitEveryRule(final ParserRuleContext ctx)
    {
        --level;
        System.out.printf("%s</%s>%n", indent(), parser.getRuleNames()[ctx.getRuleIndex()]);
        super.exitEveryRule(ctx);
    }

    @Override
    public void visitTerminal(final TerminalNode node)
    {
        final String value = node.getText();
        if (!value.matches("\\s+"))
        {
            System.out.printf("%s<t>%s</t>%n", indent(), node.getText());
        }
        super.visitTerminal(node);
    }

    private String indent()
    {
        return String.join("", Collections.nCopies(level, INDENT));
    }
}, tree);

07-24 09:52
查看更多