我正在用 Java 开发一个 shell 实作,我正在使用 antlr4 来决议语法。我想一一决议输入的命令,并将它们存盘在一个阵列串列中,稍后我将在其中执行这些命令。
例如,“echo hello; echo world”的输入应该回传两个 Call 物件的阵列串列。如果有帮助,Call 物件代表一个简单的命令。
但是,visitChildren 方法的回传值正在被最新决议的命令覆写。如何决议一个命令,将其添加到我的阵列串列中,然后继续决议下一个命令等等?
命令转换器.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 ;
uj5u.com热心网友回复:
如果你大声读出来,这个定义没有多大意义:
public Command visitCommands(ShellGrammarParser.CommandsContext ctx) {
您正在访问,commands
但希望得到Command
回报??
在这个简单的例子中,最好记住访问者不需要处理访问每个背景关系型别(这对于完整语法来说非常罕见,因为找到适用于所有节点的公共回传型别被证明是困难的) . 您可以只覆写您实际打算访问的 Context 型别的方法。
在你的情况下,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>
从呼叫中回传 a,您可以覆写类中的一些方法visitChildren()
,但上面的代码对于您的要求可能是最简单的。
0 评论