package ppg.spec;
import java.io.*;
import java.util.*;
import ppg.*;
import ppg.atoms.*;
import ppg.code.*;
import ppg.lex.*;
import ppg.parse.*;
import ppg.util.*;
public class CUPSpec extends Spec
{
private Vector productions;
// maps nonterminal to its index in the vector of productions
private Hashtable ntProds;
private String start;
private final int NT_NOT_FOUND = -1;
public CUPSpec (String pkg, Vector imp, Vector codeParts, Vector syms,
Vector precedence, String startSym, Vector prods)
{
super();
packageName = pkg;
imports = imp;
replaceCode(codeParts);
symbols = syms;
prec = precedence;
start = startSym;
productions = prods;
ntProds = new Hashtable();
hashNonterminals();
}
public void setStart (String startSym) {
if (startSym != null)
start = startSym;
}
private void hashNonterminals() {
ntProds.clear();
if (productions == null)
return;
Production prod;
for (int i=0; i < productions.size(); i++) {
prod = (Production) productions.elementAt(i);
ntProds.put(prod.getLHS().getName(), new Integer(i));
}
}
public CUPSpec coalesce() {
// cannot have a parent by definition
return this;
}
/**
* Provides a copy of the production that was present in the original
* grammar, but is equal (minus semantic actions) to the given production set.
* Thus, we transfer the semantic actions without having to re-specify them.
*/
public Production findProduction (Production p) {
// find the nonterminal which would contain this production
Nonterminal nt = p.getLHS();
int pos = errorNotFound(findNonterminal(nt), nt);
Production sourceProd = (Production) productions.elementAt(pos);
Vector sourceRHSList = sourceProd.getRHS();
Vector rhs = p.getRHS();
Production result = new Production(nt, new Vector());
Vector toMatch, source, clone;
for (int i=0; i < rhs.size(); i++) {
toMatch = (Vector) rhs.elementAt(i);
for (int j=0; j < sourceRHSList.size(); j++) {
source = (Vector) sourceRHSList.elementAt(j);
if (Production.isSameProduction(toMatch, source)) {
clone = new Vector();
for (int k=0; k < source.size(); k++) {
clone.addElement( ((GrammarPart)source.elementAt(k)).clone() );
}
//result.addToRHS((Vector) source.clone());
result.addToRHS(clone);
break;
}
}
}
return result;
}
public void removeEmptyProductions () {
Production prod;
for (int i=0; i < productions.size(); i++) {
prod = (Production) productions.elementAt(i);
if (prod.getRHS().size() == 0) {
productions.removeElementAt(i);
i--;
}
}
}
public Object clone() {
String newPkgName = (packageName == null) ? null : packageName.toString();
/*******************/
Vector newImports = new Vector();
for (int i=0; i < imports.size(); i++) {
newImports.addElement( ((String) imports.elementAt(i)).toString());
}
/*******************/
Vector newCode = new Vector();
if (actionCode != null) newCode.addElement(actionCode);
if (initCode != null) newCode.addElement(initCode);
if (parserCode != null) newCode.addElement(parserCode);
if (scanCode != null) newCode.addElement(scanCode);
/*for (int i=0; i < code.size(); i++) {
newCode.addElement( ((Code) code.elementAt(i)).clone());
}*/
/*******************/
Vector newSymbols = new Vector();
for (int i=0; i < symbols.size(); i++) {
newSymbols.addElement( ((SymbolList) symbols.elementAt(i)).clone());
}
/*******************/
Vector newPrec = new Vector();
for (int i=0; i < prec.size(); i++) {
newPrec.addElement( ((Precedence) prec.elementAt(i)).clone());
}
/*******************/
String newStart = (start == null) ? null : start.toString();
/*******************/
Vector newProductions = new Vector();
for (int i=0; i < productions.size(); i++) {
newProductions.addElement( ((Production) productions.elementAt(i)).clone());
}
return new CUPSpec(newPkgName, newImports, newCode, newSymbols,
newPrec, newStart, newProductions);
/*
return new CUPSpec(newPkgName,
(Vector) imports.clone(),
(Vector) code.clone(),
(Vector) symbols.clone(),
(Vector) prec.clone(),
newStart,
(Vector) productions.clone());
*/
}
public void addSymbols(Vector syms) {
if (syms == null)
return;
for (int i=0; i < syms.size(); i++) {
symbols.addElement(syms.elementAt(i));
}
}
public void dropSymbol(String gs) throws PPGError {
boolean dropped = false;
for (int i=0; i < symbols.size(); i++ ) {
SymbolList list = (SymbolList) symbols.elementAt(i);
dropped = dropped || list.dropSymbol(gs);
}
//TODO: error if symbol being dropped was not found
/*
if (!dropped)
throw new PPGError("file", -1, "symbol "+gs+" not found.");
*/
}
public void dropProductions(Production p) {
Nonterminal nt = p.getLHS();
int pos = errorNotFound(findNonterminal(nt), nt);
// should be a valid index from which we can drop productions
Production prod = (Production) productions.elementAt(pos);
prod.drop(p);
}
public void dropProductions(Nonterminal nt) {
int pos = errorNotFound(findNonterminal(nt), nt);
// should be a valid index from which we can drop productions
Production prod = (Production) productions.elementAt(pos);
prod.drop((Production) prod.clone());
}
public void dropAllProductions(String nt) {
int pos = findNonterminal(nt);
// a terminal will not be in the hash
if (pos == NT_NOT_FOUND)
return;
// remove the whole lhs ::= rhs entry from the list of productions
productions.removeElementAt(pos);
// now we need to rehash since positions changed
hashNonterminals();
}
public void addProductions(Production p) {
Nonterminal nt = p.getLHS();
int pos = findNonterminal(nt);
if (pos == NT_NOT_FOUND) {
// add a hash mapping for this entry
ntProds.put(nt.getName(), new Integer(productions.size()));
// just append to our list
productions.addElement(p);
} else {
// attach to specific nonterminal in our list of productions
Production prod = (Production) productions.elementAt(pos);
prod.add(p);
//productions.setElementAt(prod, pos);
}
}
/**
* Returns int which is the position of the nonterminal in the production
* list, or exits if it is not found
*/
private int findNonterminal(Nonterminal nt) {
return findNonterminal(nt.getName());
}
private int findNonterminal(String nt) {
Integer pos = (Integer) ntProds.get(nt);
if (pos == null)
return NT_NOT_FOUND;
else
return pos.intValue();
}
private int errorNotFound(int i, Nonterminal nt) {
if (i == NT_NOT_FOUND) {
// index not found, hence we have no such terminal
System.err.println(PPG.HEADER + "nonterminal " + nt + " not found.");
System.exit(1);
}
return i;
}
public void unparse(CodeWriter cw) {
cw.begin(0);
if (packageName != null) {
cw.write("package " + packageName + ";");
cw.newline(); cw.newline();
}
// import
for (int i=0; i < imports.size(); i++) {
cw.write("import " + (String) imports.elementAt(i) + ";");
cw.newline();
}
if (imports.size() > 0)
cw.newline();
// code
if (actionCode != null)
cw.write(actionCode.toString());
if (initCode != null)
cw.write(initCode.toString());
if (parserCode != null)
cw.write(parserCode.toString());
if (scanCode != null)
cw.write(scanCode.toString());
cw.newline();
// symbols
for (int i=0; i < symbols.size(); i++) {
cw.write( ((SymbolList) symbols.elementAt(i)).toString() );
cw.newline();
}
cw.newline();
// precedence
for (int i=0; i < prec.size(); i++) {
cw.write( ((Precedence) prec.elementAt(i)).toString() );
cw.newline();
}
cw.newline();
// start
if (start != null) {
cw.write("start with " + start + ";");
cw.newline(); cw.newline();
}
// productions
for (int i=0; i < productions.size(); i++) {
((Production) productions.elementAt(i)).unparse(cw);
}
cw.newline();
cw.end();
//Write out to stdout in a naive manner
/*
try {
export(System.out);
} catch (Exception e) {
System.out.println(HEADER+"Exception: "+e.getMessage());
return;
}
*/
}
/**
* Write out the CUP specification to the stream
*/
public void export(PrintStream out) throws Exception {
// package
out.println("package " + packageName + ";");
out.println();
// import
for (int i=0; i < imports.size(); i++)
out.println("import " + (String) imports.elementAt(i) + ";");
out.println();
// code
/*
for (int i=0; i < code.size(); i++)
out.println( ((Code) code.elementAt(i)).toString() );
*/
if (actionCode != null)
out.println(actionCode.toString());
if (initCode != null)
out.println(initCode.toString());
if (parserCode != null)
out.println(parserCode.toString());
if (scanCode != null)
out.println(scanCode.toString());
out.println();
// symbols
for (int i=0; i < symbols.size(); i++)
out.println( ((SymbolList) symbols.elementAt(i)).toString() );
out.println();
// precedence
for (int i=0; i < prec.size(); i++)
out.println( ((Precedence) prec.elementAt(i)).toString() );
out.println();
// start
out.println("start with " + start + ";");
out.println();
// productions
for (int i=0; i < productions.size(); i++)
out.println( ((Production) productions.elementAt(i)).toString() );
out.println();
out.flush();
out.close();
}
}