summaryrefslogtreecommitdiff
path: root/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java
diff options
context:
space:
mode:
authorbjculkin <bjculkin@mix.wvu.edu>2017-03-21 14:04:17 -0400
committerbjculkin <bjculkin@mix.wvu.edu>2017-03-21 14:04:17 -0400
commite279644fc59f46916c20b0b4f941fd37b4f07675 (patch)
tree7782b229f6482039ad0739079807294c14928085 /RGens/src/main/java/bjc/rgens/newparser/RGrammar.java
parentba7e0a2c1efe4203f766f3192b8852c3bb7d3369 (diff)
Finish basic implementation
This finishes a basic implementation. It now handles literal strings and rule references, allowing it to handle basic grammars.
Diffstat (limited to 'RGens/src/main/java/bjc/rgens/newparser/RGrammar.java')
-rw-r--r--RGens/src/main/java/bjc/rgens/newparser/RGrammar.java150
1 files changed, 150 insertions, 0 deletions
diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java
index 64385e9..4adcbe8 100644
--- a/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java
+++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammar.java
@@ -1,5 +1,8 @@
package bjc.rgens.newparser;
+import java.util.List;
+import java.util.Map;
+
/**
* Represents a randomized grammar.
*
@@ -7,5 +10,152 @@ package bjc.rgens.newparser;
*
*/
public class RGrammar {
+ private static class GenerationState {
+ public StringBuilder contents;
+
+ public GenerationState(StringBuilder contents) {
+ this.contents = contents;
+ }
+ }
+
+ private Map<String, Rule> rules;
+
+ private Map<String, Rule> importRules;
+
+ private String initialRule;
+
+ /**
+ * Create a new randomized grammar using the specified set of rules.
+ *
+ * @param rules
+ * The rules to use.
+ */
+ public RGrammar(Map<String, Rule> rules) {
+ this.rules = rules;
+ }
+
+ /**
+ * Sets the imported rules to use.
+ *
+ * Imported rules are checked for rule definitions after local
+ * definitions are checked.
+ *
+ * @param importedRules
+ * The set of imported rules to use.
+ */
+ public void setImportedRules(Map<String, Rule> importedRules) {
+ importRules = importedRules;
+ }
+
+ /**
+ * Generate a string from this grammar, starting from the specified
+ * rule.
+ *
+ * @param startRule
+ * The rule to start generating at, or null to use the
+ * initial rule for this grammar.
+ *
+ * @return A possible string from the grammar.
+ */
+ public String generate(String startRule) {
+ String fromRule = startRule;
+
+ if(startRule == null) {
+ if(initialRule == null) {
+ throw new GrammarException(
+ "Must specify a start rule for grammars with no initial rule");
+ } else {
+ fromRule = initialRule;
+ }
+ } else {
+ if(startRule.equals("")) {
+ throw new GrammarException("The empty string is not a valid rule name");
+ }
+ }
+
+ RuleCase start = rules.get(fromRule).getCase();
+
+ StringBuilder contents = new StringBuilder();
+
+ generateCase(start, new GenerationState(contents));
+
+ return contents.toString();
+ }
+
+ /*
+ * Generate a rule case.
+ */
+ private void generateCase(RuleCase start, GenerationState state) {
+ try {
+ switch(start.type) {
+ case NORMAL:
+ for(CaseElement elm : start.getElements()) {
+ generateElement(elm, state);
+ }
+ break;
+ default:
+ throw new GrammarException(String.format("Unknown case type '%s'", start.type));
+ }
+ } catch(GrammarException gex) {
+ throw new GrammarException(String.format("Error in generating case (%s)", start), gex);
+ }
+ }
+
+ /*
+ * Generate a case element.
+ */
+ private void generateElement(CaseElement elm, GenerationState state) {
+ try {
+ switch(elm.type) {
+ case LITERAL:
+ 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())) {
+ RuleCase cse = importRules.get(elm.getLiteral()).getCase();
+
+ generateCase(cse, state);
+ } else {
+ throw new GrammarException(
+ String.format("No rule by name '%s' found", elm.getLiteral()));
+ }
+ break;
+ default:
+ throw new GrammarException(String.format("Unknown element type '%s'", elm.type));
+ }
+ } catch(GrammarException gex) {
+ throw new GrammarException(String.format("Error in generating case element (%s)", elm), gex);
+ }
+ }
+
+ /**
+ * Get the initial rule of this grammar.
+ *
+ * @return The initial rule of this grammar.
+ */
+ public String getInitialRule() {
+ return initialRule;
+ }
+
+ /**
+ * Set the initial rule of this grammar.
+ *
+ * @param initialRule
+ * The initial rule of this grammar, or null to say there
+ * is no initial rule.
+ */
+ public void setInitialRule(String initialRule) {
+ if(initialRule.equals("")) {
+ throw new GrammarException("The empty string is not a valid rule name");
+ } else if(!rules.containsKey(initialRule)) {
+ throw new GrammarException(
+ String.format("No rule named '%s' local to this grammar found.", initialRule));
+ }
+ this.initialRule = initialRule;
+ }
}