我正在用Java开发一个shell实现,并使用antlr4解析语法。我希望一个一个地解析输入命令,并将它们存储在一个数组中,稍后我将在其中执行这些命令。
例如,"echo hello;echo world“的输入应该返回由两个调用对象组成的数组。如果有帮助,则调用对象表示一个简单的命令。
但是,visitChildren方法的返回值正在被最新解析的命令覆盖。我如何解析一个命令,将它添加到我的数组列表中,然后继续解析下一个命令等等?
CommandConverter.java
package parse;
import java.util.ArrayList;
import app.ApplicationFactory;
import shell.ShellGrammarBaseVisitor;
import shell.ShellGrammarParser;
public class CommandConverter extends ShellGrammarBaseVisitor<Command> {
ApplicationFactory appFactory = new ApplicationFactory();
@Override
public Command visitCommands(ShellGrammarParser.CommandsContext ctx) {
//ArrayList<Command> commands = new ArrayList<>();
return visitChildren(ctx);
}
@Override
public Command visitAtomicCommand(ShellGrammarParser.AtomicCommandContext ctx) {
int childCount = ctx.getChildCount();
String appName = ctx.getChild(0).getText();
ArrayList<String> appArgs = new ArrayList<>();
if(childCount > 1) {
for (int i = 1; i < childCount; i++) {
appArgs.add(ctx.getChild(i).getText());
}
}
return new Call(appFactory.getApplication(appName), appArgs);
}
}ShellGrammar.g4 (部分)
grammar ShellGrammar;
/*
* Parser Rules
*/
commands : atomicCommand (';' atomicCommand )*
atomicCommand : NONSPECIAL (value)*;
value : (NONSPECIAL | DOUBLEQUOTED | SINGLEQUOTED);
/*
* Lexer Rules
*/
NONSPECIAL : ~['";\r\n\t ]+;
DOUBLEQUOTED : '"' (~'"')* '"';
SINGLEQUOTED : '\'' (~'\'')* '\'';
WHITESPACE : [\r\n\t ]+ -> skip ;发布于 2021-12-13 20:09:24
如果你大声读出来,这个定义就没什么意义了:
public Command visitCommands(ShellGrammarParser.CommandsContext ctx) {你正在访问commands,但希望得到Command作为回报??
在这个简单的例子中,最好记住访问者不需要处理访问每种上下文类型(这对于一个完整的语法是非常罕见的,因为找到一个适用于所有节点的通用返回类型是很困难的)。您只需重写实际要访问的上下文类型的方法。
在您的例子中,commands是您的“顶级”规则,因此您从解析中得到的解析树节点(使用parser.commands();调用)将是一个CommandsContext。
您可以做一些类似于:(其中pt是从解析中得到的节点)。
for (AtomicCommandContext child : pt.children) {
// handle the child command
// could be adding it to a list
// could be just processing the command
}命令的好处是,您负责为每个孩子打电话给访问者。visitChildren只是一种方便的方法,可以遍历所有为您调用访问者的子程序。
如果希望使访问者在调用Visitor时返回一个List<Command>,可以重写List<Command>类中的一些方法,但是上面的代码可能是您所要求的最简单的代码。
https://stackoverflow.com/questions/70339829
复制相似问题