add grammer assignment from WCC CS 145 Spring 2019.

This commit is contained in:
Matthew Jensen 2019-12-14 18:21:37 -08:00
parent 46f17fac95
commit 8018490bbd
6 changed files with 442 additions and 0 deletions

63
grammer/GrammarMain.java Normal file
View File

@ -0,0 +1,63 @@
// Stuart Reges
// 3/10/04
//
// GrammarMain contains a main program that prompts a user for the name of a
// grammar file and then gives the user the opportunity to generate random
// versions of various elements of the grammar.
import java.io.*;
import java.util.*;
public class GrammarMain {
public static void main(String[] args) throws FileNotFoundException {
Scanner console = new Scanner(System.in);
System.out.println("Welcome to the cs145 random sentence generator.");
System.out.println();
// open grammar file
System.out.print("What is the name of the grammar file? ");
String fileName = console.nextLine();
Scanner input = new Scanner(new File(fileName));
// read the grammar file and construct the grammar solver
List<String> grammar = new ArrayList<String>();
while (input.hasNextLine())
grammar.add(input.nextLine());
GrammarSolver solver =
new GrammarSolver(Collections.unmodifiableList(grammar));
showResults(console, solver);
}
// pre : console open for console reading, solver initialized
// post: allows the user to repeatedly pick a grammar element to generate
public static void showResults(Scanner console, GrammarSolver solver) {
for(;;) {
System.out.println();
System.out.println("Available symbols to generate are:");
System.out.println(solver.getSymbols());
System.out.print("What do you want generated (return to quit)? ");
String target = console.nextLine();
if (target.length() == 0)
break;
if (!solver.grammarContains(target))
System.out.println("Illegal symbol");
else {
System.out.print("How many do you want me to generate? ");
if (!console.hasNextInt())
System.out.println("that's not an integer");
else {
int number = console.nextInt();
if (number < 0)
System.out.println("no negatives allowed");
else {
String[] answers = solver.generate(target, number);
for (int i = 0; i < number; i++)
System.out.println(answers[i]);
}
}
console.nextLine(); // to position to next line
}
}
}
}

158
grammer/GrammarSolver.java Normal file
View File

@ -0,0 +1,158 @@
/**
*
* Matt Jensen
* CS145 - Lab 5
* 5/30/19
*
*/
import java.util.*;
import java.util.stream.Collectors;
public class GrammarSolver {
private Map<String, List<String>> grammarMap;
private List<String> grammarList;
// sets grammar of object.
public GrammarSolver(List<String> grammarList) {
this.grammarList = grammarList;
this.grammarMap = new TreeMap<String, List<String>>();
// add all lines to grammer.
for(String entry : grammarList) {
if( this.isValidEntry(entry) ) { // throws exception if illegal.
this.addEntry(entry);
}
}
}
/**
*
* Public Methods
*
*/
// publicly evaluate grammar
public String[] generate(String symbol, int times) {
String[] result = new String[times];
for( int i = 0; i < result.length; i++) {
result[i] = this.generate(symbol);
}
return result;
}
// map of available grammars.
public Map<String, List<String>> getGrammars() {
return this.grammarMap;
}
// list of grammars.
public List<String> getGrammarList() {
return this.grammarList;
}
// all the keys/nonterminals of the grammer
public String getSymbols() {
return this.getGrammars().keySet().toString();
}
// grammer contains a terminal key.
public boolean grammarContains(String key) {
return this.getGrammars().keySet().contains(key);
}
/**
*
* Private Helper Methods
*
*/
// recursively evaluate grammar
private String generate(String symbol) {
String result = "";
Set<String> symbols = this.getGrammars().keySet();
// base case
if(this.grammarContains(symbol) != true ) {
return "";
}
String rule = this.getRandomTerminal(symbol);
// apply the rules
for(String subRule : GrammarSolver.splitRule(rule)){
if( ! result.isEmpty()) {
result += " "; // keeps leading whitespace off.
}
if( this.grammarContains(subRule) ) { // test if a subrule is a nonterminal.
result += this.generate(subRule); // evaluates nonterminal rule and appends it.
} else {
result += subRule;
}
}
return result.trim();
}
// add grammar to grammars.
private void addEntry(String entry) {
String nonterminal = GrammarSolver.nonTerminal(entry);
List<String> rules = GrammarSolver.terminals(entry);
this.getGrammars().put(nonterminal, rules);
}
// line of a grammar is valid.
private boolean isValidEntry(String entry) {
// errors if bad colon count
int colonCount = entry.length() - entry.replace(":", "").length();
if( colonCount != 1) {
throw new IllegalArgumentException("does not contain single colon");
}
// errors if duplicate
String nonterminal = GrammarSolver.nonTerminal(entry);
if( this.getGrammars().keySet().contains(nonterminal) ) {
throw new IllegalArgumentException("duplicate non-terminal detected");
}
return true;
}
// random element of a non-terminal's rules.
private String getRandomTerminal(String symbol) {
Random random = new Random();
List<String> rules = this.getGrammars().get(symbol);
int index = random.nextInt(rules.size());
return rules.get(index);
}
/**
*
* Static Methods
*
*/
// splits a string of rules at the whitespaces.
private static String[] splitRule(String rule) {
String[] split = rule.split("[ \t]");
return split;
}
// pre: no whitespace.
// pre: non-empty.
public static String nonTerminal(String entry) {
return entry.substring(0, entry.indexOf(':'));
}
// extracts terminals from a string.
public static List<String> terminals(String entry) {
List<String> rules = new ArrayList<String>();
entry = entry.substring(entry.indexOf(':') + 1, entry.length());
String[] exploded = entry.split("\\|");
for(int i = 0; i < exploded.length; i++) {
rules.add(exploded[i]);
}
return rules;
}
}

