我有一个生成的语法,可以做两件事:
这两个函数是分开的,我们称之为validate()和evaluate()。
validate()函数从String输入构建树,同时确保它满足语言的BNF要求。 evaluate()函数将值插入到该树中以获得结果(通常为true或false)。
代码当前正在做的是每次在输入上运行validate(),只是为了生成evaluate()使用的树。有些输入需要60秒才能检查。我想要做的是序列化validate()的结果(假设它符合语法要求),将序列化的表单存储在后端数据库中,并将其作为evaluate()的一部分从数据库加载。
我注意到我可以在解析树上执行方法toStringTree()
,并检索LISP样式树。但是,我可以将LISP样式树还原到ANTLR分析树吗?如果没有,任何人都可以推荐另一种方法来序列化和存储生成的解析树吗?
感谢您的帮助。
杰森
答案 0 :(得分:1)
ANTLR 4的ParseRuleContext
数据结构(生成的解析器用来表示解析树中语法规则的ParseTree
的具体实现)默认情况下不可序列化。在项目问题跟踪器上打开issue #233涵盖功能请求。但是,根据我使用ANTLR进行解析的许多应用程序的经验,我不相信序列化解析树从长远来看会很有用。对于序列化解析树的每个问题都要解决,已经存在一个更好的解决方案。
另一种选择是在数据库中存储最后一个已知有效文件的哈希值。使用解析器创建解析树后,如果输入文件具有与上次验证时相同的散列,则可以跳过验证步骤。这利用了ANTLR 4的两个方面:
如果您需要的性能超出您的性能,那么解析树就不是您应该使用的数据结构。 StringTemplate 4与StringTemplate 3相比具有巨大的性能优势主要来自于解释器从使用AST(相当于用于此推理的解析树)转换为线性字节码表示/解释器的事实。出于性能原因,ST4的AST永远不需要序列化,因为字节码将被序列化。实际上,StringTemplate 4的C#端口正好提供了这个功能。
答案 1 :(得分:0)
如果语法的输入数据由几个独立的块组成,您可以尝试分别存储每个块的字符串,并使用ThreadPool为每个块单独再次运行解析过程。
例如,您的输入数据是一组方法声明:
int add(int a, int b) {
return a+b;
}
int mul(int a, int b) {
return a*b;
}
...
并且语法类似于:
methodList : methodDeclaration methodList
|
;
methodDeclaration : // your method declaration rules...
解析器的第一次运行只收集每个方法文本并存储它。解析器在 methodList 规则启动该过程。
void visitMethodList(MethodListContext ctx) {
if(ctx.methodDeclaration() != null) {
String methodStr = formatParseTree(ctx.methodDeclaration(), " ");
// store methodStr for later parsing
}
// visit next method list item, if any
if(ctx.methodList() != null) {
visit(ctx.methodList());
}
}
第二次运行启动每个方法声明的解析(例如在一个单独的线程中)。为此,解析器从 methodDeclaration 规则开始。
void visitMethodDeclaration(MethodDeclarationContext ctx) {
// parse the method block
}
如果因为直接调用ctx.methodDeclaration()。getText()而将formatDeclaration规则的文本格式化的原因将组合所有子节点AntLR doc的文本,可能使其无法再次解析。如果空格是语法中的标记分隔符,则在标记之间添加一个空格不应更改解析树。
String formatParseTree(ParseTree tree, String separator) {
StringBuilder builder = new StringBuilder();
for(int i = 0; i < tree.getChildCount(); i ++) {
ParseTree child = tree.getChild(i);
if(child instanceof TerminalNode) {
builder.append(child.getText());
builder.append(separator);
} else if(child instanceof RuleContext) {
builder.append(formatParseTree(child, separator));
}
}
return builder.toString();
}