Как запрограммировать командную строку и выбрать подходящую команду для запуска?
У меня есть задача запрограммировать командную строку на Java.
Он предназначен для тестирования частей компилятора. Вы видите приглашение команды can типа "read_source ", "parse", "build_ast", "ast2cfg", "print_cfg" и т. Д.
Есть ли в Java библиотека, которая помогает мне в создании интерпретатора (или repl?). Я знаю модуль Python, который будет делать то, что я хочу: CMD
Я сам написал нечто подобное:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
interface Command {
public abstract void action(String[] parameters);
}
public class Repl {
private String prompt = "\n$ ";
private HashMap<String, Command> commands;
private Command nullCommand = null;
private Command defaultCommand = null;
public Repl() {
commands = new HashMap<String, Command>();
}
public void setPrompt(String prompt) {
this.prompt = prompt;
}
public void setDefaultCommand(Command defaultCommand) {
this.defaultCommand = defaultCommand;
}
public void setNullCommand(Command nullCommand) {
this.nullCommand = nullCommand;
}
public void addCommand(String name, Command command) {
commands.put(name, command);
}
public void runRepl() {
if (nullCommand == null) {
System.err.println("There is no 'nullCommand' specified");
return;
}
if (defaultCommand == null) {
System.err.println("There is no 'defaultCommand' specified");
return;
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
String commandName;
String[] parameters;
while (true) {
System.out.print(prompt);
commandName = reader.readLine();
if (commandName == null) {
nullCommand.action(null);
} else {
parameters = commandName.trim().split("\\s+");
Command com = commands.get(parameters[0]);
if (com != null) {
com.action(parameters);
} else {
defaultCommand.action(parameters);
}
}
}
} catch (Exception e) {
e.printStackTrace();
System.err.println("Internal error within compiler: stopping compilation");
System.exit(1);
}
}
/**
* Exapmpe:
*/
public static void main(String[] args) {
Repl repl = new Repl();
repl.addCommand("printparams", new Command() {
@Override
public void action(String[] parameters) {
System.out.println(Arrays.toString(parameters));
}
});
repl.addCommand("add", new Command() {
@Override
public void action(String[] parameters) {
if (parameters.length == 3) { // {"add", "2", "3"}
try {
int x = Integer.parseInt(parameters[1]);
int y = Integer.parseInt(parameters[2]);
System.out.println("Ergebnis: " + (x + y));
} catch (NumberFormatException e) {
System.out.println("Arguments have to be integers");
}
} else {
System.out.println("There have to be two arguments");
}
}
});
Command helpcommand = new Command() {
@Override
public void action(String[] parameters) {
System.out.println("There is: 'help', 'printparams [PARAMS...]', 'exit' and 'add INTEGER INTEGER'");
}
};
repl.addCommand("help", helpcommand);
repl.setDefaultCommand(helpcommand);
Command exitcommand = new Command() {
@Override
public void action(String[] parameters) {
System.out.println("Bye!");
System.exit(0);
}
};
repl.addCommand("exit", exitcommand);
repl.setNullCommand(exitcommand);
repl.runRepl();
}
}
Это работает, но было бы хорошо, например, если бы такие шаблоны использования, как "использование: добавить INTEGER INTEGER [INTEGER...]" для добавления еще двух или более чисел, были бы сгенерированы в соответствии со способом анализа параметров, чтобы добавление новых команд и уверенность в том, что они всегда согласованы, требует меньше усилий.
Также я спрашиваю себя, не слишком ли это силен. Вы бы порекомендовали просто написать такой цикл?
while(true) {
String command = getUserInput();
if (command.equals("dothis")) {
dothis1();
someMember = dothis2();
} else if (command.equals("dothat"))
dothat();
} else {
printHelp();
}
}
2 ответа
Ваш первый ответ кажется слишком сложным. Я использую много регистрационного кода, как у вас, но обычно это когда один класс регистрируется другим классом. Мысль о том, что класс зарегистрируется сам, я использую только из соображений производительности, если у вас большое количество команд и вы беспокоитесь о if {} else if {}
цепь занимает много времени.
Я думаю, что простое решение (хотя и не сексуальное) является лучшим здесь.
while(true) {
String command = getUserInput();
if (command.equals("dothis")) {
dothis1();
} else if (command.equals("dothat"))
dothat();
}
...
}
Я всегда выбираю метод KISS, чтобы оценить эффективность. Сложный код не только сбивает с толку кого-то другого, пытающегося сохранить ваш код, но вы также почесываете голову, когда вернетесь к нему через 3 месяца.:-)
Используйте случай переключения вместо того, чтобы использовать лестницу, чтобы создать более элегантный код и избежать опечаток.
например:
while(true){
Scanner scan = new Scanner(System.in);
String s = scan.nextLine()
switch(s){
case "Dothis" :
break;
case "Dothat" :
break;
}