206
grammer/GrammarTest.java Normal file
View File

@ -0,0 +1,206 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertArrayEquals;
import org.junit.Test;
import java.util.*;
public class GrammarTest {
@Test
public void testMixedNonAndTerminals() {
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:<b> <c>|<b>");
grammar.add("<b>:Test");
grammar.add("<c>:");
GrammarSolver solver = new GrammarSolver(grammar);
String[] result = solver.generate("<a>", 1);
String[] expected = new String[1];
Arrays.fill(expected, "Test");
assertArrayEquals(expected, result);
}
@Test(expected = IllegalArgumentException.class)
public void testGenerateNonTermDoesntExist() {
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:Test|:Other");
GrammarSolver solver = new GrammarSolver(grammar);
solver.generate("<b>", 1);
}
@Test(expected = IllegalArgumentException.class)
public void testGenerateTimesInvalid() {
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:Test|:Other");
GrammarSolver solver = new GrammarSolver(grammar);
solver.generate("<a>", 0);
solver.generate("<a>", -1);
}
@Test
public void testGenerate() {
String[] expected = new String[2];
Arrays.fill(expected, "Test");
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:Test");
GrammarSolver solver = new GrammarSolver(grammar);
String[] result = solver.generate("<a>", 2);
assertArrayEquals(expected, result);
}
@Test
public void testMultipleRulePaths() {
String[] expected = new String[3];
Arrays.fill(expected, "Test Nest");
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:<b> <c>");
grammar.add("<b>:Test");
grammar.add("<c>:Nest");
GrammarSolver solver = new GrammarSolver(grammar);
String[] result = solver.generate("<a>", 3);
assertArrayEquals(expected, result);
}
@Test
public void testMultipleSymbolsAsRules() {
String[] expected = new String[3];
Arrays.fill(expected, "Nest Nest");
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:<b> <c>");
grammar.add("<b>:<c>");
grammar.add("<c>:Nest");
GrammarSolver solver = new GrammarSolver(grammar);
String[] result = solver.generate("<a>", 3);
assertArrayEquals(expected, result);
}
@Test
public void testGenerateNestedTwice() {
String[] expected = new String[3];
Arrays.fill(expected, "Nest");
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:<b>");
grammar.add("<b>:<c>");
grammar.add("<c>:Nest");
GrammarSolver solver = new GrammarSolver(grammar);
String[] result = solver.generate("<a>", 3);
assertArrayEquals(expected, result);
}
@Test
public void testGenerateNested() {
String[] expected = new String[2];
Arrays.fill(expected, "Nest");
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:<b>");
grammar.add("<b>:Nest");
GrammarSolver solver = new GrammarSolver(grammar);
String[] result = solver.generate("<a>", 2);
assertArrayEquals(expected, result);
}
@Test
public void testGrammarListImmutable() {
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:Test");
GrammarSolver solver = new GrammarSolver(grammar);
String expected = grammar.get(0);
String actual = solver.getGrammarList().get(0);
assertEquals("got back different than instantiation.", expected, actual);
assertArrayEquals("different grammars.", grammar.toArray(), solver.getGrammarList().toArray());
}
@Test
public void testGrammarListImmutableWithPipe() {
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:Test|Other");
GrammarSolver solver = new GrammarSolver(grammar);
assertArrayEquals("different grammars.", grammar.toArray(), solver.getGrammarList().toArray());
}
@Test
public void testNonTerminalExtract() {
String entry = "<a>:Test";
String expected = "<a>";
String actual = GrammarSolver.nonTerminal(entry);
assertEquals("failure - extraction failed", expected, actual);
}
@Test
public void testRuleExtractContent() {
String entry = "<a>:Test";
List<String> expected = new ArrayList<String>();
expected.add("Test");
List<String> actual = GrammarSolver.terminals(entry);
assertArrayEquals("failure - rule extraction failed", expected.toArray(), actual.toArray());
}
@Test
public void testRuleCount() {
String entry = "<a>:Test";
List<String> expected = new ArrayList<String>();
expected.add("Test");
List<String> actual = GrammarSolver.terminals(entry);
assertEquals("rule count different", expected.size(), actual.size());
}
@Test(expected = IllegalArgumentException.class)
public void testNoColon() {
List<String> grammar = new ArrayList<String>();
grammar.add("test");
GrammarSolver solver = new GrammarSolver(grammar);
}
@Test(expected = IllegalArgumentException.class)
public void testDuplicateGrammar() {
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:Test|Other");
grammar.add("<a>:Test|Other");
GrammarSolver solver = new GrammarSolver(grammar);
}
@Test(expected = IllegalArgumentException.class)
public void testGrammarContainsSingleColon() {
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:Test|:Other");
GrammarSolver solver = new GrammarSolver(grammar);
}
@Test
public void testGrammarContains() {
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:Test");
GrammarSolver solver = new GrammarSolver(grammar);
assertEquals(true, solver.grammarContains("<a>"));
assertEquals(false, solver.grammarContains("a"));
assertEquals(false, solver.grammarContains("<b>"));
}
@Test
public void testGrammarContainsCaseInsensitive() {
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:Test");
GrammarSolver solver = new GrammarSolver(grammar);
assertEquals(true, solver.grammarContains("<a>"));
assertEquals(false, solver.grammarContains("<A>"));
}
@Test
public void testGetSymbols() {
List<String> grammar = new ArrayList<String>();
grammar.add("<a>:Test");
grammar.add("<b>:Test|Other");
GrammarSolver solver = new GrammarSolver(grammar);
assertEquals("[<a>, <b>]", solver.getSymbols());
}
@Test
public void testGetSymbolsSorted() {
List<String> grammar = new ArrayList<String>();
grammar.add("<C>:Test|Other");
grammar.add("<A>:Test");
grammar.add("<b>:Test|Other");
GrammarSolver solver = new GrammarSolver(grammar);
assertEquals("[<A>, <C>, <b>]", solver.getSymbols());
}
}

10
grammer/sentence.txt Normal file
View File

@ -0,0 +1,10 @@
<s>:<np> <vp>
<np>:<dp> <adjp> <n>|<pn>
<pn>:John|Jane|Sally|Spot|Fred|Elmo
<adjp>:<adj>|<adj> <adjp>
<adj>:big|fat|green|wonderful|faulty|subliminal|pretentious
<dp>:the|a
<n>:dog|cat|man|university|father|mother|child|television
<vp>:<tv> <np>|<iv>
<tv>:hit|honored|kissed|helped
<iv>:died|collapsed|laughed|wept

5
grammer/sentence2.txt Normal file
View File

@ -0,0 +1,5 @@
E: T | E OP T
T: x | y | 42 | 0 | 1 | 92 | ( E ) | F1 ( E ) | - T | F2 ( E , E )
OP: + | - | * | % | /
F1: sin | cos| tan |sqrt | abs
F2:max |min | pow

BIN
grammer/spec.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB