在表达式的自定义解析器中组合Java解析器

时间:2017-03-05 10:59:48

标签: java parsing dsl javacc javaparser

我正在尝试使用java表达式语句创建一个自定义域特定语言来创建HTML模板。

例如,它应该解析与java语句结合的标记:

<div>
    if (someValue == true) {

        <span>"someValue was true"</span>

    }
</div>

现在我知道如何编写这样的解析器。但是,如果我可以使用标准Java Parser作为表达式,那将非常简单,因此我不必重新实现Java Parser的一部分。我想要实现的目标可能如下:

IfStatementNode parseIfStatement() {

    scanner.expect("if");

    scanner.expect("(");

    JavaExpression expression = scanner.parseJavaExpression(); // <--- how to implement this?

    scanner.expect(")");

    return new IfStatementNode(expression);
}

如何做到这一点,以便scanner.parseJavaExpression解析任何Java表达式?

2 个答案:

答案 0 :(得分:2)

一个选项是添加一些生成代码,将表达式转换为Function对象的有效java代码。然后,您可以使用常规java编译器解析生成的函数(包含返回值的表达式),该编译器在运行时可用。

这仍然需要您能够找到表达式的结尾。 StreamTokenizer可能足够/方便。

另一个问题是在/如果你添加对它们的支持时跟踪变量。

另一种方法可能是扩展模板中非Java的部分(例如将<span>转换为output.append("<span>")),将模板转换为有效的Java代码,可以编译为整体

答案 1 :(得分:1)

你是对的:你可以重用JavaParser,我建议你这样做,因为解析Java表达式根本不是微不足道的。 JavaParser很好用,它正致力于构建对Java 9的支持,如果你使用JavaParser,你将免费获得它。

在这种情况下使用JavaParser非常简单,我几乎为编写这段代码感到羞耻:

Expression expression = JavaParser.parseExpression(code);

你已经完成了。

现在,如果代码中存在错误,我们会抛出异常。如果您想获得一个很好的问题列表,以便向用户报告,您可以这样做:

  ParseResult<Expression> result = new JavaParser().parse(ParseStart.EXPRESSION, new StringProvider(code));
  for (Problem p : result.getProblems()) {
      System.err.println("Problem at " + p.getLocation().get() + 
              ": " + p.getMessage());
  }

如果您希望处理代码以计算类型或解析对外部类的引用,您可能需要查看基于JavaParser构建的JavaSymbolSolver。

来源:我是JavaParser撰稿人