package ppg.atoms;
import java.util.*;
import ppg.parse.*;
import ppg.util.*;
public class Production implements Unparse
{
private Nonterminal lhs;
private Vector rhs;
private static String HEADER = "ppg [nterm]: ";
public Production (Nonterminal lhs, Vector rhs) {
this.lhs = lhs;
this.rhs = rhs;
}
public Nonterminal getLHS() { return lhs; }
public void setLHS(Nonterminal nt) { lhs = nt; }
public Vector getRHS() { return rhs; }
public Object clone() {
return new Production((Nonterminal) lhs.clone(),
(Vector) rhs.clone());
}
public void drop (Production prod) {
//assertSameLHS(prod, "drop");
Vector toDrop = prod.getRHS();
// this is O(n^2)
Vector target, source;
for (int i=0; i < toDrop.size(); i++) {
target = (Vector) toDrop.elementAt(i);
for (int j=0; j < rhs.size(); j++) {
source = (Vector) rhs.elementAt(j);
if (isSameProduction(target, source)) {
rhs.removeElementAt(j);
break;
}
// production match not found
if (j == rhs.size() - 1) {
System.err.println(HEADER+"no match found for production:");
System.err.print(prod.getLHS() + " ::= ");
for (int k=0; k < target.size(); k++) {
System.err.print(target.elementAt(k)+" ");
}
System.exit(1);
}
}
}
}
public static boolean isSameProduction (Vector u, Vector v) {
int uIdx = 0, vIdx = 0;
GrammarPart ug = null, vg = null;
while (uIdx < u.size() && vIdx < v.size()) {
ug = (GrammarPart) u.elementAt(uIdx);
if (ug instanceof SemanticAction) {
uIdx++;
continue;
}
vg = (GrammarPart) v.elementAt(vIdx);
if (vg instanceof SemanticAction) {
vIdx++;
continue;
}
if (! ug.equals(vg))
return false;
else {
uIdx++;
vIdx++;
}
}
if (uIdx == u.size() && vIdx == v.size()) {
// got through all the way, they are the same
return true;
} else {
// one of the lists was not seen all the way,
// must check that only semantic actions are left
if (uIdx < u.size()) {
for (; uIdx < u.size(); uIdx++) {
ug = (GrammarPart) u.elementAt(uIdx);
if (! (ug instanceof SemanticAction))
return false;
}
return true;
} else { // vIdx < v.size()
for (; vIdx < v.size(); vIdx++) {
vg = (GrammarPart) v.elementAt(vIdx);
if (! (vg instanceof SemanticAction))
return false;
}
return true;
}
}
}
public void union (Production prod) {
Vector additional = prod.getRHS();
union(additional);
}
public void union (Vector prodList) {
Vector toAdd, current;
for (int i=0; i < prodList.size(); i++) {
toAdd = (Vector) prodList.elementAt(i);
for (int j=0; j < rhs.size(); j++) {
current = (Vector) rhs.elementAt(i);
if (isSameProduction(toAdd, current))
break;
if (j == rhs.size() - 1)
rhs.addElement(toAdd);
}
}
}
public void add (Production prod) {
//assertSameLHS(prod, "add");
Vector additional = prod.getRHS();
for (int i=0; i < additional.size(); i++) {
rhs.addElement( additional.elementAt(i) );
}
}
public void addToRHS (Vector rhsPart) {
rhs.addElement(rhsPart);
}
private void assertSameLHS(Production prod, String function) {
if (! (prod.getLHS().equals(lhs)) ) {
System.err.println(HEADER + "nonterminals do not match in Production."+
function + "(): current is "+lhs+", given: "+
prod.getLHS());
System.exit(1);
}
}
public void unparse (CodeWriter cw) {
cw.begin(0);
cw.write(lhs.toString() + " ::=");
cw.allowBreak(3);
Vector rhs_part;
for (int i=0; i < rhs.size(); i++) {
rhs_part = (Vector) rhs.elementAt(i);
for (int j=0; j < rhs_part.size(); j++) {
cw.write(" ");
((GrammarPart) rhs_part.elementAt(j)).unparse(cw);
}
if (i < rhs.size() - 1) {
cw.allowBreak(0);
cw.write(" | ");
}
}
cw.write(";");
cw.newline(); cw.newline();
cw.end();
}
public String toString() {
String result = lhs.toString();
Vector rhs_part;
result += " ::=";
for (int i=0; i < rhs.size(); i++) {
rhs_part = (Vector) rhs.elementAt(i);
for (int j=0; j < rhs_part.size(); j++) {
result += " " + rhs_part.elementAt(j).toString();
}
if (i < rhs.size() - 1)
result += " | ";
}
return result + ";";
}
}