summaryrefslogtreecommitdiff
path: root/RGens/src/main
diff options
context:
space:
mode:
authorbjculkin <bjculkin@mix.wvu.edu>2017-03-21 19:29:27 -0400
committerbjculkin <bjculkin@mix.wvu.edu>2017-03-21 19:38:42 -0400
commit5444cd4db8a0fa41d25cd303c1145cadd112e12f (patch)
tree779f205becc1e1cded6ed1c307f295a2404ce22d /RGens/src/main
parentccb2510fadf19e5e1cda63d948fd482e25fc799d (diff)
Add formatter
Adds a formatter capable of taking in a parsed grammar and printing it out in a formatted form, capable of being reparsed.
Diffstat (limited to 'RGens/src/main')
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/CaseElement.java24
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/RGrammar.java45
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java12
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/RGrammarFormatter.java98
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java8
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/RGrammarTest.java11
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/Rule.java57
7 files changed, 236 insertions, 19 deletions
diff --git a/RGens/src/main/java/bjc/rgens/newparser/CaseElement.java b/RGens/src/main/java/bjc/rgens/newparser/CaseElement.java
index fe088b8..a15cb9b 100644
--- a/RGens/src/main/java/bjc/rgens/newparser/CaseElement.java
+++ b/RGens/src/main/java/bjc/rgens/newparser/CaseElement.java
@@ -92,11 +92,35 @@ public class CaseElement {
}
/**
+
+ /**
* Get the literal string value for this element.
*
* @return The literal string value for this element.
+ *
+ * @throws IllegalStateException
+ * If this type doesn't have a literal string value.
*/
public String getLiteral() {
+ switch(type) {
+ case LITERAL:
+ case RULEREF:
+ break;
+ default:
+ throw new IllegalStateException(String.format("Type '%s' doesn't have a literal string value"));
+ }
+
return literalVal;
}
+
+ @Override
+ public String toString() {
+ switch(type) {
+ case LITERAL:
+ case RULEREF:
+ return literalVal;
+ default:
+ return String.format("Unknown type '%s'", type);
+ }
+ }
} \ No newline at end of file
diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java
index 35fc356..3e82779 100644
--- a/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java
+++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java
@@ -114,18 +114,7 @@ public class RGrammar {
state.contents.append(elm.getLiteral() + " ");
break;
case RULEREF:
- if(rules.containsKey(elm.getLiteral())) {
- RuleCase cse = rules.get(elm.getLiteral()).getCase();
-
- generateCase(cse, state);
- } else if(importRules.containsKey(elm.getLiteral())) {
- RGrammar dst = importRules.get(elm.getLiteral());
-
- state.contents.append(dst.generate(elm.getLiteral()));
- } else {
- throw new GrammarException(
- String.format("No rule by name '%s' found", elm.getLiteral()));
- }
+ generateRuleReference(elm, state);
break;
default:
throw new GrammarException(String.format("Unknown element type '%s'", elm.type));
@@ -135,6 +124,29 @@ public class RGrammar {
}
}
+ /*
+ * Generate a rule reference.
+ */
+ private void generateRuleReference(CaseElement elm, GenerationState state) {
+ String refersTo = elm.getLiteral();
+
+ GenerationState newState = new GenerationState(new StringBuilder());
+
+ if(rules.containsKey(refersTo)) {
+ RuleCase cse = rules.get(refersTo).getCase();
+
+ generateCase(cse, newState);
+ } else if(importRules.containsKey(refersTo)) {
+ RGrammar dst = importRules.get(refersTo);
+
+ newState.contents.append(dst.generate(refersTo));
+ } else {
+ throw new GrammarException(String.format("No rule by name '%s' found", refersTo));
+ }
+
+ state.contents.append(newState.contents.toString());
+ }
+
/**
* Get the initial rule of this grammar.
*
@@ -205,4 +217,13 @@ public class RGrammar {
public void setExportedRules(Set<String> exportRules) {
this.exportRules = exportRules;
}
+
+ /**
+ * Get all the rules in this grammar.
+ *
+ * @return All the rules in this grammar.
+ */
+ public Map<String, Rule> getRules() {
+ return rules;
+ }
}
diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java
index 346e588..fb8003a 100644
--- a/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java
+++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java
@@ -18,6 +18,10 @@ import static bjc.rgens.newparser.RuleCase.CaseType.*;
*
*/
public class RGrammarBuilder {
+ private static final String REFER_CASELEM = "\\[[^\\]]+\\]";
+
+ private static final String SPECIAL_CASELEM = "{[^}]}";
+
private IList<CaseElement> currentCase;
private Rule currRule;
@@ -91,8 +95,12 @@ public class RGrammarBuilder {
* @param csepart
*/
public void addCasePart(String csepart) {
- if(csepart.matches("\\[[^\\]]+\\]")) {
- currentCase.add(new CaseElement(RULEREF, csepart));
+ if(csepart.matches(SPECIAL_CASELEM)) {
+ /*
+ * Handle other cases.
+ */
+ } else if(csepart.matches(REFER_CASELEM)) {
+ currentCase.add(new CaseElement(RULEREF, csepart));
} else {
currentCase.add(new CaseElement(LITERAL, csepart));
}
diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarFormatter.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarFormatter.java
new file mode 100644
index 0000000..231e191
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarFormatter.java
@@ -0,0 +1,98 @@
+package bjc.rgens.newparser;
+
+import bjc.utils.funcdata.IList;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Format randomized grammars to strings properly.
+ *
+ * @author EVE
+ *
+ */
+public class RGrammarFormatter {
+ /**
+ * Format a grammar into a file that represents that grammar.
+ *
+ * @param gram
+ * The grammar to format.
+ *
+ * @return The formatted grammar.
+ */
+ public static String formatGrammar(RGrammar gram) {
+ StringBuilder sb = new StringBuilder();
+
+ Map<String, Rule> rules = gram.getRules();
+
+ String initRuleName = gram.getInitialRule();
+
+ Set<String> processedRules = new HashSet<>();
+
+ if(initRuleName != null) {
+ processRule(rules.get(initRuleName), sb);
+
+ processedRules.add(initRuleName);
+ }
+
+ for(Rule rule : rules.values()) {
+ if(!processedRules.contains(rule.ruleName)) {
+ sb.append("\n\n");
+
+ processRule(rule, sb);
+ }
+
+ processedRules.add(rule.ruleName);
+ }
+
+ return sb.toString().trim();
+ }
+
+ private static void processRule(Rule rule, StringBuilder sb) {
+ IList<RuleCase> cases = rule.getCases();
+
+ StringBuilder ruleBuilder = new StringBuilder();
+
+ ruleBuilder.append(rule.ruleName);
+ ruleBuilder.append(" \u2192 ");
+
+ int markerPos = ruleBuilder.length();
+
+ processCase(cases.first(), ruleBuilder);
+
+ sb.append(ruleBuilder.toString().trim());
+
+ ruleBuilder = new StringBuilder();
+
+ for(RuleCase cse : cases.tail()) {
+ sb.append("\n\t");
+
+ for(int i = 8; i < markerPos; i++) {
+ ruleBuilder.append(" ");
+ }
+
+ processCase(cse, ruleBuilder);
+
+ sb.append(ruleBuilder.toString());
+
+ ruleBuilder = new StringBuilder();
+ }
+
+ }
+
+ private static void processCase(RuleCase cse, StringBuilder sb) {
+ /*
+ * Process each element, adding a space.
+ */
+ for(CaseElement element : cse.getElements()) {
+ sb.append(element.toString());
+ sb.append(" ");
+ }
+
+ /*
+ * Remove the trailing space.
+ */
+ sb.deleteCharAt(sb.length() - 1);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java
index 64d7b54..3d7b708 100644
--- a/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java
+++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java
@@ -20,13 +20,13 @@ public class RGrammarParser {
/*
* Templates for level-dependent delimiters.
*/
- private static final String TMPL_PRAGMA_BLOCK_DELIM = "\\n\\t{%d}(?!\\t)";
- private static final String TMPL_RULEDECL_BLOCK_DELIM = "\\n\\t\\t{%d}";
+ private static final String TMPL_PRAGMA_BLOCK_DELIM = "\\r?\\n\\t{%d}(?!\\t)";
+ private static final String TMPL_RULEDECL_BLOCK_DELIM = "\\r?\\n\\t\\t{%d}";
/*
* Templates for non-level-dependent delimiters.
*/
- private static final String TOPLEVEL_BLOCK_DELIM = "\\n\\.?\\n";
+ private static final String TOPLEVEL_BLOCK_DELIM = "\\r?\\n\\.?\\r?\\n";
/*
* Pragma impls.
@@ -276,7 +276,7 @@ public class RGrammarParser {
for(String csepart : cse.split(" ")) {
String partToAdd = csepart.trim();
-
+
/*
* Ignore empty parts
*/
diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarTest.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarTest.java
index 48977e9..76efa86 100644
--- a/RGens/src/main/java/bjc/rgens/newparser/RGrammarTest.java
+++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarTest.java
@@ -16,7 +16,7 @@ public class RGrammarTest {
* Unused CLI args.
*/
public static void main(String[] args) {
- InputStream stream = RGrammarTest.class.getResourceAsStream("/sample-grammars/24hr-rpg.gram");
+ InputStream stream = RGrammarTest.class.getResourceAsStream("/sample-grammars/web.gram");
RGrammarSet grammarSet = new RGrammarSet();
@@ -29,5 +29,14 @@ public class RGrammarTest {
for(int i = 0; i < 10; i++) {
System.out.println(grammar.generate(null));
}
+
+ System.out.println();
+ System.out.println();
+
+ System.out.println("Formatted grammar: ");
+
+ String formattedGrammar = RGrammarFormatter.formatGrammar(grammar);
+
+ System.out.print(formattedGrammar);
}
}
diff --git a/RGens/src/main/java/bjc/rgens/newparser/Rule.java b/RGens/src/main/java/bjc/rgens/newparser/Rule.java
index c479c87..a65f1ce 100644
--- a/RGens/src/main/java/bjc/rgens/newparser/Rule.java
+++ b/RGens/src/main/java/bjc/rgens/newparser/Rule.java
@@ -22,8 +22,17 @@ public class Rule {
*
* @param ruleName
* The name of the grammar rule.
+ *
+ * @throws IllegalArgumentException
+ * If the rule name is invalid.
*/
public Rule(String ruleName) {
+ if(ruleName == null) {
+ throw new NullPointerException("Rule name must not be null");
+ } else if(ruleName.equals("")) {
+ throw new IllegalArgumentException("The empty string is not a valid rule name");
+ }
+
this.ruleName = ruleName;
ruleCases = new FunctionalList<>();
@@ -36,6 +45,10 @@ public class Rule {
* The case to add.
*/
public void addCase(RuleCase cse) {
+ if(cse == null) {
+ throw new NullPointerException("Case must not be null");
+ }
+
ruleCases.add(cse);
}
@@ -47,4 +60,48 @@ public class Rule {
public RuleCase getCase() {
return ruleCases.randItem();
}
+
+ /**
+ * Get all the cases of this rule.
+ *
+ * @return All the cases in this rule.
+ */
+ public IList<RuleCase> getCases() {
+ return ruleCases;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+
+ int result = 1;
+ result = prime * result + ((ruleCases == null) ? 0 : ruleCases.hashCode());
+ result = prime * result + ((ruleName == null) ? 0 : ruleName.hashCode());
+
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(this == obj) return true;
+ if(obj == null) return false;
+ if(!(obj instanceof Rule)) return false;
+
+ Rule other = (Rule) obj;
+
+ if(ruleCases == null) {
+ if(other.ruleCases != null) return false;
+ } else if(!ruleCases.equals(other.ruleCases)) return false;
+
+ if(ruleName == null) {
+ if(other.ruleName != null) return false;
+ } else if(!ruleName.equals(other.ruleName)) return false;
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Rule [ruleName='%s', ruleCases=%s]", ruleName, ruleCases);
+ }
} \ No newline at end of file