Commit 0bfa89fe authored by Alexandru Dura's avatar Alexandru Dura
Browse files

Enumerate parse trees from the SPPF

parent 9d220f4a
......@@ -2,6 +2,7 @@ package se.lth.sep;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.TreeSet;
public class Grammar {
......@@ -122,4 +123,15 @@ public class Grammar {
throw new EarleyException("Rule not preset in the grammar");
return r;
}
public Rule getRule(Category head, List<Category> body) {
List<Rule> ruleList = grammarRules.get(head);
if (ruleList == null)
return null;
for (Rule r : ruleList) {
if (r.getBody().equals(body))
return r;
}
return null;
}
}
package se.lth.sep;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ParseTree {
private int start;
private int end;
private Category cat;
private ArrayList<ParseTree> children;
public ParseTree(Category c, int start, int end) {
this.cat = c;
this.children = new ArrayList<ParseTree>();
this.start = start;
this.end = end;
}
public void addChild(ParseTree t) {
children.add(t);
}
public void addChildren(Collection<ParseTree> ts) {
children.addAll(ts);
}
public List<ParseTree> getChildren() {
return children;
}
public Category getCategory() {
return cat;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
}
package se.lth.sep;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import se.lth.sep.SPPFNode.FamilyNode;
public class ParseTreeGenerator implements SPPFNodeVisitor {
private HashMap<SPPFNode, LinkedList<ParseTree>> nodeMap = new HashMap<>();
private HashMap<SPPFNode.FamilyNode, LinkedList<LinkedList<ParseTree>>> familyMap = new HashMap<>();
private Grammar grammar;
private SPPFNode root;
public ParseTreeGenerator(Grammar grammar, SPPFNode root) {
this.grammar = grammar;
this.root = root;
}
public List<ParseTree> getParseTrees() {
root.accept(this);
return nodeMap.get(root);
}
@Override
public void visit(FamilyNode f) {
if (familyMap.containsKey(f))
return;
for (int i = 0; i < f.getNumChildren(); ++i) {
f.getChild(i).accept(this);
}
LinkedList<LinkedList<ParseTree>> childrenTrees = new LinkedList<>();
for (int i = 0; i < f.getNumChildren(); ++i) {
childrenTrees.add(nodeMap.get(f.getChild(i)));
}
LinkedList<LinkedList<ParseTree>> childrenCombinations = Util.<ParseTree>product(childrenTrees.iterator());
familyMap.put(f, childrenCombinations);
}
@Override
public void visit(SPPFNode n) {
if (nodeMap.containsKey(n)) {
return;
}
int start = n.getLabel().getStart();
int end = n.getLabel().getEnd();
Category c = ((SymbolLabel)n.getLabel()).getSymbol(grammar);
LinkedList<ParseTree> result = new LinkedList<>();
if (n.getChildren().isEmpty()) {
// handle the empty case
result.add(new ParseTree(c, start, end));
}
for (FamilyNode f : n.getChildren()) {
f.accept(this);
LinkedList<LinkedList<ParseTree>> childAlternatives = familyMap.get(f);
for (LinkedList<ParseTree> childAlternative : childAlternatives) {
ParseTree pt = new ParseTree(c, start, end);
pt.addChildren(childAlternative);
result.add(pt);
}
}
nodeMap.put(n, result);
}
}
......@@ -4,13 +4,24 @@ import java.util.Arrays;
import java.util.List;
public class Rule {
private Category head;
private Category[] body;
private final Category head;
private final Category[] body;
private final SemanticAction action;
public Rule(Category head, Category... body) {
this.head = head;
// assert body.length > 0;
this.body = body;
this.action = SemanticAction.NULL;
}
public Rule(SemanticAction act, Category head, Category... body) {
this.head = head;
this.body = body;
this.action = act;
}
public SemanticAction getAction() {
return action;
}
public Category getHead() {
......@@ -20,4 +31,33 @@ public class Rule {
public List<Category> getBody() {
return Arrays.asList(body);
}
@Override
public int hashCode() {
final int prime = 47;
int result = 1;
result = prime * result + Arrays.hashCode(body);
result = prime * result + ((head == null) ? 0 : head.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Rule other = (Rule) obj;
if (!Arrays.equals(body, other.body))
return false;
if (head == null) {
if (other.head != null)
return false;
} else if (!head.equals(other.head))
return false;
return true;
}
}
package se.lth.sep;
import java.util.List;
public abstract class SemanticAction {
public abstract Object act(List<Object> children);
public static SemanticAction NULL = new SemanticAction() {
@Override public Object act(List<Object> children) { return null; }
};
public static SemanticAction PASSTROUGH = new SemanticAction() {
@Override public Object act(List<Object> children) { return children.get(0); }
};
}
......@@ -3,7 +3,12 @@ package se.lth.sep;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import org.apache.commons.lang3.mutable.MutableInt;
public class Util {
public static void dumpParseResult(String dotFileName, SPPFNode node, Grammar grammar) {
......@@ -17,6 +22,65 @@ public class Util {
e.printStackTrace();
}
}
private static int dumpParseTree(PrintStream ps, ParseTree pt, MutableInt count) {
int currentID = count.getAndIncrement();
ps.println(currentID + " [shape=box,label=\"" + pt.getCategory().getName() + "\"];");
for (ParseTree c : pt.getChildren()) {
int childID = dumpParseTree(ps, c, count);
ps.println(currentID + " -> " + childID + ";");
}
return currentID;
}
public static void dumpParseTree(String dotFileName, ParseTree pt) {
try {
PrintStream out = new PrintStream(new File(dotFileName));
out.println("digraph G {");
dumpParseTree(out, pt, new MutableInt(0));
out.println("}");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void dumpParseTrees(String dotFilePrefix, Collection<ParseTree> pts) {
int index = 0;
for (ParseTree pt : pts) {
index++;
dumpParseTree(dotFilePrefix + "_" + index + ".dot", pt);
}
}
public static<T> LinkedList<LinkedList<T>> product(Iterator<LinkedList<T>> children) {
if (!children.hasNext()) {
return new LinkedList<>();
}
LinkedList<T> head = children.next();
LinkedList<LinkedList<T>> tail = product(children);
LinkedList<LinkedList<T>> result = new LinkedList<>();
if (tail.isEmpty()) {
for (T t : head) {
LinkedList<T> singleton = new LinkedList<T>();
singleton.add(t);
result.add(singleton);
}
return result;
}
for (T t : head) {
for (LinkedList<T> tt : tail) {
LinkedList<T> childList = new LinkedList<>();
childList.add(t);
childList.addAll(tt);
result.add(childList);
}
}
return result;
}
}
class DotVisitor implements SPPFNodeVisitor {
......
import static org.junit.Assert.*;
import java.util.List;
import se.lth.sep.*;
import org.junit.Test;
......@@ -195,7 +198,10 @@ public class EarleyParserTest {
};
tpr.visit(root);
Util.dumpParseResult("testJava1-notr.dot", root, g);
// dump the parse trees
ParseTreeGenerator ptg = new ParseTreeGenerator(g, root);
List<ParseTree> pts = ptg.getParseTrees();
Util.dumpParseTrees("testJava1-parse-tree", pts);
}
@Test public void testJava2() {
......@@ -236,6 +242,11 @@ public class EarleyParserTest {
};
tpr.visit(root);
Util.dumpParseResult("testJava2-notr.dot", root, g);
// dump the parse trees
ParseTreeGenerator ptg = new ParseTreeGenerator(g, root);
List<ParseTree> pts = ptg.getParseTrees();
Util.dumpParseTrees("testJava2-parse-tree", pts);
}
@Test public void testJava3() {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment