简体   繁体   English

如何编写命令行并选择合适的命令来运行?

[英]How to program a command-line and choose the appropriate command to run?

I've got the task to program a kind of commandline in Java. 我的任务是用Java编写一种命令行。

It's meant to tests parts of a compiler. 它旨在测试编译器的各个部分。 You see a promt an can type commands like "read_source ", "parse", "build_ast", "ast2cfg", "print_cfg", etc. 您会看到一个可以输入“ read_source”,“ parse”,“ build_ast”,“ ast2cfg”,“ print_cfg”等命令的promt。

Is there any library in Java that assists me in building an interpreter (or repl?). Java中是否有任何库可以帮助我构建解释器(或repl?)。 I know a python module that would do just what i want : cmd 我知道一个Python模块 可以满足 我的要求cmd

I wrote something similar myself: 我自己写了类似的东西:

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();
    }
}

It works, but it would be nice, for example, if the usage patterns such as "usage: add INTEGER INTEGER [INTEGER...]" for adding two ar more numbers would be generated according to the way the parameters are parsed so that it's less work to add new commands and to assure they are always consistent. 它可以工作,但是,例如,如果根据参数解析的方式生成用于添加两个或更多数字的使用模式(例如“用法:添加INTEGER INTEGER [INTEGER ...]”),那就很好了。添加新命令并确保它们始终保持一致的工作量减少了。

Also I'm asking myself if that's overengineered. 我也在问自己这是否设计过度。 Would you recommend just writing a loop like this?: 您是否建议只编写这样的循环?:

while(true) {
    String command = getUserInput();
    if (command.equals("dothis")) {
        dothis1();
        someMember = dothis2();
    } else if (command.equals("dothat"))
        dothat();
    } else {
        printHelp();
    }
}

Use switch case instead of if else ladder, to create more elegant code, and avoid typos. 使用开关大小写代替梯形,以创建更优雅的代码,并避免输入错误。

eg: 例如:

while(true){

  Scanner scan = new Scanner(System.in);
  String s = scan.nextLine()

    switch(s){

         case "Dothis" :
                           break;

         case "Dothat" :
                           break;




    }

You first answer does seem overly complicated. 您的第一个答案确实似乎过于复杂。 I use a lot of register code like you have but typically this is when one class is registering itself with another class. 我像您一样使用许多注册代码,但是通常这是当一个类向另一个类进行自身注册时。 The idea that the class would register itself I only use for performance reasons if you have a large number of commands and you were worried about the if {} else if {} chain taking a long time. 如果您有大量命令,并且担心if {} else if {}链花费很长时间, if {} else if {}仅出于性能方面的考虑,我会使用类自行注册的想法。

I think the simply solution (albeit not sexy) is the best here. 我认为简单的解决方案(尽管不是很性感)是这里最好的。

while(true) {
    String command = getUserInput();
    if (command.equals("dothis")) {
        dothis1();
    } else if (command.equals("dothat"))
        dothat();
    }
    ...
}

I always choose the KISS method here with an eye out for performance implications. 总是在这里选择KISS方法,着眼于性能。 Complicated code will not only trip up someone else trying to maintain your code but you will be scratching your head as well when you come back to it in 3 months. 复杂的代码不仅会使试图维护您的代码的人绊倒,而且在3个月后再次使用它时,您也会抓挠头。 :-) :-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM