summaryrefslogtreecommitdiff
path: root/RGens/src/main/java/bjc/rgens
diff options
context:
space:
mode:
authorstudent <student@student-OptiPlex-9020>2017-03-17 10:49:27 -0400
committerstudent <student@student-OptiPlex-9020>2017-03-17 10:49:27 -0400
commit0ea49dd4a52358f053c9be7138c392b16de05899 (patch)
tree802e275aaf279480ee8626136f56bfa1fbab6845 /RGens/src/main/java/bjc/rgens
parent36cf3a0f0604ef43ce838ff6e9a7fc4e7c299522 (diff)
Move things around, and start on new parser.
Diffstat (limited to 'RGens/src/main/java/bjc/rgens')
-rw-r--r--RGens/src/main/java/bjc/rgens/.DS_Storebin0 -> 6148 bytes
-rw-r--r--RGens/src/main/java/bjc/rgens/ZadronsPouch.java219
-rw-r--r--RGens/src/main/java/bjc/rgens/gui/GrammarStudio.java26
-rw-r--r--RGens/src/main/java/bjc/rgens/gui/GrammarStudioFrame.java30
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/RGrammar.java5
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java7
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java110
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/.DS_Storebin0 -> 6148 bytes
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/GrammarReaderApp.java93
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/GrammarReaderCLI.java61
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/PragmaErrorException.java21
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/RBGrammarReader.java319
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/ReaderState.java306
-rw-r--r--RGens/src/main/java/bjc/rgens/server/CLIArgsParser.java141
-rw-r--r--RGens/src/main/java/bjc/rgens/server/GrammarServer.java346
-rw-r--r--RGens/src/main/java/bjc/rgens/server/GrammarServerEngine.java300
-rw-r--r--RGens/src/main/java/bjc/rgens/server/ReaderState.java181
-rw-r--r--RGens/src/main/java/bjc/rgens/server/ServerGrammarReader.java326
-rwxr-xr-xRGens/src/main/java/bjc/rgens/text/markov/Markov.java189
-rw-r--r--RGens/src/main/java/bjc/rgens/text/markov/StandaloneMarkov.java42
-rw-r--r--RGens/src/main/java/bjc/rgens/text/markov/StandaloneTextGenerator.java70
-rwxr-xr-xRGens/src/main/java/bjc/rgens/text/markov/TextGenerator.java69
22 files changed, 2861 insertions, 0 deletions
diff --git a/RGens/src/main/java/bjc/rgens/.DS_Store b/RGens/src/main/java/bjc/rgens/.DS_Store
new file mode 100644
index 0000000..918453d
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/.DS_Store
Binary files differ
diff --git a/RGens/src/main/java/bjc/rgens/ZadronsPouch.java b/RGens/src/main/java/bjc/rgens/ZadronsPouch.java
new file mode 100644
index 0000000..7160bdd
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/ZadronsPouch.java
@@ -0,0 +1,219 @@
+package bjc.rgens;
+
+import bjc.utils.funcdata.FunctionalStringTokenizer;
+import bjc.utils.funcdata.IList;
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.gen.RandomGrammar;
+
+/**
+ * Example showing code manipulate of random grammars
+ *
+ * @author ben
+ *
+ */
+public class ZadronsPouch {
+ /**
+ * Main method for running application
+ *
+ * @param args
+ * Unused CLI args
+ */
+ public static void main(String[] args) {
+ ZadronsPouch zp = new ZadronsPouch();
+
+ for (int i = 0; i < 100; i++) {
+ IList<String> ls = zp.grammar.generateListValues("[item]", " ");
+
+ StringBuilder sb = new StringBuilder();
+
+ ls.forEach(sp -> sb.append(sp));
+
+ System.out.println(sb.toString().replaceAll("\\s+", " "));
+ }
+ }
+
+ private RandomGrammar<String> grammar;
+
+ /**
+ * Create a new instance with a grammar
+ */
+ public ZadronsPouch() {
+ grammar = new RandomGrammar<>();
+
+ addRule("[item]",
+ "[egg]", "[glove]", "[crys-sphere]", "[rock]",
+ "[figurine]", "[vial]", "[mini-weapon]", "[bag]",
+ "[card]", "[rope]", "[box]", "[wand]");
+
+ addEggRules();
+ addGloveRules();
+ addCrysSphereRules();
+ addRockRules();
+
+ addFigurineRules();
+ addVialRules();
+ addMiniWeaponRules();
+ addBagRules();
+
+ addCardRules();
+ addRopeRules();
+ addBoxRules();
+ addWandRules();
+ }
+
+ private void addBagRules() {
+ addRule("[bag]",
+ "bag of [bag-type]", "[sack-type] sack", "[purse-type] purse");
+ addRule("[bag-type]",
+ "holding", "tricks", "useful items",
+ "devouring", "dwarf-kind", "invisible cloth",
+ "monster summoning");
+ addRule("[sack-type]",
+ "lunch", "recursive");
+ addRule("[purse-type]",
+ "everfull");
+ }
+
+ private void addBoxRules() {
+ addRule("[box]",
+ "[box-type] box", "cube of [box-type]");
+ addRule("[box-type]",
+ "limited-force", "frost-resisting", "morphing",
+ "self-destructing", "pandora", "panicking");
+ }
+
+ private void addCardRules() {
+ addRule("[card]",
+ "card of [card-type]", "[card-type] card");
+ addRule("[card-type]",
+ "fate", "teleporting", "elusive treasure", "spell-storing",
+ "many-things", "imprisoning", "messaging", "bounty");
+ }
+
+ private void addCrysSphereRules() {
+ addRule("[crys-sphere]",
+ "[sphere-type] spheres", "[sphere-type] sphere",
+ "lens of [lens-type]", "[crystal-type] crystal",
+ "crystal of [crystal-type]", "crystal ball",
+ "crystal ball of [crys-suffix]");
+ addRule("[sphere-type]",
+ "microphonic", "seeing-eye");
+ addRule("[lens-type]",
+ "detection");
+ addRule("[crystal-type]",
+ "prison", "radar");
+ addRule("[crys-suffix]",
+ "jumping");
+ }
+
+ private void addEggRules() {
+ addRule("[egg]",
+ "[egg-type] egg");
+ addRule("[egg-type]",
+ "copper", "stone", "golden",
+ "white", "white/pink", "glass");
+ }
+
+ private void addFigurineRules() {
+ addRule("[figurine]",
+ "[fig-material] [fig-animal]");
+ addRule("[fig-material]",
+ "golden", "onyx", "serpentine", "ivory",
+ "marble", "bronze", "jade", "limestone");
+ addRule("[fig-animal]",
+ "lion", "dog", "owl", "goat",
+ "elephant", "warrior", "palace", "leprechaun");
+ }
+
+ private void addGloveRules() {
+ addRule("[glove]",
+ "gauntlets of [gauntlet-type]",
+ "gloves of [glove-type]",
+ "[glove-type] gloves");
+ addRule("[gauntlet-type]",
+ "dexterity", "power");
+ addRule("[glove-type]",
+ "pushing", "choking", "bigby", "stunning");
+ }
+
+ private void addMiniWeaponRules() {
+ addRule("[mini-weapon]",
+ "minature [weapon-type]", "small [weapon-type]",
+ "tiny [weapon-type]", "[sling-type] sling",
+ "[weapon-type]");
+ addRule("[weapon-type]",
+ "boomerang", "arrow", "net",
+ "catapult", "hammer", "sword", "club");
+ addRule("[sling-type]",
+ "seeking");
+ }
+
+ private void addRockRules() {
+ addRule("[rock]",
+ "[pebble-type] pebble", "stone of [stone-type]",
+ "[stone-type] stone", "brick of [brick-type]",
+ "[geode-type] geode");
+ addRule("[pebble-type]",
+ "inscribed", "elemental control");
+ addRule("[stone-type]",
+ "good-luck", "weight",
+ "blind-defense", "metal-clinging");
+ addRule("[brick-type]",
+ "flying");
+ addRule("[geode-type]",
+ "ioun");
+ }
+
+ private void addRopeRules() {
+ addRule("[rope]",
+ "[rope-type] rope", "rope of [rope-type]",
+ "ball of [string-type] [string-kind]");
+ addRule("[rope-type]",
+ "trick", "entangling", "climbing", "dancing",
+ "tripping", "snaring", "levitating", "self-entangling");
+ addRule("[string-type]",
+ "endless");
+ addRule("[string-kind]",
+ "string", "yarn");
+ }
+
+ private void addRule(String rule, String... cases) {
+ IList<IList<String>> cses = new FunctionalList<>();
+
+ for (String strang : cases) {
+ cses.add(FunctionalStringTokenizer.fromString(strang).toList(s -> s));
+ }
+
+ grammar.makeRule(rule, cses);
+ }
+
+ private void addVialRules() {
+ addRule("[vial]",
+ "vial of [vial-type]", "[vial-type] vial",
+ "[bottle-type] bottle", "[flask-type] flask");
+ addRule("[vial-type]",
+ "holding", "trapping",
+ "experience", "unnatural regeneration");
+ addRule("[bottle-type]",
+ "ever-smoking", "wheezing",
+ "blank potion");
+ addRule("[flask-type]",
+ "iron");
+ }
+
+ private void addWandRules() {
+ addRule("[wand]",
+ "[wand-type] wand", "wand of [wand-type]",
+ "canceling [wand-type] wand");
+ addRule("[wand-type]",
+ "magic missile", "[spell-1]", "[spell-2]",
+ "gusting", "life-detecting", "zadron");
+ addRule("[spell-1]",
+ "frost", "fire", "lightning", "fear",
+ "illumination", "polymorphing", "conjuration", "paralyzing");
+ addRule("[spell-2]",
+ "[spell2-type] detecting");
+ addRule("[spell2-type]",
+ "magic", "enemy", "secret door/trap");
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/gui/GrammarStudio.java b/RGens/src/main/java/bjc/rgens/gui/GrammarStudio.java
new file mode 100644
index 0000000..46f0d6e
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/gui/GrammarStudio.java
@@ -0,0 +1,26 @@
+package bjc.rgens.gui;
+
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+public class GrammarStudio {
+ public static void main(String[] args) {
+ try {
+ UIManager.setLookAndFeel(
+ UIManager.getSystemLookAndFeelClassName());
+ } catch (ClassNotFoundException | InstantiationException
+ | IllegalAccessException
+ | UnsupportedLookAndFeelException ex) {
+ System.out.println(
+ "WARNING: Could not use system look and feel");
+ ex.printStackTrace();
+ }
+
+ GrammarStudioFrame mainFrame = new GrammarStudioFrame();
+
+ mainFrame.setDefaultCloseOperation(
+ GrammarStudioFrame.EXIT_ON_CLOSE);
+
+ mainFrame.setVisible(true);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/gui/GrammarStudioFrame.java b/RGens/src/main/java/bjc/rgens/gui/GrammarStudioFrame.java
new file mode 100644
index 0000000..17021fc
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/gui/GrammarStudioFrame.java
@@ -0,0 +1,30 @@
+package bjc.rgens.gui;
+
+import javax.swing.JDesktopPane;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+
+import bjc.utils.gui.layout.AutosizeLayout;
+
+public class GrammarStudioFrame extends JFrame {
+ private static final long serialVersionUID = 1476431892446002428L;
+
+ public GrammarStudioFrame() {
+ super("Grammar Studio");
+
+ setLayout(new AutosizeLayout());
+
+ JDesktopPane mainPane = new JDesktopPane();
+
+ JMenuBar menuBar = new JMenuBar();
+
+ JMenu fileMenu = new JMenu("File");
+ fileMenu.setMnemonic('m');
+
+ menuBar.add(fileMenu);
+
+ setJMenuBar(menuBar);
+ add(mainPane);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java
new file mode 100644
index 0000000..9b47bd6
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java
@@ -0,0 +1,5 @@
+package bjc.rgens.newparser;
+
+public class RGrammar {
+
+}
diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java
new file mode 100644
index 0000000..3b48a2a
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java
@@ -0,0 +1,7 @@
+package bjc.rgens.newparser;
+
+public class RGrammarBuilder {
+ public RGrammar toRGrammar() {
+ return null;
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java
new file mode 100644
index 0000000..d60c6d4
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java
@@ -0,0 +1,110 @@
+package bjc.rgens.newparser;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.StringReader;
+import java.util.Scanner;
+
+/**
+ * Reads {@link RGrammar} from a input stream.
+ *
+ * @author student
+ *
+ */
+public class RGrammarParser {
+ /**
+ * The exception thrown when something goes wrong while parsing a grammar.
+ *
+ * @author student
+ *
+ */
+ public static class GrammarException extends Exception {
+ /*
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -7287427479316953668L;
+
+ /**
+ * Create a new grammar exception with the specified message.
+ *
+ * @param msg
+ * The message for this exception.
+ */
+ public GrammarException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Create a new grammar exception with the specified message and cause.
+ *
+ * @param msg
+ * The message for this exception.
+ *
+ * @param cause
+ * The cause of this exception.
+ */
+ public GrammarException(String msg, Exception cause) {
+ super(msg, cause);
+ }
+ }
+
+ /**
+ * Read a {@link RGrammar} from an input stream.
+ *
+ * @param is
+ * The input stream to read from.
+ *
+ * @return The grammar represented by the stream.
+ *
+ * @throws GrammarException
+ * Thrown if the grammar has a syntax error.
+ */
+ public RGrammar readGrammar(InputStream is) throws GrammarException {
+ LineNumberReader lnReader = new LineNumberReader(new InputStreamReader(is));
+
+ try (Scanner scn = new Scanner(lnReader)) {
+ scn.useDelimiter("\\n\\.?\\n");
+
+ RGrammarBuilder build = new RGrammarBuilder();
+
+ while (scn.hasNext()) {
+ String block = scn.next();
+
+ if (block.startsWith("pragma")) {
+ handlePragmaBlock(block, build);
+ } else if (block.startsWith("[")) {
+ handleRuleBlock(block, build);
+ } else {
+ throw new GrammarException(String.format("Unknown block: %s", lnReader.getLineNumber(), block));
+ }
+ }
+ } catch (GrammarException gex) {
+ throw new GrammarException(String.format("Error at line %d", lnReader.getLineNumber()), gex);
+ }
+
+ return null;
+ }
+
+ private void handlePragmaBlock(String block, RGrammarBuilder build) throws GrammarException {
+ LineNumberReader lnReader = new LineNumberReader(new StringReader(block));
+
+ try (Scanner deblocker = new Scanner(lnReader)) {
+ deblocker.useDelimiter("\\n(?!\\t)");
+
+ while (deblocker.hasNext()) {
+ String pragma = deblocker.next();
+
+ if (!pragma.startsWith("pragma")) {
+ throw new GrammarException(String.format("Illegal line at line %d of pragma block: %s",
+ lnReader.getLineNumber(), pragma));
+ }
+ }
+ }
+ }
+
+ private void handleRuleBlock(String block, RGrammarBuilder build) {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/.DS_Store b/RGens/src/main/java/bjc/rgens/parser/.DS_Store
new file mode 100644
index 0000000..5008ddf
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/.DS_Store
Binary files differ
diff --git a/RGens/src/main/java/bjc/rgens/parser/GrammarReaderApp.java b/RGens/src/main/java/bjc/rgens/parser/GrammarReaderApp.java
new file mode 100644
index 0000000..b3beb81
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/GrammarReaderApp.java
@@ -0,0 +1,93 @@
+package bjc.rgens.parser;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+import bjc.utils.funcutils.ListUtils;
+import bjc.utils.gen.WeightedGrammar;
+import bjc.utils.gui.SimpleDialogs;
+import bjc.utils.gui.awt.SimpleFileDialog;
+
+/**
+ * App that reads a grammar from a file and generates results
+ *
+ * @author ben
+ *
+ */
+public class GrammarReaderApp {
+ /**
+ * Main method of class
+ *
+ * @param args
+ * CLI args
+ */
+ public static void main(String[] args) {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (ClassNotFoundException
+ | InstantiationException
+ | IllegalAccessException
+ | UnsupportedLookAndFeelException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ doSingleFile();
+ }
+
+ private static void doSingleFile() {
+ File gramFile = SimpleFileDialog.getOpenFile(null, "Choose Grammar File", ".gram");
+
+ WeightedGrammar<String> grammar = null;
+
+ try {
+ grammar = RBGrammarReader.fromPath(gramFile.toPath());
+ } catch (IOException ioex) {
+ ioex.printStackTrace();
+
+ System.exit(1);
+ }
+
+ String initRule = "";
+
+ if (!grammar.hasInitialRule()) {
+ grammar.getRuleNames().sort((leftString, rightString) -> {
+ return leftString.compareTo(rightString);
+ });
+
+ initRule = SimpleDialogs.getChoice(null,
+ "Pick a initial rule",
+ "Pick a initial rule to generate choices from",
+ grammar.getRuleNames().toArray(new String[0]));
+ } else {
+ initRule = grammar.getInitialRule();
+ }
+
+ int count = SimpleDialogs.getWhole(null,
+ "Enter number of repetitions",
+ "Enter the number of items to generate from the rule");
+
+ File outputFile = SimpleFileDialog.getSaveFile(null, "Choose Grammar File");
+
+ PrintStream outputStream = null;
+
+ try {
+ outputStream = new PrintStream(outputFile);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ for (int i = 0; i < count; i++) {
+ String ruleResult = ListUtils.collapseTokens(grammar.generateListValues(initRule, " "));
+
+ outputStream.println(ruleResult.replaceAll("\\s+", " "));
+ }
+
+ outputStream.close();
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/GrammarReaderCLI.java b/RGens/src/main/java/bjc/rgens/parser/GrammarReaderCLI.java
new file mode 100644
index 0000000..b8eac35
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/GrammarReaderCLI.java
@@ -0,0 +1,61 @@
+package bjc.rgens.parser;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import bjc.utils.funcutils.ListUtils;
+import bjc.utils.gen.WeightedGrammar;
+
+/**
+ * App that reads a grammar from a file and generates results
+ *
+ * @author ben
+ *
+ */
+public class GrammarReaderCLI {
+ private static WeightedGrammar<String> grammar = null;
+
+ /**
+ * Main application method
+ *
+ * @param args
+ * CLI args
+ */
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ GrammarReaderApp.main(args);
+ } else {
+ String fName = args[0];
+
+ if (fName.equalsIgnoreCase("--help")) {
+ System.out.println(
+ "Usage: java -jar GrammarReader.jar <file-name> <init-rule> <num-res>");
+ System.exit(0);
+ }
+
+ String ruleName = args[1];
+
+ try (FileInputStream fStream = new FileInputStream(fName)) {
+ grammar = RBGrammarReader.fromPath(Paths.get(fName, ""));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ if (ruleName.equalsIgnoreCase("--list-rules")) {
+ grammar.getRuleNames().forEach(System.out::println);
+
+ System.exit(0);
+ }
+
+ int rCount = Integer.parseInt(args[2]);
+
+ for (int i = 0; i < rCount; i++) {
+ String ruleResult = ListUtils.collapseTokens(
+ grammar.generateListValues(ruleName, " "));
+
+ System.out.println(ruleResult.replaceAll("\\s+", " "));
+ }
+ }
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/PragmaErrorException.java b/RGens/src/main/java/bjc/rgens/parser/PragmaErrorException.java
new file mode 100644
index 0000000..05b71d3
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/PragmaErrorException.java
@@ -0,0 +1,21 @@
+package bjc.rgens.parser;
+
+/**
+ * Exception for error executing a pragma
+ *
+ * @author ben
+ *
+ */
+public class PragmaErrorException extends RuntimeException {
+ private static final long serialVersionUID = 7245421182038076899L;
+
+ /**
+ * Create a new exception with the given message
+ *
+ * @param message
+ * The message of the exception
+ */
+ public PragmaErrorException(String message) {
+ super(message);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/RBGrammarReader.java b/RGens/src/main/java/bjc/rgens/parser/RBGrammarReader.java
new file mode 100644
index 0000000..7753d25
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/RBGrammarReader.java
@@ -0,0 +1,319 @@
+package bjc.rgens.parser;
+
+import com.mifmif.common.regex.Generex;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Random;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+
+import bjc.utils.funcdata.FunctionalStringTokenizer;
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.FunctionalMap;
+import bjc.utils.funcdata.IList;
+import bjc.utils.funcdata.IMap;
+import bjc.utils.funcutils.ListUtils;
+import bjc.utils.gen.WeightedGrammar;
+import bjc.utils.parserutils.RuleBasedConfigReader;
+
+/**
+ * Read a grammar from a stream
+ *
+ * @author ben
+ *
+ */
+public class RBGrammarReader {
+ private static RuleBasedConfigReader<ReaderState> reader;
+
+ private static Random numgen = new Random();
+
+ static {
+ setupReader();
+
+ initPragmas();
+ }
+
+ private static void addSubgrammarPragmas() {
+ reader.addPragma("new-sub-grammar", (tokenizer, state) -> {
+ state.startNewSubgrammar();
+ });
+
+ reader.addPragma("load-sub-grammar", RBGrammarReader::loadSubGrammar);
+ reader.addPragma("save-sub-grammar", RBGrammarReader::saveGrammar);
+ reader.addPragma("edit-sub-grammar", RBGrammarReader::editSubGrammar);
+ reader.addPragma("remove-sub-grammar", RBGrammarReader::removeSubGrammar);
+
+ reader.addPragma("edit-parent", (tokenizer, state) -> {
+ state.editParent();
+ });
+
+ reader.addPragma("promote", RBGrammarReader::promoteGrammar);
+ reader.addPragma("subordinate", RBGrammarReader::subordinateGrammar);
+
+ }
+
+ private static void debugGrammar(ReaderState state) {
+ System.out.println("Printing rule names: ");
+
+ for (String currentRule : state.getRuleNames().toIterable()) {
+ System.out.println("\t" + currentRule);
+ }
+
+ System.out.println();
+ }
+
+ private static void doCase(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ int ruleProbability = readOptionalProbability(tokenizer, state);
+
+ state.addCase(ruleProbability, tokenizer.toList());
+ }
+
+ private static void editSubGrammar(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String subgrammarName = tokenizer.nextToken();
+
+ state.editSubgrammar(subgrammarName);
+ }
+
+ /**
+ * Read a grammar from a path
+ *
+ * @param inputPath
+ * The path to load the grammar from
+ *
+ * @return A grammar read from the stream
+ *
+ * @throws IOException
+ * If something goes wrong during file reading
+ *
+ */
+ public static WeightedGrammar<String> fromPath(Path inputPath) throws IOException {
+ ReaderState initialState = new ReaderState(inputPath);
+
+ try (FileInputStream inputStream = new FileInputStream(inputPath.toFile())) {
+ WeightedGrammar<String> gram = reader.fromStream(inputStream, initialState).getGrammar();
+
+ IMap<String, IList<String>> vars = new FunctionalMap<>();
+
+ Predicate<String> specialPredicate = (strang) -> {
+ if(strang.matches("\\{\\S+\\}") || strang.matches("\\[\\S+\\}")) {
+ return true;
+ }
+
+ return false;
+ };
+
+ BiFunction<String, WeightedGrammar<String>, IList<String>>
+ specialAction = (strang, gramm) -> {
+ IList<String> retList = new FunctionalList<>();
+
+ if(strang.matches("\\{\\S+\\}")) {
+ if(strang.matches("\\{\\S+:=\\S+\\}")) {
+ String[] varParts = strang.split(":=");
+
+ String varName = varParts[0].substring(1);
+ String ruleName = varParts[1].substring(0, varParts[1].length());
+
+ IList<String> varValue = gramm.generateGenericValues(
+ ruleName, (s) -> s, " ");
+
+ vars.put(varName, varValue);
+ } else if(strang.matches("\\{\\S+=\\S+\\}")) {
+ String[] varParts = strang.split("=");
+
+ String varName = varParts[0].substring(1);
+ String varValue = varParts[1].substring(0, varParts[1].length());
+
+ vars.put(varName, new FunctionalList<>(varValue));
+ } else {
+ // @FIXME notify the user they did something wrong
+ retList.add(strang);
+ }
+ } else {
+ if(strang.matches("\\[\\$\\S+\\]")) {
+ String varName = strang.substring(2, strang.length());
+
+ retList = vars.get(varName);
+ } else if(strang.matches("\\[\\$\\S+\\-\\S+\\]")) {
+ String[] varParts = strang.substring(1, strang.length()).split("-");
+
+ StringBuilder actualName = new StringBuilder("[");
+
+ for(String varPart : varParts) {
+ if(varPart.startsWith("$")) {
+ IList<String> varName = vars.get(varPart.substring(1));
+
+ if(varName.getSize() != 1) {
+ // @FIXME notify the user they did something wrong
+ }
+
+ actualName.append(varName.first() + "-");
+ } else {
+ actualName.append(varPart + "-");
+ }
+ }
+
+ // Trim trailing -
+ actualName.deleteCharAt(actualName.length() - 1);
+ actualName.append("]");
+
+ retList = gramm.generateGenericValues(actualName.toString(), (s) -> s, " ");
+ } else {
+ // @FIXME notify the user they did something wrong
+ retList.add(strang);
+ }
+ }
+
+ return retList;
+ };
+
+ gram.configureSpecial(specialPredicate, specialAction);
+
+ return gram;
+ } catch (IOException ioex) {
+ throw ioex;
+ }
+ }
+
+ private static void importRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+ String subgrammarName = tokenizer.nextToken();
+
+ state.addGrammarAlias(subgrammarName, ruleName);
+ }
+
+ private static void initialRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String initialRuleName = tokenizer.nextToken();
+
+ state.setInitialRule(initialRuleName);
+ }
+
+ private static void initPragmas() {
+ addSubgrammarPragmas();
+
+ reader.addPragma("debug", (tokenizer, state) -> {
+ debugGrammar(state);
+ });
+
+ reader.addPragma("uniform", (tokenizer, state) -> {
+ state.toggleUniformity();
+ });
+
+ reader.addPragma("initial-rule", RBGrammarReader::initialRule);
+
+ reader.addPragma("import-rule", RBGrammarReader::importRule);
+
+ reader.addPragma("remove-rule", RBGrammarReader::removeRule);
+
+ reader.addPragma("prefix-with", RBGrammarReader::prefixRule);
+ reader.addPragma("suffix-with", RBGrammarReader::suffixRule);
+
+ reader.addPragma("regex-rule", (tokenizer, state) -> {
+ String ruleName = tokenizer.nextToken();
+
+ IList<String> regx = tokenizer.toList();
+ Generex regex = new Generex(ListUtils.collapseTokens(regx));
+
+ state.addSpecialRule(ruleName, () -> {
+ return new FunctionalList<>(regex.random().split(" "));
+ });
+ });
+
+ reader.addPragma("range-rule", (tokenizer, state) -> {
+ String ruleName = tokenizer.nextToken();
+
+ int start = Integer.parseInt(tokenizer.nextToken());
+ int end = Integer.parseInt(tokenizer.nextToken());
+
+ state.addSpecialRule(ruleName, () -> {
+ return new FunctionalList<>(Integer.toString(
+ numgen.nextInt((end - start) + 1) + start));
+ });
+ });
+ }
+
+ private static void loadSubGrammar(FunctionalStringTokenizer stk, ReaderState rs) {
+ String subgrammarName = stk.nextToken();
+ String subgrammarPath = stk.nextToken();
+
+ rs.loadSubgrammar(subgrammarName, subgrammarPath);
+ }
+
+ private static void prefixRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+ String prefixToken = tokenizer.nextToken();
+
+ int additionalProbability = readOptionalProbability(tokenizer, state);
+
+ state.prefixRule(ruleName, prefixToken, additionalProbability);
+ }
+
+ private static void promoteGrammar(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String subgrammarName = tokenizer.nextToken();
+ String subordinateName = tokenizer.nextToken();
+
+ state.promoteGrammar(subgrammarName, subordinateName);
+ }
+
+ private static int readOptionalProbability(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ if (state.isUniform()) {
+ return 1;
+ }
+
+ return Integer.parseInt(tokenizer.nextToken());
+ }
+
+ private static void removeRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+
+ state.deleteRule(ruleName);
+ }
+
+ private static void removeSubGrammar(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String subgrammarName = tokenizer.nextToken();
+
+ state.deleteSubgrammar(subgrammarName);
+ }
+
+ private static void saveGrammar(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String subgrammarName = tokenizer.nextToken();
+
+ state.saveSubgrammar(subgrammarName);
+ }
+
+ private static void setupReader() {
+ reader = new RuleBasedConfigReader<>(null, null, null);
+
+ reader.setStartRule((tokenizer, stateTokenPair) -> {
+ stateTokenPair.doWith((initToken, state) -> {
+ state.startNewRule(initToken);
+
+ doCase(tokenizer, state);
+ });
+ });
+
+ reader.setContinueRule((tokenizer, state) -> {
+ doCase(tokenizer, state);
+ });
+
+ reader.setEndRule((tokenizer) -> {
+ tokenizer.setCurrentRule(null);
+ });
+ }
+
+ private static void subordinateGrammar(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String grammarName = tokenizer.nextToken();
+
+ state.subordinateGrammar(grammarName);
+ }
+
+ private static void suffixRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+ String suffixToken = tokenizer.nextToken();
+
+ int additionalProbability = readOptionalProbability(tokenizer, state);
+
+ state.suffixRule(ruleName, suffixToken, additionalProbability);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/ReaderState.java b/RGens/src/main/java/bjc/rgens/parser/ReaderState.java
new file mode 100644
index 0000000..89fde25
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/ReaderState.java
@@ -0,0 +1,306 @@
+package bjc.rgens.parser;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Stack;
+import java.util.function.Supplier;
+
+import bjc.utils.funcdata.IList;
+import bjc.utils.gen.WeightedGrammar;
+
+/**
+ * Represents the internal state of reader
+ *
+ * @author ben
+ *
+ */
+public class ReaderState {
+ private WeightedGrammar<String> currentGrammar;
+
+ private Stack<WeightedGrammar<String>> grammarStack;
+
+ private String currentRule;
+
+ private boolean isUniform;
+
+ private Path currentDirectory;
+
+ /**
+ * Create a new reader state
+ *
+ * @param inputPath
+ * The path to this grammar
+ */
+ public ReaderState(Path inputPath) {
+ grammarStack = new Stack<>();
+
+ currentGrammar = new WeightedGrammar<>();
+
+ // Grammars start out uniform
+ isUniform = true;
+
+ currentDirectory = inputPath.getParent();
+ }
+
+ /**
+ * Get the rule names for the current grammar
+ *
+ * @return The rule names for the current grammar
+ */
+ public IList<String> getRuleNames() {
+ return currentGrammar.getRuleNames();
+ }
+
+ /**
+ * Check if this reader is currently in uniform mode
+ *
+ * @return Whether this grammar is in uniform mode
+ */
+ public boolean isUniform() {
+ return isUniform;
+ }
+
+ /**
+ * Set the current grammar to be the specified one
+ *
+ * @param newWorkingGrammar
+ * The new grammar to use
+ */
+ public void setCurrentGrammar(WeightedGrammar<String> newWorkingGrammar) {
+ currentGrammar = newWorkingGrammar;
+ }
+
+ /**
+ * Set the rule currently being worked on
+ *
+ * @param ruleName
+ * The rule currently being worked on
+ */
+ public void setCurrentRule(String ruleName) {
+ currentRule = ruleName;
+ }
+
+ /**
+ * Set the initial rule of this grammar
+ *
+ * @param ruleName
+ * The initial rule of this grammar
+ */
+ public void setInitialRule(String ruleName) {
+ currentGrammar.setInitialRule(ruleName);
+ }
+
+ /**
+ * Toggle this uniformity setting for this grammar
+ */
+ public void toggleUniformity() {
+ isUniform = !isUniform;
+ }
+
+ /**
+ * Start work on a new sub-grammar of the previous grammar
+ */
+ public void startNewSubgrammar() {
+ grammarStack.push(currentGrammar);
+
+ currentGrammar = new WeightedGrammar<>();
+ }
+
+ /**
+ * Move to editing the grammar that is the parent of this current one
+ */
+ public void editParent() {
+ currentGrammar = grammarStack.pop();
+ }
+
+ /**
+ * Add a case to the current grammar
+ *
+ * @param ruleProbability
+ * The probability for this case to occur
+ * @param ruleParts
+ * The parts that make up this case
+ */
+ public void addCase(int ruleProbability, IList<String> ruleParts) {
+ currentGrammar.addCase(currentRule, ruleProbability, ruleParts);
+ }
+
+ public void addSpecialRule(String ruleName, Supplier<IList<String>> cse) {
+ currentGrammar.addSpecialRule(ruleName, cse);
+ }
+ /**
+ * Edit a subgrammar of the current grammar
+ *
+ * @param subgrammarName
+ * The name of the subgrammar to edit
+ */
+ public void editSubgrammar(String subgrammarName) {
+ WeightedGrammar<String> subgrammar = currentGrammar.getSubgrammar(subgrammarName);
+
+ grammarStack.push(currentGrammar);
+
+ currentGrammar = subgrammar;
+ }
+
+ /**
+ * Start editing a new rule in the current grammar
+ *
+ * @param ruleName
+ * The name of the new rule to edit
+ */
+ public void startNewRule(String ruleName) {
+ currentGrammar.addRule(ruleName);
+
+ currentRule = ruleName;
+ }
+
+ /**
+ * Convert this package of state into a weighted grammar
+ *
+ * @return The grammar represented by this state
+ */
+ public WeightedGrammar<String> getGrammar() {
+ return currentGrammar;
+ }
+
+ /**
+ * Alias a current subgrammar to a new name
+ *
+ * @param subgrammarName
+ * The name of the subgrammar to alias
+ * @param subgrammarAlias
+ * The name of the alias for the subgrammar
+ */
+ public void addGrammarAlias(String subgrammarName, String subgrammarAlias) {
+ currentGrammar.addGrammarAlias(subgrammarName, subgrammarAlias);
+ }
+
+ /**
+ * Load a subgrammar into this one.
+ *
+ * @param subgrammarName
+ * The name to assign to the subgrammar
+ * @param subgrammarPath
+ * The path to load the subgrammar from
+ */
+ public void loadSubgrammar(String subgrammarName,
+ String subgrammarPath) {
+ Path loadPath = currentDirectory.resolve(subgrammarPath);
+
+ try {
+ WeightedGrammar<String> subgrammar = RBGrammarReader
+ .fromPath(loadPath);
+
+ currentGrammar.addSubgrammar(subgrammarName, subgrammar);
+ } catch (IOException ioex) {
+ PragmaErrorException peex = new PragmaErrorException(
+ "Couldn't load subgrammar " + subgrammarName + " from "
+ + subgrammarPath);
+
+ peex.initCause(ioex);
+
+ throw peex;
+ }
+ }
+
+ /**
+ * Prefix a token onto all of the cases for the specified rule
+ *
+ * @param ruleName
+ * The rule to do prefixing on
+ * @param prefixToken
+ * The token to prefix onto each case
+ * @param additionalProbability
+ * The probability modification of the prefixed cases
+ */
+ public void prefixRule(String ruleName, String prefixToken,
+ int additionalProbability) {
+ currentGrammar.prefixRule(ruleName, prefixToken,
+ additionalProbability);
+ }
+
+ /**
+ * Promote the specified subgrammar above the current grammar
+ *
+ * @param subgrammarName
+ * The name of the subgrammar to promote
+ * @param subordinateName
+ * The name to bind this grammar to the subgrammar under
+ */
+ public void promoteGrammar(String subgrammarName,
+ String subordinateName) {
+ WeightedGrammar<String> subgrammar = currentGrammar
+ .getSubgrammar(subgrammarName);
+
+ currentGrammar.deleteSubgrammar(subgrammarName);
+
+ subgrammar.addSubgrammar(subordinateName, currentGrammar);
+
+ currentGrammar = subgrammar;
+ }
+
+ /**
+ * Delete a rule from the current subgrammar
+ *
+ * @param ruleName
+ * The name of the rule to delete
+ */
+ public void deleteRule(String ruleName) {
+ currentGrammar.deleteRule(ruleName);
+ }
+
+ /**
+ * Delete a subgrammar from the current grammar
+ *
+ * @param subgrammarName
+ * The name of the subgrammar to delete
+ */
+ public void deleteSubgrammar(String subgrammarName) {
+ currentGrammar.deleteSubgrammar(subgrammarName);
+ }
+
+ /**
+ * Save the current grammar as a subgrammar of the previous one
+ *
+ * @param subgrammarName
+ * The name of the subgrammar to save this under
+ */
+ public void saveSubgrammar(String subgrammarName) {
+ WeightedGrammar<String> newWorkingGrammar = grammarStack.pop();
+
+ newWorkingGrammar.addSubgrammar(subgrammarName, currentGrammar);
+
+ currentGrammar = newWorkingGrammar;
+ }
+
+ /**
+ * Subordinate this grammar as a subgrammar to a new grammar
+ *
+ * @param grammarName
+ * The name for the subgrammar to bind the current grammar
+ * to
+ */
+ public void subordinateGrammar(String grammarName) {
+ WeightedGrammar<String> newWorkingGrammar = new WeightedGrammar<>();
+
+ newWorkingGrammar.addSubgrammar(grammarName, currentGrammar);
+
+ currentGrammar = newWorkingGrammar;
+ }
+
+ /**
+ * Suffix a token onto all of the cases for the specified rule
+ *
+ * @param ruleName
+ * The rule to do suffixing on
+ * @param suffixToken
+ * The token to suffix onto each case
+ * @param additionalProbability
+ * The probability modification of the suffixed cases
+ */
+ public void suffixRule(String ruleName, String suffixToken,
+ int additionalProbability) {
+ currentGrammar.suffixRule(ruleName, suffixToken,
+ additionalProbability);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/server/CLIArgsParser.java b/RGens/src/main/java/bjc/rgens/server/CLIArgsParser.java
new file mode 100644
index 0000000..fa0d399
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/server/CLIArgsParser.java
@@ -0,0 +1,141 @@
+package bjc.rgens.server;
+
+import java.io.File;
+
+public class CLIArgsParser {
+ public static void parseArgs(String[] args, GrammarServerEngine eng) {
+ boolean didTerminalOp = false;
+ boolean forceInteractive = false;
+
+ // @TODO report error status
+ boolean didError = false;
+
+ if(args.length < 0) return;
+
+ if(args.length == 1 && args[0].equals("--help")) {
+ // @TODO show help
+ } else {
+ for(int i = 0; i < args.length; i++) {
+ String arg = args[i];
+
+ switch(arg) {
+ case "-lc":
+ case "--load-config-file":
+ String configFileName = args[++i];
+
+ eng.doLoadConfig(configFileName);
+ break;
+ case "-lg":
+ case "--load-grammar-file":
+ String grammarFileName = args[++i];
+
+ File grammarFile = new File(grammarFileName);
+
+ String ruleName = grammarFile.getName();
+ ruleName = ruleName.substring(0, ruleName.lastIndexOf('.'));
+
+ if(!args[i+1].startsWith("-")) {
+ ruleName = args[++i];
+ }
+
+ eng.doLoadGrammar(ruleName, grammarFileName);
+
+ break;
+ case "-ll":
+ case "--load-long-file":
+ String longRuleFileName = args[++i];
+
+ File longRuleFile = new File(longRuleFileName);
+
+ String longRuleName = longRuleFile.getName();
+ longRuleName = longRuleName.substring(0, longRuleName.lastIndexOf('.'));
+
+ if(!args[i+1].startsWith("-")) {
+ longRuleName = args[++i];
+ }
+
+ eng.doLoadLongRule(longRuleName, longRuleFileName);
+
+ break;
+ case "-ge":
+ case "--generate-exported-rule":
+ String exportedRuleName = args[++i];
+
+ if(eng.hasExportedRule(exportedRuleName)) {
+ eng.doGenerateExportedRule(exportedRuleName);
+ didTerminalOp = true;
+ } else {
+ System.out.printf("Error: No exported rule named %s\n", exportedRuleName);
+ }
+ break;
+ case "-gg":
+ case "--generate-grammar-rule":
+ String grammarName = args[++i];
+
+ if(!eng.hasLoadedGrammar(grammarName)) {
+ System.out.printf("Error: No grammar named %s\n", grammarName);
+ } else {
+ String ruleToGenerate = "";
+
+ if(!args[i+1].startsWith("-")) {
+ ruleToGenerate = args[++i];
+ } else if(eng.hasInitialRule(grammarName)) {
+ ruleToGenerate = eng.getInitialRule(grammarName);
+ } else {
+ System.out.printf("Error: Grammar %s has no initial rule. A "
+ + "rule must be provided.",grammarName);
+ }
+
+ eng.doGenerateGrammar(grammarName, ruleToGenerate);
+ didTerminalOp = true;
+ }
+ break;
+ case "-st":
+ case "--stress-test":
+ String thingToTest = args[++i];
+
+ // @TODO support testing rules from grammars
+ // as well as a specified number of times
+ if(thingToTest.equals("*")) {
+ eng.doStressTest(10000);
+ } else {
+ eng.doStressTest(thingToTest, 1000);
+ }
+
+ didTerminalOp = true;
+
+ break;
+ case "-d":
+ case "--debug":
+ if(eng.debugMode) {
+ System.out.println("Warning: debug mode is already on. Use -nd or --no-debug"
+ + " to turn it off");
+ } else {
+ eng.debugMode = true;
+ }
+ break;
+ case "-nd":
+ case "--no-debug":
+ if(!eng.debugMode) {
+ System.out.println("Warning: debug mode is already off. Use -d or --debug"
+ + " to turn it on");
+ } else {
+ eng.debugMode = false;
+ }
+ break;
+ case "-i":
+ case "--interactive":
+ forceInteractive = true;
+ break;
+ default:
+ System.out.println("Error: Unrecognized argument " + arg);
+ break;
+ }
+ }
+ }
+
+ if(!forceInteractive && didTerminalOp) {
+ System.exit(didError ? 1 : 0);
+ }
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/server/GrammarServer.java b/RGens/src/main/java/bjc/rgens/server/GrammarServer.java
new file mode 100644
index 0000000..1a47de2
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/server/GrammarServer.java
@@ -0,0 +1,346 @@
+package bjc.rgens.server;
+
+import bjc.utils.funcdata.FunctionalMap;
+import bjc.utils.funcdata.IMap;
+import bjc.utils.gen.WeightedGrammar;
+
+import java.io.File;
+
+import java.util.Scanner;
+
+public class GrammarServer {
+ private Scanner scn;
+
+ private IMap<String, WeightedGrammar<String>> loadedGrammars;
+ private IMap<String, WeightedGrammar<String>> exportedRules;
+
+ private GrammarServerEngine eng;
+
+ public GrammarServer(Scanner scn) {
+ this.scn = scn;
+
+ this.loadedGrammars = new FunctionalMap<>();
+ this.exportedRules = new FunctionalMap<>();
+
+ eng = new GrammarServerEngine(loadedGrammars, exportedRules);
+
+ ServerGrammarReader.setExportedRules(exportedRules);
+ }
+
+ public static void main(String[] args) {
+ System.out.println("GrammarServer 1.0");
+
+ Scanner scn = new Scanner(System.in);
+
+ GrammarServer serv = new GrammarServer(scn);
+
+ CLIArgsParser.parseArgs(args, serv.eng);
+
+ System.out.print("Enter a command (m for help): ");
+
+ char comm = scn.nextLine().charAt(0);
+
+ while(comm != 'e') {
+ switch(comm) {
+ case 'm':
+ System.out.println("GrammarServer Commands:");
+ System.out.println("\tm: Print command help");
+ System.out.println("\te: Exit GrammarServer");
+ System.out.println("\tl: Load from file");
+ System.out.println("\ts: Show information");
+ System.out.println("\tg: Generate text");
+ break;
+ case 'g':
+ serv.generateMode();
+ break;
+ case 's':
+ serv.showMode();
+ break;
+ case 'l':
+ serv.loadMode();
+ break;
+ default:
+ System.out.println("? Unrecognized Command");
+ }
+
+ System.out.print("Enter a command (m for help): ");
+
+ comm = scn.nextLine().charAt(0);
+ }
+
+ System.out.println("GrammarServer exiting");
+ }
+
+
+
+ private void loadMode() {
+ System.out.println("Entering Load Mode");
+
+ System.out.print("(Load Mode) Enter a command (m for help): ");
+ char comm = scn.nextLine().charAt(0);
+
+ while(comm != 'e') {
+ switch(comm) {
+ case 'm':
+ System.out.println("GrammarServer Load Mode Commands");
+ System.out.println("\tm: Show command help");
+ System.out.println("\te: Exit Load Mode");
+ System.out.println("\tg: Load grammar from a file");
+ System.out.println("\tl: Load long rule from a file");
+ System.out.println("\tc: Load configuration from a file");
+ break;
+ case 'g':
+ loadGrammar();
+ break;
+ case 'c':
+ loadConfig();
+ break;
+ case 'l':
+ loadLongRule();
+ break;
+ default:
+ System.out.println("? Unrecognized Command");
+ }
+
+ System.out.print("(Load Mode) Enter a command (m for help): ");
+ comm = scn.nextLine().charAt(0);
+ }
+
+ System.out.println("Exiting Load Mode");
+ }
+
+ private void loadGrammar() {
+ System.out.print("Enter path to load grammar from: ");
+
+ String grammarPath = scn.nextLine().trim();
+
+ File grammarFile = new File(grammarPath);
+
+ String grammarName = grammarFile.getName().trim();
+
+ grammarName = grammarName.substring(0, grammarName.lastIndexOf("."));
+
+ System.out.printf("Enter grammar name or press enter for"
+ + " the default (%s): ", grammarName);
+
+ String inputName = scn.nextLine();
+
+ if(!inputName.equals("")) {
+ grammarName = inputName;
+ }
+
+ eng.doLoadGrammar(grammarName, grammarPath);
+
+ return;
+ }
+
+ private void loadLongRule() {
+ System.out.print("Enter the file to load a long rule from: ");
+
+ String fileName = scn.nextLine().trim();
+ File ruleFile = new File(fileName);
+
+ String tempName = ruleFile.getName();
+ tempName = tempName.substring(0, tempName.lastIndexOf('.'));
+
+ System.out.printf("Enter the name for the long rule (default %s): ", tempName);
+
+ String ruleName = scn.nextLine().trim();
+
+ if(ruleName.equals("")) {
+ ruleName = tempName;
+ }
+
+ eng.doLoadLongRule(ruleName, fileName);
+ }
+
+ private void loadConfig() {
+ System.out.print("Enter the file to load configuration from: ");
+
+ String fileName = scn.nextLine().trim();
+
+ eng.doLoadConfig(fileName);
+ }
+
+ private void showMode() {
+ System.out.println("Entering Show Mode");
+
+ System.out.print("(Show Mode) Enter a command (m for help): ");
+
+ char comm = scn.nextLine().charAt(0);
+
+ while(comm != 'e') {
+ switch(comm) {
+ case 'm':
+ System.out.println("GrammarServer Show Mode Commands: ");
+ System.out.println("\tm: Show command help");
+ System.out.println("\tl: Show loaded grammars");
+ System.out.println("\tr: Show rules from a grammar");
+ System.out.println("\tx: Show exported rules");
+ System.out.println("\te: Exit Show Mode");
+ break;
+ case 'r':
+ showGrammarRules();
+ break;
+ case 'x':
+ eng.doShowExportedRules();
+ break;
+ case 'l':
+ eng.doShowLoadedGrammars();
+ break;
+ default:
+ System.out.println("? Unrecognized command");
+ break;
+ }
+
+ System.out.print("(Show Mode) Enter a command (m for help): ");
+
+ comm = scn.nextLine().charAt(0);
+ }
+
+
+
+ System.out.println("Exiting Show Mode");
+ }
+
+ private void generateMode() {
+ System.out.println("Entering Generate Mode");
+
+ System.out.print("(Generate Mode) Enter a command (m for help): ");
+
+ char comm = scn.nextLine().charAt(0);
+
+ while(comm != 'e') {
+ switch(comm) {
+ case 'm':
+ System.out.println("GrammarServer Generate Mode Commands: ");
+ System.out.println("\tm: Show command help");
+ System.out.println("\tx: Generate from exported rules");
+ System.out.println("\tr: Generate from a grammar");
+ System.out.println("\te: Exit Generate Mode");
+ break;
+ case 'x':
+ generateExportedRule();
+ break;
+ case 'r':
+ generateGrammar();
+ break;
+ default:
+ System.out.println("? Unrecognized command");
+ }
+
+ System.out.print("(Generate Mode) Enter a command (m for help): ");
+
+ comm = scn.nextLine().charAt(0);
+ }
+
+ System.out.println("Exiting Generate Mode");
+ }
+
+ private void generateExportedRule() {
+ System.out.print("Enter the name of the rule to generate"
+ + " (l to list, enter to cancel): ");
+
+ String ruleName = scn.nextLine().trim();
+
+ while(true) {
+ if(ruleName.equals("")) break;
+
+ if(ruleName.equals("l")) {
+ eng.doShowExportedRules();
+ } else if (exportedRules.containsKey(ruleName)) {
+ eng.doGenerateExportedRule(ruleName);
+
+ System.out.print("Generate again from this rule? (yes/no) (yes by default): ");
+
+ String resp = scn.nextLine().trim();
+
+ if(resp.equalsIgnoreCase("yes") || resp.equals("")) {
+ continue;
+ }
+ } else {
+ System.out.println("? Unrecognized external rule");
+ }
+
+ System.out.print("Enter the name of the rule to generate"
+ + " (l to list, enter to cancel): ");
+
+ ruleName = scn.nextLine().trim();
+ }
+ }
+
+ private void generateGrammar() {
+ System.out.print("Enter the name of the grammar to generate from (l to list, enter to cancel): ");
+
+ String grammarName = scn.nextLine().trim();
+
+ while(true) {
+ if(grammarName.equals("")) break;
+
+ if(grammarName.equals("l")) {
+ eng.doShowLoadedGrammars();
+ } else if(loadedGrammars.containsKey(grammarName)) {
+ WeightedGrammar<String> currentGram = loadedGrammars.get(grammarName);
+
+ System.out.print("Enter the name of the rule to generate"
+ + " (l to list, enter to cancel): ");
+
+ String ruleName = scn.nextLine().trim();
+
+ while(true) {
+ if(ruleName.equals("")) break;
+
+ if(ruleName.equals("l")) {
+ eng.doShowGrammarRules(grammarName);
+ } else if (currentGram.hasRule(ruleName)) {
+ eng.doGenerateGrammar(currentGram, ruleName);
+
+ System.out.print("Generate again from this rule? (yes/no) (yes by default): ");
+
+ String resp = scn.nextLine().trim();
+
+ if(resp.equalsIgnoreCase("yes") || resp.equals("")) {
+ continue;
+ }
+ } else {
+ System.out.println("? Unrecognized grammar rule");
+ }
+
+ System.out.print("Enter the name of the rule to generate"
+ + " (l to list, enter to cancel): ");
+
+ ruleName = scn.nextLine().trim();
+ }
+
+ } else {
+ System.out.println("? Unrecognized grammar name");
+ }
+
+ System.out.print("Enter the name of the grammar to generate from "
+ + "(l to list, enter to cancel): ");
+
+ grammarName = scn.nextLine().trim();
+ }
+ }
+
+ private void showGrammarRules() {
+ System.out.print("Enter the name of the grammar (l to list): ");
+ String gramName = scn.nextLine().trim();
+
+ do {
+ if(gramName.equals("")) break;
+
+ if(gramName.equals("l")) {
+ eng.doShowLoadedGrammars();
+ } else if (loadedGrammars.containsKey(gramName)) {
+ eng.doShowGrammarRules(gramName);
+ break;
+ } else {
+ System.out.println("? Unrecognized grammar name");
+ }
+
+ System.out.print("Enter the name of the grammar (l to list): ");
+ gramName = scn.nextLine().trim();
+ } while(true);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/server/GrammarServerEngine.java b/RGens/src/main/java/bjc/rgens/server/GrammarServerEngine.java
new file mode 100644
index 0000000..2f608ec
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/server/GrammarServerEngine.java
@@ -0,0 +1,300 @@
+package bjc.rgens.server;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Scanner;
+
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.IList;
+import bjc.utils.funcdata.IMap;
+import bjc.utils.funcutils.ListUtils;
+import bjc.utils.gen.WeightedGrammar;
+
+public class GrammarServerEngine {
+ private IMap<String, WeightedGrammar<String>> loadedGrammars;
+ private IMap<String, WeightedGrammar<String>> exportedRules;
+
+ public static boolean debugMode = false;
+
+ public GrammarServerEngine(IMap<String, WeightedGrammar<String>> loadedGrammars,
+ IMap<String, WeightedGrammar<String>> exportedRules) {
+ this.loadedGrammars = loadedGrammars;
+ this.exportedRules = exportedRules;
+ }
+
+ public String getInitialRule(String grammarName) {
+ return loadedGrammars.get(grammarName).getInitialRule();
+ }
+
+ public boolean hasInitialRule(String grammarName) {
+ return loadedGrammars.get(grammarName).hasInitialRule();
+ }
+
+ public boolean hasExportedRule(String ruleName) {
+ return exportedRules.containsKey(ruleName);
+ }
+
+ public boolean hasLoadedGrammar(String grammarName) {
+ return loadedGrammars.containsKey(grammarName);
+ }
+
+ public void doLoadConfig(String fileName) {
+ File inputFile = new File(fileName);
+
+ try(FileInputStream inputStream = new FileInputStream(inputFile)) {
+ try(Scanner fle = new Scanner(inputStream)) {
+ while(fle.hasNextLine()) {
+ String line = fle.nextLine().trim();
+
+ // Handle comments
+ if(line.equals("") ||
+ line.startsWith("#") ||
+ line.startsWith("//")) {
+ continue;
+ }
+
+ // Handle mixed whitespace in input
+ line = line.replaceAll("\\s+", " ");
+
+ String path;
+ String name;
+
+ if(line.lastIndexOf(' ') != -1) {
+ path = line.substring(0, line.lastIndexOf(' '));
+ name = line.substring(line.lastIndexOf(' ') + 1, line.length());
+ } else {
+ path = line;
+
+ File pathFile = new File(path);
+ String pathName = pathFile.getName();
+
+ if(pathFile.isDirectory()) {
+ // Load all the files in the directory recursively
+ Queue<File> entries = new LinkedList<>();
+
+ for (File entry : pathFile.listFiles()) {
+ entries.add(entry);
+ }
+
+ while(!entries.isEmpty()) {
+ File entry = entries.poll();
+
+ String entryPath = entry.getName();
+
+ if(entry.isHidden()) continue;
+ if(entry.isDirectory()) {
+ for (File newEntry : entry.listFiles()) {
+ entries.add(newEntry);
+ }
+
+ continue;
+ }
+
+ name = entryPath.substring(0, entryPath.lastIndexOf('.'));
+
+ doLoadGrammarEntry(entry.toString(), name);
+ }
+
+ continue;
+ }
+
+ name = pathName.substring(0, pathName.lastIndexOf('.'));
+ }
+
+ doLoadGrammarEntry(path, name);
+ }
+ }
+ } catch(IOException ioex) {
+ System.out.printf("? Error reading configuration from file"
+ + " (reason: %s)\n", ioex.getMessage());
+ }
+ }
+
+ private void doLoadGrammarEntry(String path, String name) {
+ if(path.endsWith(".gram")) {
+ doLoadGrammar(name, path);
+ } else if(path.endsWith(".template")) {
+ System.out.println("Error: Templates are not supported yet");
+ } else if(path.endsWith(".long")) {
+ doLoadLongRule(name, path);
+ } else {
+ System.out.println("Error: Unknown filetype " +
+ path.substring(path.lastIndexOf("."), path.length()));
+ }
+ }
+
+ public void doLoadLongRule(String ruleName, String ruleFile) {
+ ruleName = "[" + ruleName + "]";
+
+ if(debugMode) {
+ System.out.printf("Loading long rule (named %s) from path %s\n",
+ ruleName, ruleFile);
+ }
+
+ try (FileInputStream inputStream = new FileInputStream(ruleFile)) {
+ try (Scanner fle = new Scanner(inputStream)) {
+ IList<IList<String>> ruleParts = new FunctionalList<>();
+
+ while(fle.hasNextLine()) {
+ ruleParts.add(new FunctionalList<>(fle.nextLine().trim().split(" ")));
+ }
+
+ WeightedGrammar<String> longGram = new WeightedGrammar<>();
+
+ longGram.addSpecialRule(ruleName, () -> ruleParts.randItem());
+ longGram.setInitialRule(ruleName);
+
+ exportedRules.put(ruleName, longGram);
+
+ if(debugMode) {
+ System.out.printf("Loaded long rule (named %s) from path %s\n",
+ ruleName, ruleFile);
+ }
+ }
+ } catch (IOException ioex) {
+ System.out.printf("Error reading long rule (%s)\n", ioex.getMessage());
+ }
+ }
+
+ public void doLoadGrammar(String grammarName, String grammarPath) {
+ if(debugMode) {
+ System.out.printf("Loading grammar (named %s) from path %s\n",
+ grammarName, grammarPath);
+ }
+
+ try (FileInputStream inputStream = new FileInputStream(grammarPath)) {
+ WeightedGrammar<String> newGram =
+ ServerGrammarReader.fromStream(inputStream).merge((gram, exports) -> {
+ for(String export : exports.toIterable()) {
+ if(debugMode) {
+ System.out.printf("\tLoaded exported rule %s from grammar %s\n",
+ export, grammarName);
+
+ if(exportedRules.containsKey(export)) {
+ System.out.printf("\tWarning: Exported rule %s from grammar %s" +
+ " shadows a pre-existing rule\n", export, grammarName);
+ }
+ }
+
+ exportedRules.put(export, gram);
+ }
+
+ return gram;
+ });
+
+ loadedGrammars.put(grammarName, newGram);
+ } catch (IOException ioex) {
+ System.out.printf("? Error reading grammar from file"
+ + " (reason: %s)\n", ioex.getMessage());
+ }
+
+ if(debugMode) {
+ System.out.printf("Loaded grammar (named %s) from path %s\n",
+ grammarName, grammarPath);
+ }
+ }
+
+ public void doGenerateExportedRule(String ruleName) {
+ String ruleResult = ListUtils.collapseTokens(
+ exportedRules.get(ruleName)
+ .generateListValues(ruleName, " "));
+
+ System.out.println("Generated Result: ");
+ System.out.println("\t" + ruleResult.replaceAll("\\s+", " "));
+ }
+
+ public void doGenerateGrammar(String currentGram, String ruleName) {
+ doGenerateGrammar(loadedGrammars.get(currentGram), ruleName);
+ }
+
+ public void doGenerateGrammar(WeightedGrammar<String> currentGram, String ruleName) {
+ String ruleResult = ListUtils.collapseTokens(
+ currentGram.generateListValues(ruleName, " "));
+
+ System.out.println("Generated Result: ");
+ System.out.println("\t" + ruleResult.replaceAll("\\s+", " "));
+ }
+
+ public void doShowExportedRules() {
+ System.out.printf("Currently exported rules (%d total):\n",
+ exportedRules.getSize());
+
+ exportedRules.forEachKey(key -> {
+ System.out.println("\t" + key);
+ });
+ }
+
+ public void doShowGrammarRules(String gramName) {
+ WeightedGrammar<String> gram = loadedGrammars.get(gramName);
+
+ IList<String> ruleNames = gram.getRuleNames();
+
+ System.out.printf("Rules for grammar %s (%d total)\n",
+ gramName, ruleNames.getSize());
+
+ ruleNames.forEach(rule -> {
+ System.out.println("\t" + rule);
+ });
+ }
+
+ public void doShowLoadedGrammars() {
+ System.out.printf("Currently loaded grammars (%d total):\n",
+ loadedGrammars.getSize());
+
+ loadedGrammars.forEachKey(key -> {
+ System.out.println("\t" + key);
+ });
+ }
+
+ public void doStressTest(int count) {
+ exportedRules.forEachKey(key -> {
+ doStressTest(key, count);
+ });
+ }
+
+ public void doStressTest(String ruleName, int count) {
+ doStressTest(exportedRules.get(ruleName), ruleName, count);
+ }
+
+ public void doStressTest(WeightedGrammar<String> gram, String ruleName, int count) {
+ if(debugMode) System.out.println("Stress-testing rule " + ruleName);
+
+ IList<String> res = new FunctionalList<>();
+ IList<String> foundTags = new FunctionalList<>();
+
+ boolean foundBroken = false;
+
+ for(int i = 0; i < count; i++) {
+ res = gram.generateListValues(ruleName, " ");
+
+ for(String tok : res.toIterable()) {
+ if(tok.matches("\\[\\S+\\]") && !foundTags.contains(tok)) {
+ System.out.println("\tWarning: Possible un-expanded rule " + tok + " found"
+ + " in expansion of " + ruleName);
+
+ doFindRule(tok);
+
+ foundBroken = true;
+
+ foundTags.add(tok);
+ }
+ }
+ }
+
+ if(debugMode) {
+ if(!foundBroken) System.out.printf("Rule %s succesfully passed stress-testing\n", ruleName);
+ else System.out.printf("Rule %s failed stress-testing\n", ruleName);
+ }
+ }
+
+ private void doFindRule(String ruleName) {
+ loadedGrammars.forEach((gramName, gram) -> {
+ if(gram.hasRule(ruleName)) {
+ System.out.printf("\t\tFound rule %s in grammar %s\n", ruleName, gramName);
+ }
+ });
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/server/ReaderState.java b/RGens/src/main/java/bjc/rgens/server/ReaderState.java
new file mode 100644
index 0000000..3f5021e
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/server/ReaderState.java
@@ -0,0 +1,181 @@
+package bjc.rgens.server;
+
+import java.util.function.Supplier;
+
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.IList;
+import bjc.utils.gen.WeightedGrammar;
+
+/**
+ * Represents the internal state of reader
+ *
+ * @author ben
+ *
+ */
+public class ReaderState {
+ private WeightedGrammar<String> currentGrammar;
+ private String currentRule;
+ private boolean isUniform;
+
+ private IList<String> exports;
+
+ /**
+ * Create a new reader state
+ */
+ public ReaderState() {
+ currentGrammar = new WeightedGrammar<>();
+
+ // Grammars start out uniform
+ isUniform = true;
+
+ exports = new FunctionalList<>();
+ }
+
+ public void addExport(String export) {
+ exports.add(export);
+ }
+
+ public IList<String> getExports() {
+ return exports;
+ }
+
+ /**
+ * Get the rule names for the current grammar
+ *
+ * @return The rule names for the current grammar
+ */
+ public IList<String> getRuleNames() {
+ return currentGrammar.getRuleNames();
+ }
+
+ /**
+ * Check if this reader is currently in uniform mode
+ *
+ * @return Whether this grammar is in uniform mode
+ */
+ public boolean isUniform() {
+ return isUniform;
+ }
+
+ /**
+ * Set the current grammar to be the specified one
+ *
+ * @param newWorkingGrammar
+ * The new grammar to use
+ */
+ public void setCurrentGrammar(WeightedGrammar<String> newWorkingGrammar) {
+ currentGrammar = newWorkingGrammar;
+ }
+
+ /**
+ * Set the rule currently being worked on
+ *
+ * @param ruleName
+ * The rule currently being worked on
+ */
+ public void setCurrentRule(String ruleName) {
+ currentRule = ruleName;
+ }
+
+ /**
+ * Set the initial rule of this grammar
+ *
+ * @param ruleName
+ * The initial rule of this grammar
+ */
+ public void setInitialRule(String ruleName) {
+ currentGrammar.setInitialRule(ruleName);
+ }
+
+ /**
+ * Toggle this uniformity setting for this grammar
+ */
+ public void toggleUniformity() {
+ isUniform = !isUniform;
+ }
+
+ /**
+ * Add a case to the current grammar
+ *
+ * @param ruleProbability
+ * The probability for this case to occur
+ * @param ruleParts
+ * The parts that make up this case
+ */
+ public void addCase(int ruleProbability, IList<String> ruleParts) {
+ currentGrammar.addCase(currentRule, ruleProbability, ruleParts);
+ }
+
+ /**
+ * Add a special rule to the grammar
+ *
+ * @param ruleName The name of the special rule
+ * @param cse The special case for the rule
+ */
+ public void addSpecialRule(String ruleName, Supplier<IList<String>> cse) {
+ currentGrammar.addSpecialRule(ruleName, cse);
+ }
+
+ /**
+ * Start editing a new rule in the current grammar
+ *
+ * @param ruleName
+ * The name of the new rule to edit
+ */
+ public void startNewRule(String ruleName) {
+ currentGrammar.addRule(ruleName);
+
+ currentRule = ruleName;
+ }
+
+ /**
+ * Convert this package of state into a weighted grammar
+ *
+ * @return The grammar represented by this state
+ */
+ public WeightedGrammar<String> getGrammar() {
+ return currentGrammar;
+ }
+
+ /**
+ * Prefix a token onto all of the cases for the specified rule
+ *
+ * @param ruleName
+ * The rule to do prefixing on
+ * @param prefixToken
+ * The token to prefix onto each case
+ * @param additionalProbability
+ * The probability modification of the prefixed cases
+ */
+ public void prefixRule(String ruleName, String prefixToken,
+ int additionalProbability) {
+ currentGrammar.prefixRule(ruleName, prefixToken,
+ additionalProbability);
+ }
+
+ /**
+ * Delete a rule from the current grammar
+ *
+ * @param ruleName
+ * The name of the rule to delete
+ */
+ public void deleteRule(String ruleName) {
+ currentGrammar.deleteRule(ruleName);
+ }
+
+ /**
+ * Suffix a token onto all of the cases for the specified rule
+ *
+ * @param ruleName
+ * The rule to do suffixing on
+ * @param suffixToken
+ * The token to suffix onto each case
+ * @param additionalProbability
+ * The probability modification of the suffixed cases
+ */
+ public void suffixRule(String ruleName, String suffixToken,
+ int additionalProbability) {
+ currentGrammar.suffixRule(ruleName, suffixToken,
+ additionalProbability);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/server/ServerGrammarReader.java b/RGens/src/main/java/bjc/rgens/server/ServerGrammarReader.java
new file mode 100644
index 0000000..77b1e8b
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/server/ServerGrammarReader.java
@@ -0,0 +1,326 @@
+package bjc.rgens.server;
+
+import com.mifmif.common.regex.Generex;
+
+import java.io.InputStream;
+import java.util.Random;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+
+import bjc.utils.data.IPair;
+import bjc.utils.data.Pair;
+import bjc.utils.funcdata.FunctionalStringTokenizer;
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.FunctionalMap;
+import bjc.utils.funcdata.IList;
+import bjc.utils.funcdata.IMap;
+import bjc.utils.funcutils.ListUtils;
+import bjc.utils.gen.WeightedGrammar;
+import bjc.utils.parserutils.RuleBasedConfigReader;
+
+/**
+ * Read a grammar from a stream
+ *
+ * @author ben
+ *
+ */
+public class ServerGrammarReader {
+ static {
+ setupReader();
+
+ initPragmas();
+ }
+
+ private static RuleBasedConfigReader<ReaderState> reader;
+
+ private static Random numgen = new Random();
+
+ private static IMap<String, WeightedGrammar<String>> exportedRules;
+
+ public static void setExportedRules(IMap<String, WeightedGrammar<String>> rules) {
+ exportedRules = rules;
+ }
+
+ /**
+ * Read a grammar from a stream
+ *
+ * @param inputStream
+ * The stream to load the grammar from
+ *
+ * @return A grammar read from the stream
+ *
+ */
+ public static IPair<WeightedGrammar<String>, IList<String>>
+ fromStream(InputStream inputStream) {
+ ReaderState initialState = new ReaderState();
+
+ WeightedGrammar<String> gram = reader.fromStream(inputStream, initialState).getGrammar();
+
+ IMap<String, IList<String>> vars = new FunctionalMap<>();
+
+ Predicate<String> specialPredicate = (strang) -> {
+ if(strang.matches("\\[\\S+\\]")) {
+ return true;
+ }
+
+ return false;
+ };
+
+ BiFunction<String, WeightedGrammar<String>, IList<String>>
+ specialAction = (strang, gramm) -> {
+ return handleSpecialRule(vars, strang, gramm);
+ };
+
+ gram.configureSpecial(specialPredicate, specialAction);
+
+ IList<String> exports = initialState.getExports();
+
+ if(gram.getInitialRule() != null && !exports.contains(gram.getInitialRule())) {
+ exports.add(gram.getInitialRule());
+ }
+
+ return new Pair<>(gram, exports);
+ }
+
+ private static void initPragmas() {
+ reader.addPragma("debug", (tokenizer, state) -> {
+ debugGrammar(state);
+ });
+
+ reader.addPragma("uniform", (tokenizer, state) -> {
+ state.toggleUniformity();
+ });
+
+ reader.addPragma("initial-rule", ServerGrammarReader::initialRule);
+
+ reader.addPragma("remove-rule", ServerGrammarReader::removeRule);
+
+ reader.addPragma("prefix-with", ServerGrammarReader::prefixRule);
+ reader.addPragma("suffix-with", ServerGrammarReader::suffixRule);
+
+ reader.addPragma("regex-rule", ServerGrammarReader::handleRegexRule);
+
+ reader.addPragma("range-rule", ServerGrammarReader::handleRangeRule);
+
+ reader.addPragma("export-rule", (tokenizer, state) -> {
+ String ruleName = tokenizer.nextToken();
+
+ state.addExport(ruleName);
+ });
+ }
+
+ private static void setupReader() {
+ reader = new RuleBasedConfigReader<>(null, null, null);
+
+ reader.setStartRule((tokenizer, stateTokenPair) -> {
+ stateTokenPair.doWith((initToken, state) -> {
+ state.startNewRule(initToken);
+
+ doCase(tokenizer, state);
+ });
+ });
+
+ reader.setContinueRule((tokenizer, state) -> {
+ doCase(tokenizer, state);
+ });
+
+ reader.setEndRule((tokenizer) -> {
+ tokenizer.setCurrentRule(null);
+ });
+ }
+
+ private static void debugGrammar(ReaderState state) {
+ System.out.println("Printing rule names: ");
+
+ for (String currentRule : state.getRuleNames().toIterable()) {
+ System.out.println("\t" + currentRule);
+ }
+
+ System.out.println();
+ }
+
+ private static IList<String> handleSpecialRule(IMap<String, IList<String>> vars, String strang,
+ WeightedGrammar<String> gramm) {
+ IList<String> retList = new FunctionalList<>();
+
+ if(strang.matches("\\[\\[\\S+\\]\\]")) {
+ if(strang.matches("\\[\\[\\S+:=\\S+\\]\\]")) {
+ doDefineExpandedVariable(vars, strang, gramm);
+ } else if(strang.matches("\\[\\[\\S+=\\S+\\]\\]")) {
+ doDefineVariable(vars, strang);
+ } else if(strang.matches("\\[\\[\\S+\\]\\]")) {
+ if(GrammarServerEngine.debugMode) {
+ if(strang.contains("+"))
+ System.out.println("Double-triggering no-space rule " + strang);
+ else
+ System.out.println("Triggered alternate no-space rule " + strang);
+ }
+
+ doNoSpaceRule(strang, gramm, retList);
+ } else if (strang.contains("+")) {
+ if(GrammarServerEngine.debugMode)
+ System.out.println("Triggered alternate no-space rule " + strang);
+
+ doNoSpaceRule(strang, gramm, retList);
+ } else {
+ // @FIXME notify the user they did something wrong
+ retList.add(strang);
+ }
+ } else {
+ if(strang.matches("\\[\\$\\S+\\-\\S+\\]")) {
+ retList = doExpandVariableReference(vars, strang, gramm);
+ } else if(strang.matches("\\[\\$\\S+\\]")) {
+ String varName = strang.substring(2, strang.length());
+
+ retList = vars.get(varName);
+ } else if (exportedRules.containsKey(strang) &&
+ exportedRules.get(strang) != gramm &&
+ !gramm.hasRule(strang)) {
+ // Only pick external rules if they are both
+ // a) in a different grammar
+ // b) not shadowed in the current grammar
+ WeightedGrammar<String> exportGram = exportedRules.get(strang);
+
+ retList = exportGram.generateGenericValues(strang, (s) -> s, " ");
+ } else if (strang.contains("+")) {
+ doNoSpaceRule(strang, gramm, retList);
+ } else {
+ // @FIXME notify the user they did something wrong
+ retList.add(strang);
+ }
+ }
+
+ return retList;
+ }
+
+ private static void handleRangeRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+
+ int start = Integer.parseInt(tokenizer.nextToken());
+ int end = Integer.parseInt(tokenizer.nextToken());
+
+ state.addSpecialRule(ruleName, () -> {
+ int genNum = numgen.nextInt((end - start) + 1) + start;
+
+ return new FunctionalList<>(Integer.toString(genNum));
+ });
+ }
+
+ private static void handleRegexRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+
+ IList<String> regx = tokenizer.toList();
+ Generex regex = new Generex(ListUtils.collapseTokens(regx));
+
+ state.addSpecialRule(ruleName, () -> {
+ return new FunctionalList<>(regex.random().split(" "));
+ });
+ }
+
+ private static int readOptionalProbability(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ if (state.isUniform()) {
+ return 1;
+ }
+
+ return Integer.parseInt(tokenizer.nextToken());
+ }
+
+ private static void initialRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String initialRuleName = tokenizer.nextToken();
+
+ state.setInitialRule(initialRuleName);
+ }
+
+ private static void prefixRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+ String prefixToken = tokenizer.nextToken();
+
+ int additionalProbability = readOptionalProbability(tokenizer, state);
+
+ state.prefixRule(ruleName, prefixToken, additionalProbability);
+ }
+
+ private static void removeRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+
+ state.deleteRule(ruleName);
+ }
+
+ private static void suffixRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+ String suffixToken = tokenizer.nextToken();
+
+ int additionalProbability = readOptionalProbability(tokenizer, state);
+
+ state.suffixRule(ruleName, suffixToken, additionalProbability);
+ }
+
+ private static void doCase(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ int ruleProbability = readOptionalProbability(tokenizer, state);
+
+ state.addCase(ruleProbability, tokenizer.toList());
+ }
+
+ private static void doDefineExpandedVariable(IMap<String, IList<String>> vars, String strang, WeightedGrammar<String> gramm) {
+ String[] varParts = strang.split(":=");
+
+ String varName = varParts[0].substring(2);
+ String ruleName = varParts[1].substring(0, varParts[1].length() - 2);
+
+ IList<String> varValue = gramm.generateGenericValues(
+ ruleName, (s) -> s, " ");
+
+ vars.put(varName, varValue);
+ }
+
+ private static void doDefineVariable(IMap<String, IList<String>> vars, String strang) {
+ String[] varParts = strang.split("=");
+
+ String varName = varParts[0].substring(2);
+ String varValue = varParts[1].substring(0, varParts[1].length() - 2);
+
+ vars.put(varName, new FunctionalList<>(varValue));
+ }
+
+ private static IList<String> doExpandVariableReference(IMap<String, IList<String>> vars, String strang,
+ WeightedGrammar<String> gramm) {
+ IList<String> retList;
+ String[] varParts = strang.substring(1, strang.length()).split("-");
+
+ StringBuilder actualName = new StringBuilder("[");
+
+ for(String varPart : varParts) {
+ if(varPart.startsWith("$")) {
+ IList<String> varName = vars.get(varPart.substring(1));
+
+ if(varName.getSize() != 1) {
+ // @FIXME notify the user they did something wrong
+ }
+
+ actualName.append(varName.first() + "-");
+ } else {
+ actualName.append(varPart + "-");
+ }
+ }
+
+ // Trim trailing -
+ actualName.deleteCharAt(actualName.length() - 1);
+
+ retList = gramm.generateGenericValues(actualName.toString(), (s) -> s, " ");
+ return retList;
+ }
+
+ private static void doNoSpaceRule(String strang, WeightedGrammar<String> gramm, IList<String> retList) {
+ if(!GrammarServerEngine.debugMode) {
+ IList<String> ruleValue = gramm.generateGenericValues(
+ strang, (s) -> s.trim(), "");
+
+ retList.add(ListUtils.collapseTokens(ruleValue));
+ } else {
+ // if(!gramm.hasRule(strang))
+ // System.out.println("Warning: Possible unexpanded rule " + strang);
+
+ retList.add(strang);
+ }
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/text/markov/Markov.java b/RGens/src/main/java/bjc/rgens/text/markov/Markov.java
new file mode 100755
index 0000000..a07f44e
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/text/markov/Markov.java
@@ -0,0 +1,189 @@
+package bjc.rgens.text.markov;
+
+import java.util.Map.Entry;
+import java.util.*;
+
+/**
+ * Represents a k-character substring. Can give a pseudo-random suffix
+ * character based on probability.
+ *
+ * @author Daniel Friedman (Fall 2011)
+ *
+ */
+public class Markov {
+ String substring;
+ int count = 0;
+
+ TreeMap<Character, Integer> map;
+
+ /**
+ * Constructs a Markov object from a given substring.
+ *
+ * @param substring
+ * the given substring.
+ */
+ public Markov(String substring) {
+ this.substring = substring;
+
+ map = new TreeMap<>();
+
+ add();
+ }
+
+ /**
+ * Constructs a Markov object from a given substring and suffix
+ * character. Suffix characters are stored in a TreeMap.
+ *
+ * @param substring
+ * the specified substring.
+ * @param suffix
+ * the specified suffix.
+ */
+ public Markov(String substring, Character suffix) {
+ this.substring = substring;
+
+ map = new TreeMap<>();
+
+ add(suffix);
+ }
+
+ /**
+ * Increments the count of number of times the substring appears in a
+ * text.
+ */
+ public void add() {
+ count++;
+ }
+
+ /**
+ * Adds a suffix character to the TreeMap.
+ *
+ * @param c
+ * the suffix character to be added.
+ */
+ public void add(char c) {
+ add();
+
+ if (map.containsKey(c)) {
+ int frequency = map.get(c);
+ map.put(c, frequency + 1);
+ } else
+ map.put(c, 1);
+ }
+
+ /**
+ * Gives the frequency count of a suffix character; that is, the number
+ * of times the specified suffix follows the substring in a text.
+ *
+ * @param c
+ * the specified suffix.
+ * @return the frequency count.
+ */
+ public int getFrequencyCount(char c) {
+ if (!map.containsKey(c)) {
+ return -1;
+ }
+
+ return map.get(c);
+ }
+
+ /**
+ * Gives a percentage of frequency count / number of total suffixes.
+ *
+ * @param c
+ * @return the ratio of frequency count of a single character to the
+ * total number of suffixes
+ */
+ public double getCharFrequency(char c) {
+ if (getFrequencyCount(c) == -1) {
+ return -1;
+ }
+
+ return (double) getFrequencyCount(c) / (double) count;
+ }
+
+ /**
+ * Finds whether or not the given suffix is in the TreeMap.
+ *
+ * @param c
+ * the given suffix.
+ * @return True if the suffix exists in the TreeMap, false otherwise.
+ */
+ public boolean containsChar(char c) {
+ if (!map.containsKey(c)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Gives the number of times this substring occurs in a text.
+ *
+ * @return said number of times.
+ */
+ public int count() {
+ return count;
+ }
+
+ /**
+ * Gives the TreeMap.
+ *
+ * @return the TreeMap.
+ */
+ public TreeMap<Character, Integer> getMap() {
+ return map;
+ }
+
+ /**
+ * Using probability, returns a pseudo-random character to follow the
+ * substring. Character possibilities are added to an ArrayList
+ * (duplicates allowed), and a random number from 0 to the last index
+ * in the ArrayList is picked. Since more common suffixes occupy more
+ * indices in the ArrayList, the probability of getting a more common
+ * suffix is greater than the probability of getting a less common
+ * suffix.
+ *
+ * @return the pseudo-random suffix.
+ */
+ public char random() {
+ Character ret = null;
+
+ Set<Entry<Character, Integer>> s = map.entrySet();
+
+ Iterator<Entry<Character, Integer>> it = s.iterator();
+
+ ArrayList<Character> suffixes = new ArrayList<>();
+
+ while (it.hasNext()) {
+ Entry<Character, Integer> tmp = it.next();
+
+ for (int i = 0; i < tmp.getValue(); i++) {
+ suffixes.add(tmp.getKey());
+ }
+ }
+
+ Random rand = new Random();
+ int retIndex = rand.nextInt(suffixes.size());
+ ret = suffixes.get(retIndex);
+ return ret;
+ }
+
+ /**
+ * Gives a String representation of the Markov object.
+ *
+ * @return said String representation.
+ */
+ @Override
+ public String toString() {
+ String ret = "Substring: " + substring + ", Count: " + count;
+ ret += "\n" + "Suffixes and frequency counts: ";
+
+ for (Entry<Character, Integer> entry : map.entrySet()) {
+ char key = entry.getKey();
+ int value = entry.getValue();
+ ret += "\n" + "Suffix: " + key + ", frequency count: " + value;
+ }
+ return ret;
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/text/markov/StandaloneMarkov.java b/RGens/src/main/java/bjc/rgens/text/markov/StandaloneMarkov.java
new file mode 100644
index 0000000..0edaaa8
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/text/markov/StandaloneMarkov.java
@@ -0,0 +1,42 @@
+package bjc.rgens.text.markov;
+
+import java.util.Map;
+
+public class StandaloneMarkov {
+ private int k;
+
+ private Map<String, Markov> markovHash;
+ private String firstSub;
+
+ public StandaloneMarkov(int k, Map<String, Markov> markovHash,
+ String firstSub) {
+ this.k = k;
+ this.markovHash = markovHash;
+ this.firstSub = firstSub;
+ }
+
+ public String generateTextFromMarkov(int M) {
+ StringBuilder text = new StringBuilder();
+ for (int i = k; i < M; i++) {
+ if (i == k) {
+ text.append(firstSub);
+
+ if (text.length() > k)
+ i = text.length();
+ }
+
+ String sub = text.substring((i - k), (i));
+ Markov tmp = markovHash.get(sub);
+
+ if (tmp != null) {
+ Character nextChar = tmp.random();
+ text.append(nextChar);
+ } else {
+ i = k - 1;
+ }
+ }
+
+ return text.toString();
+ }
+
+}
diff --git a/RGens/src/main/java/bjc/rgens/text/markov/StandaloneTextGenerator.java b/RGens/src/main/java/bjc/rgens/text/markov/StandaloneTextGenerator.java
new file mode 100644
index 0000000..92bc653
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/text/markov/StandaloneTextGenerator.java
@@ -0,0 +1,70 @@
+package bjc.rgens.text.markov;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Map;
+
+public class StandaloneTextGenerator {
+
+ /**
+ * Build a markov generator from a provided source
+ *
+ * @param k
+ * The markov order to use
+ * @param reader
+ * The source to seed the generator from
+ * @return The markov generator for the provided text
+ */
+ public static StandaloneMarkov generateMarkovMap(int k,
+ Reader reader) {
+ Map<String, Markov> hash = new HashMap<>();
+
+ Character next = null;
+
+ try {
+ next = (char) reader.read();
+ } catch (IOException e1) {
+ System.out
+ .println("IOException in stepping through the reader");
+ e1.printStackTrace();
+ System.exit(1);
+ }
+
+ StringBuilder origFileBuffer = new StringBuilder();
+
+ while (next != null && Character.isDefined(next)) {
+ Character.toString(next);
+ origFileBuffer.append(next);
+
+ try {
+ next = (char) reader.read();
+ } catch (IOException e) {
+ System.out.println(
+ "IOException in stepping through the reader");
+ e.printStackTrace();
+ }
+
+ }
+
+ String origFile = origFileBuffer.toString();
+ String firstSub = origFile.substring(0, k);
+
+ for (int i = 0; i < origFile.length() - k; i++) {
+ String sub = origFile.substring(i, i + k);
+ Character suffix = origFile.charAt(i + k);
+
+ if (hash.containsKey(sub)) {
+ Markov marvin = hash.get(sub);
+ marvin.add(suffix);
+ hash.put(sub, marvin);
+ } else {
+ Markov marvin = new Markov(sub, suffix);
+ hash.put(sub, marvin);
+ }
+ }
+
+ return new StandaloneMarkov(k, hash, firstSub);
+ }
+
+}
diff --git a/RGens/src/main/java/bjc/rgens/text/markov/TextGenerator.java b/RGens/src/main/java/bjc/rgens/text/markov/TextGenerator.java
new file mode 100755
index 0000000..770acd9
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/text/markov/TextGenerator.java
@@ -0,0 +1,69 @@
+package bjc.rgens.text.markov;
+
+import java.io.*;
+
+/**
+ * Generate text from a markov model of an input text
+ *
+ * @author ben
+ *
+ */
+public class TextGenerator {
+ /**
+ * @param args
+ * when used with three arguments, the first represents the
+ * k-order of the Markov objects. The second represents the
+ * number of characters to print out. The third represents
+ * the file to be read.
+ *
+ * When used with two arguments, the first represents the
+ * k-order of the Markov objects, and the second represents
+ * the file to be read. The generated text will be the same
+ * number of characters as the original file.
+ */
+ public static void main(String[] args) {
+ int k = 0;
+ int M = 0;
+
+ String file = "";
+ StringBuilder text = new StringBuilder();
+
+ if (args.length == 3) {
+ k = Integer.parseInt(args[0]);
+ M = Integer.parseInt(args[1]);
+ file = args[2];
+ } else if (args.length == 2) {
+ k = Integer.parseInt(args[0]);
+ file = args[1];
+ } else {
+ System.out
+ .println("\n" + "Usage: java TextGenerator k M file");
+ System.out.println(
+ "where k is the markov order, M is the number");
+ System.out.println(
+ "of characters to be printed, and file is the");
+ System.out.println(
+ "name of the file to print from. M may be left out."
+ + "\n");
+ System.exit(1);
+ }
+
+ StandaloneMarkov markov = null;
+
+ try (FileReader reader = new FileReader(file)) {
+ markov = StandaloneTextGenerator.generateMarkovMap(k,
+ reader);
+
+ System.out.println(markov.generateTextFromMarkov(M)
+ .substring(0, Math.min(M, text.length())));
+ } catch (FileNotFoundException e) {
+ System.out.println("File not found.");
+ e.printStackTrace();
+ System.exit(1);
+ } catch (IOException ioex) {
+ System.out.println("IOException");
+ ioex.printStackTrace();
+ System.exit(1);
+ }
+ }
+} \ No newline at end of file