简体   繁体   中英

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.

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.

Is there any library in Java that assists me in building an interpreter (or repl?). I know a python module that would do just what i want : 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.

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.

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. 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. :-)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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