code: package edu.berkeley.nlp.PCFGLA;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Map;
  import java.util.Set;
  
  public class OptionParser {
  
  	private final Map<String, Option> nameToOption = new HashMap<String, Option>();
  
  	private final Map<String, Field> nameToField = new HashMap<String, Field>();
  
  	private final Set<String> requiredOptions = new HashSet<String>();
  
  	private final Class optionsClass;
  
  	private StringBuilder passedInOptions;
  
  	public OptionParser(Class optionsClass) {
  		this.optionsClass = optionsClass;
  		for (Field field : optionsClass.getDeclaredFields()) {
  			Option option = field.getAnnotation(Option.class);
  			if (option == null) {
  				continue;
  			}
  			nameToOption.put(option.name(), option);
  			nameToField.put(option.name(), field);
  			if (option.required()) {
  				requiredOptions.add(option.name());
  			}
  		}
  	}
  
  	private void usage() {
  		System.err.println();
  		for (Option opt : nameToOption.values()) {
  			System.err.printf("%-30s%s", opt.name(), opt.usage());
  			if (opt.required()) {
  				System.err.printf(" [required]");
  			}
  			System.err.println();
  		}
  		System.err.printf("%-30shelp message\n", "-h");
  		System.err.println();
  		System.exit(2);
  	}
  
  	public Object parse(String[] args) {
  		return parse(args, false, false);
  	}
  
  	public Object parse(String[] args, boolean failOnUnrecognized) {
  		return parse(args, failOnUnrecognized, false);
  	}
  
  	public Object parse(String[] args, boolean failOnUnrecognized,
  			boolean parrot) {
  		if (parrot)
  			System.out.println("Calling with " + Arrays.deepToString(args));
  		try {
  			Set<String> seenOpts = new HashSet<String>();
  			passedInOptions = new StringBuilder("{");
  			Object options = optionsClass.newInstance();
  			for (int i = 0; i < args.length; ++i) {
  				if (args[i].equals("-h")) {
  					usage();
  				}
  				Option opt = nameToOption.get(args[i]);
  				if (opt == null) {
  					if (failOnUnrecognized) {
  						throw new RuntimeException("Did not recognize option "
  								+ args[i]);
  					} else {
  						System.err.println("WARNING: Did not recognize option "
  								+ args[i]);
  					}
  					continue;
  				}
  				seenOpts.add(args[i]);
  				Field field = nameToField.get(args[i]);
  				Class fieldType = field.getType();
  				// If option is boolean type then
  				// we set the associate field to true
  				if (fieldType == boolean.class) {
  					field.setBoolean(options, true);
  					passedInOptions.append(String.format(" %s => true",
  							opt.name()));
  				}
  				// Otherwise look at next arg and
  				// set field to that value
  				// this will automatically
  				// convert String to double or
  				// whatever
  				else {
  					String value = args[i + 1];
  					if (value != null)
  						value.trim();
  					passedInOptions.append(String.format(" %s => %s",
  							opt.name(), value));
  					if (fieldType == int.class) {
  						field.setInt(options, Integer.parseInt(value));
  					} else if (fieldType == double.class) {
  						field.setDouble(options, Double.parseDouble(value));
  					} else if (fieldType == float.class) {
  						field.setFloat(options, Float.parseFloat(value));
  					} else if (fieldType == short.class) {
  						field.setFloat(options, Short.parseShort(value));
  					} else if (fieldType.isEnum()) {
  						Object[] possibleValues = fieldType.getEnumConstants();
  						boolean found = false;
  						for (Object possibleValue : possibleValues) {
  
  							String enumName = ((Enum) possibleValue).name();
  							if (value.equals(enumName)) {
  								field.set(options, possibleValue);
  								found = true;
  								break;
  							}
  
  						}
  						if (!found) {
  							if (failOnUnrecognized) {
  								throw new RuntimeException(
  										"Unrecognized enumeration option "
  												+ value);
  							} else {
  								System.err
  										.println("WARNING: Did not recognize option Enumeration option "
  												+ value);
  							}
  						}
  					} else if (fieldType == String.class) {
  						field.set(options, value);
  					} else {
  						try {
  							Constructor constructor = fieldType
  									.getConstructor(new Class[] { String.class });
  							field.set(
  									options,
  									constructor
  											.newInstance((Object[]) (new String[] { value })));
  						} catch (NoSuchMethodException e) {
  							System.err
  									.println("Cannot construct object of type "
  											+ fieldType.getCanonicalName()
  											+ " from just a string");
  						}
  					}
  					++i;
  				}
  			}
  			passedInOptions.append(" }");
  
  			Set<String> optionsLeft = new HashSet<String>(requiredOptions);
  			optionsLeft.removeAll(seenOpts);
  			if (!optionsLeft.isEmpty()) {
  				System.err.println("Failed to specify: " + optionsLeft);
  				usage();
  			}
  
  			return options;
  		} catch (Exception e) {
  			e.printStackTrace();
  		}
  		return null;
  	}
  
  	public String getPassedInOptions() {
  		return passedInOptions.toString();
  	}
  
  }
  