diff options
| author | bjculkin <bjculkin@mix.wvu.edu> | 2017-03-21 15:42:22 -0400 |
|---|---|---|
| committer | bjculkin <bjculkin@mix.wvu.edu> | 2017-03-21 15:42:22 -0400 |
| commit | ccb2510fadf19e5e1cda63d948fd482e25fc799d (patch) | |
| tree | 0873c7693afb5aefcd1618a65933f795d6a72835 /RGens/src/main/java/bjc | |
| parent | ec144248bf199d8c3c0667a93ace78eb65a38de2 (diff) | |
Add export rules to grammars
Diffstat (limited to 'RGens/src/main/java/bjc')
6 files changed, 247 insertions, 19 deletions
diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java index 4adcbe8..35fc356 100644 --- a/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java +++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java @@ -1,7 +1,8 @@ package bjc.rgens.newparser; -import java.util.List; +import java.util.HashSet; import java.util.Map; +import java.util.Set; /** * Represents a randomized grammar. @@ -20,7 +21,9 @@ public class RGrammar { private Map<String, Rule> rules; - private Map<String, Rule> importRules; + private Map<String, RGrammar> importRules; + + private Set<String> exportRules; private String initialRule; @@ -40,11 +43,11 @@ public class RGrammar { * Imported rules are checked for rule definitions after local * definitions are checked. * - * @param importedRules + * @param exportedRules * The set of imported rules to use. */ - public void setImportedRules(Map<String, Rule> importedRules) { - importRules = importedRules; + public void setImportedRules(Map<String, RGrammar> exportedRules) { + importRules = exportedRules; } /** @@ -116,9 +119,9 @@ public class RGrammar { generateCase(cse, state); } else if(importRules.containsKey(elm.getLiteral())) { - RuleCase cse = importRules.get(elm.getLiteral()).getCase(); + RGrammar dst = importRules.get(elm.getLiteral()); - generateCase(cse, state); + state.contents.append(dst.generate(elm.getLiteral())); } else { throw new GrammarException( String.format("No rule by name '%s' found", elm.getLiteral())); @@ -149,6 +152,14 @@ public class RGrammar { * is no initial rule. */ public void setInitialRule(String initialRule) { + /* + * Passing null nulls our initial rule. + */ + if(initialRule == null) { + this.initialRule = null; + return; + } + if(initialRule.equals("")) { throw new GrammarException("The empty string is not a valid rule name"); } else if(!rules.containsKey(initialRule)) { @@ -158,4 +169,40 @@ public class RGrammar { this.initialRule = initialRule; } + + /** + * Gets the rules exported by this grammar. + * + * The initial rule is exported by default if specified. + * + * @return The rules exported by this grammar. + */ + public Set<Rule> getExportedRules() { + Set<Rule> res = new HashSet<>(); + + for(String rname : exportRules) { + if(!rules.containsKey(rname)) { + throw new GrammarException(String + .format("No rule named '%s' local to this grammar found", initialRule)); + } + + res.add(rules.get(rname)); + } + + if(initialRule != null) { + res.add(rules.get(initialRule)); + } + + return res; + } + + /** + * Set the rules exported by this grammar. + * + * @param exportRules + * The rules exported by this grammar. + */ + public void setExportedRules(Set<String> exportRules) { + this.exportRules = exportRules; + } } diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java index 7549847..346e588 100644 --- a/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java +++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java @@ -4,7 +4,9 @@ import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.IList; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import static bjc.rgens.newparser.CaseElement.ElementType.*; import static bjc.rgens.newparser.RuleCase.CaseType.*; @@ -16,11 +18,13 @@ import static bjc.rgens.newparser.RuleCase.CaseType.*; * */ public class RGrammarBuilder { - private Map<String, Rule> rules; + private IList<CaseElement> currentCase; private Rule currRule; - private IList<CaseElement> currentCase; + private Map<String, Rule> rules; + + private Set<String> exportedRules; private String initialRule; @@ -30,6 +34,8 @@ public class RGrammarBuilder { public RGrammarBuilder() { rules = new HashMap<>(); + exportedRules = new HashSet<>(); + currentCase = new FunctionalList<>(); } @@ -65,6 +71,8 @@ public class RGrammarBuilder { grammar.setInitialRule(initialRule); + grammar.setExportedRules(exportedRules); + return grammar; } @@ -139,6 +147,10 @@ public class RGrammarBuilder { * * @param init * The initial rule of the grammar. + * + * @throws IllegalArgumentException + * If the rule is either not valid or not defined in the + * grammar. */ public void setInitialRule(String init) { if(init == null) { @@ -151,4 +163,26 @@ public class RGrammarBuilder { initialRule = init; } + + /** + * Add an exported rule to this grammar. + * + * @param export + * The name of the rule to export. + * + * @throws IllegalArgumentException + * If the rule is either not valid or not defined in the + * grammar. + */ + public void addExport(String export) { + if(export == null) { + throw new NullPointerException("Export name must not be null"); + } else if(export.equals("")) { + throw new NullPointerException("The empty string is not a valid rule name"); + } else if(!rules.containsKey(export)) { + throw new IllegalArgumentException(String.format("No rule named '%s' found", export)); + } + + exportedRules.add(export); + } } diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java index b74c5f7..64d7b54 100644 --- a/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java +++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java @@ -49,6 +49,14 @@ public class RGrammarParser { build.setInitialRule(body); }); + + pragmas.put("export-rule", (body, build, level) -> { + String[] exports = body.split(" "); + + for(String export : exports) { + build.addExport(export); + } + }); } /** @@ -99,6 +107,7 @@ public class RGrammarParser { */ if(block.equals("")) return; if(block.equals("\n")) return; + if(block.equals("\r\n")) return; int typeSep = block.indexOf(' '); @@ -176,7 +185,11 @@ public class RGrammarParser { String pragmaBody = pragma.substring(bodySep + 1); if(pragmas.containsKey(pragmaName)) { - pragmas.get(pragmaName).accept(pragmaBody, build, level); + try { + pragmas.get(pragmaName).accept(pragmaBody, build, level); + } catch(GrammarException gex) { + throw new GrammarException(String.format("Error in '%s' pragma", pragmaName), gex); + } } else { throw new GrammarException(String.format("Unknown pragma named '%s'", pragmaName)); } @@ -211,7 +224,7 @@ public class RGrammarParser { * single case. */ handleRuleDecl(build, ruleBlock); - + build.finishRule(); } } catch(GrammarException gex) { @@ -231,7 +244,8 @@ public class RGrammarParser { if(declSep == -1) { /* - * The old syntax allowed it to work with just a space. + * TODO remove support for the old syntax when all of + * the files are converted. */ declSep = declContents.indexOf(' '); @@ -240,9 +254,6 @@ public class RGrammarParser { "A rule must be given at least one case in its declaration, and" + "seperated from that case by \u2192"); } - - System.out.println( - "WARNING: Rule declarations must now be seperated from the initial case by \u2192."); } String ruleName = declContents.substring(0, declSep).trim(); @@ -264,7 +275,14 @@ public class RGrammarParser { build.beginCase(); for(String csepart : cse.split(" ")) { - build.addCasePart(csepart); + String partToAdd = csepart.trim(); + + /* + * Ignore empty parts + */ + if(partToAdd.equals("")) continue; + + build.addCasePart(partToAdd); } build.finishCase(); diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarSet.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarSet.java new file mode 100644 index 0000000..e67e356 --- /dev/null +++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarSet.java @@ -0,0 +1,123 @@ +package bjc.rgens.newparser; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Represents a set of grammars that can share rules via exports. + * + * @author EVE + * + */ +public class RGrammarSet { + private Map<String, RGrammar> grammars; + + private Map<String, RGrammar> exportedRules; + + /** + * Create a new set of randomized grammars. + */ + public RGrammarSet() { + grammars = new HashMap<>(); + + exportedRules = new HashMap<>(); + } + + /** + * Add a grammar to this grammar set. + * + * @param grammarName + * The name of the grammar to add. + * + * @param gram + * The grammar to add. + * + * @throws IllegalArgumentException + * If the grammar name is invalid. + */ + public void addGrammar(String grammarName, RGrammar gram) { + if(grammarName == null) { + throw new NullPointerException("Grammar name must not be null"); + } else if(gram == null) { + throw new NullPointerException("Grammar must not be null"); + } else if(grammarName.equals("")) { + throw new IllegalArgumentException("The empty string is not a valid grammar name"); + } + + grammars.put(grammarName, gram); + + for(Rule export : gram.getExportedRules()) { + exportedRules.put(export.ruleName, gram); + } + + gram.setImportedRules(exportedRules); + } + + /** + * Get a grammar from this grammar set. + * + * @param grammarName + * The name of the grammar to get. + * + * @return The grammar with that name. + * + * @throws IllegalArgumentException + * If the grammar name is invalid or not present in this + * set. + */ + public RGrammar getGrammar(String grammarName) { + if(grammarName == null) { + throw new NullPointerException("Grammar name must not be null"); + } else if(grammarName.equals("")) { + throw new IllegalArgumentException("The empty string is not a valid grammar name"); + } else if(!grammars.containsKey("")) { + throw new IllegalArgumentException( + String.format("No grammar with name '%s' found", grammarName)); + } + + return grammars.get(grammarName); + } + + /** + * Get the grammar a rule was exported from. + * + * @param exportName + * The name of the exported rule. + * + * @return The grammar the exported rule came from. + * + * @throws IllegalArgumentException + * If the export name is invalid or not present in this + * set. + */ + public RGrammar getExportSource(String exportName) { + if(exportName == null) { + throw new NullPointerException("Export name must not be null"); + } else if(exportName.equals("")) { + throw new IllegalArgumentException("The empty string is not a valid rule name"); + } else if(!exportedRules.containsKey(exportName)) { + throw new IllegalArgumentException(String.format("No export with name '%s' found", exportName)); + } + + return exportedRules.get(exportName); + } + + /** + * Get the names of all the grammars in this set. + * + * @return The names of all the grammars in this set. + */ + public Set<String> getGrammars() { + return grammars.keySet(); + } + + /** + * Get the names of all the exported rules in this set. + * + * @return The names of all the exported rules in this set. + */ + public Set<String> getExportedRules() { + return exportedRules.keySet(); + } +} diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarTest.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarTest.java index 483542e..48977e9 100644 --- a/RGens/src/main/java/bjc/rgens/newparser/RGrammarTest.java +++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarTest.java @@ -16,12 +16,18 @@ public class RGrammarTest { * Unused CLI args. */ public static void main(String[] args) { - InputStream stream = RGrammarTest.class.getResourceAsStream("/sample-grammars/insults.gram"); + InputStream stream = RGrammarTest.class.getResourceAsStream("/sample-grammars/24hr-rpg.gram"); + + RGrammarSet grammarSet = new RGrammarSet(); RGrammarParser parse = new RGrammarParser(); RGrammar grammar = parse.readGrammar(stream); - System.out.println(grammar.generate(null)); + grammarSet.addGrammar("rpg", grammar); + + for(int i = 0; i < 10; i++) { + System.out.println(grammar.generate(null)); + } } } diff --git a/RGens/src/main/java/bjc/rgens/newparser/RuleCase.java b/RGens/src/main/java/bjc/rgens/newparser/RuleCase.java index e919cb8..9652273 100644 --- a/RGens/src/main/java/bjc/rgens/newparser/RuleCase.java +++ b/RGens/src/main/java/bjc/rgens/newparser/RuleCase.java @@ -18,7 +18,7 @@ public class RuleCase { /** * A normal case, composed from a list of elementList. */ - NORMAL; + NORMAL, } /** |
