java - 使用 ANTLR4 检查嵌套函数中数组的最大出现次数
问题描述
我有以下用于解析嵌套函数的语法文件。
语法:
grammar FunctionTokenizer;
parse : function* EOF;
function : ID '(' expr_list? ')';
expr_list : expr (',' expr)*;
expr : expr subscript | function | STRING | NUMBER | ID;
subscript : '[' expr? ']';
STRING : '"' ~'"'* '"';
NUMBER : [0-9]+ ('.' [0-9]+)?;
ID : [a-zA-Z_] [a-zA-Z_0-9]*;
SPACES : [ \t\r\n]+ -> skip;
输入失败,因为它有方括号。我将词法分析器的正则表达式更改为:
ID : [a-zA-Z_] [a-zA-Z_0-9\\[\\]]*;
但它给出了错误。
输入:
split(mul(add(input["data"][0]["name"][]["node"],input["data"][0]),input["data"][0]["name"][]["node"][]),",")
对于上面的输入,我正在检查哪个参数具有最大括号,要么是[](empty) or [0-9]
带数字的方括号,要么是忽略那些具有单引号和双引号的参数,例如["1234"]
or ['data']
。
对于上面的输入最大数组是:3,因为参数input["data"][0]["name"][]["node"][]
具有最大数组。
因此,我正在尝试实现访问者模式实现,但表达式列表未达到visitExpr_list方法。
以下是该项目的 GitHub 链接:
https://github.com/VIKRAMAS/CheckMaxArrayInNestedFunction/tree/master
访客实现类:
public class FunctionValidateVisitorImpl extends FunctionTokenizerBaseVisitor<String> {
@Override
public String visitParse(FunctionTokenizerParser.ParseContext ctx) {
ParseTree name = ctx.getChild(2);
String visit = visit(name);
System.err.println("visit1:::::::::::"+visit);
return visit(name);
}
@Override
public String visitFunction(FunctionTokenizerParser.FunctionContext ctx) {
ParseTree name = ctx.getChild(2);
String visit = visit(name);
System.err.println("visit2:::::::::::"+visit);
return visit;
}
@Override
public String visitExpr_list(FunctionTokenizerParser.Expr_listContext ctx) {
String s="";
for (int i = 0; i < ctx.getChildCount(); i+=2) {
if(ctx.getChild(i) instanceof FunctionTokenizerParser.Expr_listContext ) {
String g=visit(ctx.getChild(i));
System.err.println("visit3:::::::::::if "+i+" "+g);
s=s+g;
}
else {
System.err.println("visit4:::::::::::else "+i+" "+ctx.getChild(i).getText());
s=s+ctx.getChild(i).getText();
}
}
return s;
}
public String visitSubscript(FunctionTokenizerParser.SubscriptContext ctx) {
System.err.println("visit5:::::::::::");
String s="";
for (int i = 0; i < ctx.getChildCount(); i++) {
if(ctx.getChild(i) instanceof FunctionTokenizerParser.SubscriptContext) {
String g=visit(ctx.getChild(i));
s=s+g;
}
else {
s=s+ctx.getChild(i).getText();
}
}
return s;
}
@Override
public String visitExpr(FunctionTokenizerParser.ExprContext ctx) {
System.err.println("visit6:::::::::::");
String s="";
for (int i = 0; i < ctx.getChildCount(); i++) {
if(ctx.getChild(i) instanceof TerminalNodeImpl ) {
s=s+ctx.getChild(i).getText();
}
else {
String g=visit(ctx.getChild(i));
s=s+g;
}
}
return s;
}
}
测试类:
public class FunctionValidate {
public static void main(String[] args) {
try {
String input = "mul(add(input[\"data\"][0][\"name\"][][\"node\"],input[\"data\"][0]),input[\"data\"][0][\"name\"][][\"node\"][])";
ANTLRInputStream str = new ANTLRInputStream(input);
FunctionTokenizerLexer lexer = new FunctionTokenizerLexer(str);
CommonTokenStream tokens = new CommonTokenStream(lexer);
FunctionTokenizerParser parser = new FunctionTokenizerParser(tokens);
parser.removeErrorListeners(); // remove ConsoleErrorListener
parser.addErrorListener(new VerboseListener());
FunctionContext tree = parser.function();
FunctionValidateVisitorImpl visitor = new FunctionValidateVisitorImpl();
visitor.visit(tree);
System.out.println("-->"+tree.toStringTree( parser ));
AST ast=new AST(tree);
System.out.println( "Improved ParseTree:\n" + ast.toString() );
JFrame frame = new JFrame("Antlr AST");
JPanel panel = new JPanel();
TreeViewer viewr = new TreeViewer(Arrays.asList(
parser.getRuleNames()),tree);
viewr.setScale(1.5);
panel.add(viewr);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
访问者的实施适用于一个论点,但如果我传递多个论点,它就会失败。输入:
split(rrr(test(input[\"data\"][0]),input[\"data\"]),input[\"data\"])[]
输出:
visit4:::::::::::else 0 rrr(test(input["data"][0]),input["data"])
visit4:::::::::::else 2 input["data"]
visit2:::::::::::rrr(test(input["data"][0]),input["data"])input["data"]
在表达式列表方法之后,直接执行else循环,但它应该调用访问方法。表达式列表条件的实例失败,因此方法调用直接到达 else。
解决方案
对于像bar["foo"]
,这样["foo"]
的输入,你不想bar
在你的词法分析器中粘上你的东西。这是解析器应该识别为表达式的东西。
像这样的东西怎么样:
expr : expr subscript | function | STRING | NUMBER | ID;
subscript : '[' expr? ']';
这也将匹配foo()[42]
。如果您只想匹配以 开头的标识符subscript
,请更改expr subscript
为ID subscript
.
推荐阅读
- java - 像 Python 一样,Java 中是否有任何方法可以在不关闭缓冲区的情况下进行读/写?
- java - Observable Vs Completable 为什么没有调用 Completable 任务?
- php - laravel 的背包 - 更新行时出错
- unit-testing - 如何在扩展 yii2 中运行 php 单元测试
- android - JSON 对象上的空对象引用
- sql - 提取第 n 个子串
- uri - URI 是否总是有主机部分
- json - 该功能未重定向到正确的屏幕
- spring - 如何使用 Spring 5 WebClient 进行头部调用
- java - Java TreeSet 使用的内存是否比 PriorityQueue 少?