package jflex;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jflex.base.Build;
import jflex.core.OptionUtils;
import jflex.core.unicode.UnicodeProperties;
import jflex.exceptions.GeneratorException;
import jflex.exceptions.SilentExit;
import jflex.generator.LexGenerator;
import jflex.gui.MainFrame;
import jflex.l10n.ErrorMessages;
import jflex.logging.Out;
import jflex.option.Options;
public class Main {
private static List<File> parseOptions(String[] argv) throws SilentExit {
List<File> files = new ArrayList<>();
for (int i = 0; i < argv.length; i++) {
if (Objects.equals(argv[i], "-d")
|| Objects.equals(argv[i], "--outdir")) {
if (++i >= argv.length) {
Out.error(ErrorMessages.NO_DIRECTORY);
throw new GeneratorException();
}
OptionUtils.setDir(argv[i]);
continue;
}
if (Objects.equals(argv[i], "--skel")
|| Objects.equals(argv[i], "-skel")) {
if (++i >= argv.length) {
Out.error(ErrorMessages.NO_SKEL_FILE);
throw new GeneratorException();
}
OptionUtils.setSkeleton(new File(argv[i]));
continue;
}
if (Objects.equals(argv[i], "--encoding")) {
if (++i >= argv.length) {
Out.error(ErrorMessages.NO_ENCODING);
throw new GeneratorException();
}
OptionUtils.setEncoding(argv[i]);
continue;
}
if (Objects.equals(argv[i], "-jlex")
|| Objects.equals(argv[i], "--jlex")) {
Options.jlex = true;
continue;
}
if (Objects.equals(argv[i], "-v")
|| Objects.equals(argv[i], "--verbose")
|| Objects.equals(argv[i], "-verbose")) {
Options.verbose = true;
Options.progress = true;
Options.unused_warning = true;
continue;
}
if (Objects.equals(argv[i], "-q")
|| Objects.equals(argv[i], "--quiet")
|| Objects.equals(argv[i], "-quiet")) {
Options.verbose = false;
Options.progress = false;
Options.unused_warning = false;
continue;
}
if (Objects.equals(argv[i], "--warn-unused")) {
Options.unused_warning = true;
continue;
}
if (Objects.equals(argv[i], "--no-warn-unused")) {
Options.unused_warning = false;
continue;
}
if (Objects.equals(argv[i], "--dump")
|| Objects.equals(argv[i], "-dump")) {
Options.dump = true;
continue;
}
if (Objects.equals(argv[i], "--time")
|| Objects.equals(argv[i], "-time")) {
Options.time = true;
continue;
}
if (Objects.equals(argv[i], "--version")
|| Objects.equals(argv[i], "-version")) {
Out.println(ErrorMessages.THIS_IS_JFLEX, Build.VERSION);
throw new SilentExit(0);
}
if (Objects.equals(argv[i], "--dot")
|| Objects.equals(argv[i], "-dot")) {
Options.dot = true;
continue;
}
if (Objects.equals(argv[i], "--help")
|| Objects.equals(argv[i], "-h")
|| Objects.equals(argv[i], "/h")) {
printUsage();
throw new SilentExit(0);
}
if (Objects.equals(argv[i], "--info")
|| Objects.equals(argv[i], "-info")) {
printSystemInfo();
throw new SilentExit(0);
}
if (Objects.equals(argv[i], "--nomin")
|| Objects.equals(argv[i], "-nomin")) {
Options.no_minimize = true;
continue;
}
if (Objects.equals(argv[i], "--pack")
|| Objects.equals(argv[i], "-pack")) {
continue;
}
if (Objects.equals(argv[i], "--nobak")
|| Objects.equals(argv[i], "-nobak")) {
Options.no_backup = true;
continue;
}
if (Objects.equals(argv[i], "--legacydot")
|| Objects.equals(argv[i], "-legacydot")) {
Options.legacy_dot = true;
continue;
}
if (Objects.equals(argv[i], "--uniprops")
|| Objects.equals(argv[i], "-uniprops")) {
if (++i >= argv.length) {
Out.error(
ErrorMessages.PROPS_ARG_REQUIRES_UNICODE_VERSION, UnicodeProperties.UNICODE_VERSIONS);
throw new GeneratorException();
}
String unicodeVersion = argv[i];
try {
printUnicodePropertyValuesAndAliases(unicodeVersion);
} catch (UnicodeProperties.UnsupportedUnicodeVersionException e) {
Out.error(
ErrorMessages.UNSUPPORTED_UNICODE_VERSION_SUPPORTED_ARE,
UnicodeProperties.UNICODE_VERSIONS);
throw new GeneratorException(e);
}
throw new SilentExit();
}
if (argv[i].startsWith("-")) {
Out.error(ErrorMessages.UNKNOWN_COMMANDLINE, argv[i]);
printUsage();
throw new SilentExit();
}
File f = new File(argv[i]);
if (f.isFile() && f.canRead()) files.add(f);
else {
Out.error("Sorry, couldn't open \"" + f + "\"");
throw new GeneratorException();
}
}
return files;
}
private static void printUnicodePropertyValuesAndAliases(String unicodeVersion)
throws UnicodeProperties.UnsupportedUnicodeVersionException {
Pattern versionPattern = Pattern.compile("(\\d+)(?:\\.(\\d+))?(?:\\.\\d+)?");
Matcher matcher = versionPattern.matcher(unicodeVersion);
if (!matcher.matches()) {
throw new UnicodeProperties.UnsupportedUnicodeVersionException();
}
String underscoreVersion =
matcher.group(1) + (null == matcher.group(2) ? "_0" : "_" + matcher.group(2));
String[] propertyValues;
String[] propertyValueAliases;
try {
Class<?> clazz = Class.forName("jflex.unicode.data.Unicode_" + underscoreVersion);
Field field = clazz.getField("propertyValues");
propertyValues = (String[]) field.get(null);
field = clazz.getField("propertyValueAliases");
propertyValueAliases = (String[]) field.get(null);
} catch (Exception e) {
throw new UnicodeProperties.UnsupportedUnicodeVersionException(e);
}
SortedMap<String, SortedSet<String>> propertyValuesToAliases = new TreeMap<>();
for (String value : propertyValues) {
propertyValuesToAliases.put(value, new TreeSet<String>());
}
for (int i = 0; i < propertyValueAliases.length - 1; i += 2) {
String alias = propertyValueAliases[i];
String value = propertyValueAliases[i + 1];
SortedSet<String> aliases = propertyValuesToAliases.get(value);
if (null == aliases) {
aliases = new TreeSet<>();
propertyValuesToAliases.put(value, aliases);
}
aliases.add(alias);
}
for (Map.Entry<String, SortedSet<String>> entry : propertyValuesToAliases.entrySet()) {
String value = entry.getKey();
SortedSet<String> aliases = entry.getValue();
Out.print(value);
if (aliases.size() > 0) {
for (String alias : aliases) {
Out.print(", " + alias);
}
}
Out.println("");
}
}
private static void printUsage() {
Out.println("");
Out.println("Usage: jflex <options> <input-files>");
Out.println("");
Out.println("Where <options> can be one or more of");
Out.println("-d <directory> write generated file to <directory>");
Out.println("--skel <file> use external skeleton <file>");
Out.println("--encoding <name> use <name> as input/output encoding");
Out.println("--pack set default code generation method (default)");
Out.println("--jlex strict JLex compatibility");
Out.println("--legacydot dot (.) metachar matches [^\\n] instead of");
Out.println(" [^\\n\\r\\u000B\\u000C\\u0085\\u2028\\u2029]");
Out.println("--nomin skip minimization step");
Out.println("--nobak don't create backup files");
Out.println("--dump display transition tables");
Out.println("--dot write graphviz .dot files for the generated automata (alpha)");
Out.println("--verbose");
Out.println("-v display generation progress messages (default)");
Out.println("--quiet");
Out.println("-q display errors only");
Out.println("--time display generation time statistics");
Out.println("--version print the version number of this copy of jflex");
Out.println("--info print system + JDK information");
Out.println("--uniprops <ver> print all supported properties for Unicode version <ver>");
Out.println("--help");
Out.println("-h print this message");
Out.println("");
Out.println(ErrorMessages.THIS_IS_JFLEX, Build.VERSION);
Out.println("Have a nice day!");
}
public static void generate(String[] argv) throws SilentExit {
List<File> files = parseOptions(argv);
if (files.size() > 0) {
for (File file : files) {
new LexGenerator(file).generate();
}
} else {
new MainFrame();
}
}
public static void main(String[] argv) {
OptionUtils.setDefaultOptions();
try {
generate(argv);
} catch (GeneratorException e) {
if (e.isUnExpected()) {
Out.error(
"Unexpected exception encountered. This indicates a bug in JFlex."
+ Out.NL
+ "Please consider filing an issue at http://github.com/jflex-de/jflex/issues/new"
+ Out.NL);
Throwable cause = e.getCause();
if (cause != null) {
String msg = cause.getLocalizedMessage();
if (msg != null) Out.error(msg);
cause.printStackTrace();
}
} else {
Out.statistics();
}
System.exit(1);
} catch (SilentExit e) {
System.exit(e.exitCode());
}
}
private Main() {}
public static void printSystemInfo() {
Out.err("Java version: " + System.getProperty("java.version"));
Out.err("Runtime name: " + System.getProperty("java.runtime.name"));
Out.err("Vendor: " + System.getProperty("java.vendor"));
Out.err("VM version: " + System.getProperty("java.vm.version"));
Out.err("VM vendor: " + System.getProperty("java.vm.vendor"));
Out.err("VM name: " + System.getProperty("java.vm.name"));
Out.err("VM info: " + System.getProperty("java.vm.info"));
Out.err("OS name: " + System.getProperty("os.name"));
Out.err("OS arch: " + System.getProperty("os.arch"));
Out.err("OS version: " + System.getProperty("os.version"));
Out.err("Encoding: " + System.getProperty("file.encoding"));
Out.err("Unicode versions: " + UnicodeProperties.UNICODE_VERSIONS);
Out.err("JFlex version: " + Build.VERSION);
}
}