/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This file is part of SableCC. *
* See the file "LICENSE" for copyright information and the *
* terms and conditions for copying, distribution and *
* modification of SableCC. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Last Modification date : 17-11-2003
* Fix simpleTerm and simpleListTerm bug related to
* name confusion.
* Now, elem_name is automatically added to an elem to avoid that.
* The name has the form (production_name#alternative_name#elemId)
* or (production_name#alternative_name#elemName)
*/
package org.sablecc.sablecc;
import org.sablecc.sablecc.analysis.*;
import org.sablecc.sablecc.node.*;
import java.util.*;
@SuppressWarnings({"rawtypes", "unchecked"})
public class Inlining {
public static HashSet productionsToBeRemoved =
new HashSet();
private AProd current_production;
//The production to inline within current_production
private In_Production prod_to_inline;
public Inlining(AProd curr_prod, In_Production prod_to_inline) {
this.current_production = curr_prod;
this.prod_to_inline = prod_to_inline;
}
/*
* The core of inlining is done here.
* returns true if it succeeds and false otherwise
*/
public boolean inlineProduction() {
AAlt[] alts = (AAlt[]) current_production.getAlts().toArray(new AAlt[0]);
final BooleanEx prodMustBeInlined = new BooleanEx(false);
/*
We're trying to detect if the current production must be inlined.
ie one of its alternatives contains production to inline
*/
for (int i = 0; i < alts.length; i++) {
((PAlt) alts[i]).apply(new DepthFirstAdapter() {
@Override
public void caseAElem(AElem node) {
String elem_name = node.getId().getText();
if (elem_name.equals(prod_to_inline.getName()) &&
!(node.getSpecifier() instanceof ATokenSpecifier)) {
prodMustBeInlined.setValue(true);
}
}
}
);
//We only need to know if one element within one of the production alternatives matches.
if (prodMustBeInlined.getValue()) {
break;
}
}
//IfStmt the production must be inlined
if (prodMustBeInlined.getValue()) {
/*
Once we detect that the production can be inline,
we try to inline each of its alternatives.
*/
LinkedList listOfAlts = new TypedLinkedList(NodeCast.instance);
for (int i = 0; i < alts.length; i++) {
listOfAlts.addAll(inlineAlternative(alts[i]));
}
/**************************************************************************
if( !containsDoubloons(listOfAlts) )
{
//list of productions whose inlining was a success.
productionsToBeRemoved.add("P" + ResolveIds.name(prod_to_inline.getName()));
current_production.setAlts(listOfAlts);
return true;
}
return false;
/**************************************************************************/
// Etienne: Removing duplicate alternatives modifies the grammar; it could
// hide grammar ambiguities.
//
// So, I commented out the following line of code:
// listOfAlts = (LinkedList)removeAlternativeDoubloonsFromInlinedProduction(listOfAlts);
//list of productions whose inlining was a success.
productionsToBeRemoved.add("P" + ResolveIds.name(prod_to_inline.getName()));
current_production.setAlts(listOfAlts);
return true;
}
return false;
}
List removeAlternativeDoubloonsFromInlinedProduction(List inlinedAlternatives) {
AAlt[] alts = (AAlt[]) inlinedAlternatives.toArray(new AAlt[0]);
LinkedList[] theWhole = new LinkedList[alts.length];
TreeSet indexOfDoublonsAlternatives = new TreeSet();
for (int i = 0; i < alts.length; i++) {
LinkedList elems = alts[i].getElems();
AElem[] arrayOfElems = (AElem[]) elems.toArray(new AElem[0]);
LinkedList listOfElems = new TypedLinkedList(StringCast.instance);
for (int j = 0; j < arrayOfElems.length; j++) {
listOfElems.add(arrayOfElems[j].getId().getText());
}
theWhole[i] = listOfElems;
LinkedList currentList = listOfElems;
for (int k = 0; k < i; k++) {
if (currentList.equals(theWhole[k])) {
//theWhole[k] = null;
indexOfDoublonsAlternatives.add(new Integer(k));
}
}
}
{
int i = 0;
for (Iterator iter = indexOfDoublonsAlternatives.iterator(); iter.hasNext(); ) {
int index = ((Integer) iter.next()).intValue();
//System.out.println("(" + index + "," + i + ")");
inlinedAlternatives.remove(index - i++);
}
}
return inlinedAlternatives;
}
/**
* **************************************************************
* boolean containsDoubloons(List aList)
* {
* AAlt[] alts = (AAlt [])aList.toArray(new AAlt[0]);
* LinkedList[] theWhole = new LinkedList[alts.length];
* <p/>
* for(int i=0; i<alts.length; i++)
* {
* LinkedList elems = alts[i].getElems();
* AElem[] arrayOfElems = (AElem []) elems.toArray(new AElem[0]);
* LinkedList listOfElems = new TypedLinkedList(StringCast.instance);
* for(int j=0; j<arrayOfElems.length; j++)
* {
* listOfElems.add(arrayOfElems[j].getId().getText());
* }
* theWhole[i] = listOfElems;
* <p/>
* LinkedList currentList = listOfElems;
* for(int k=0; k<i; k++)
* {
* if( currentList.equals(theWhole[k]) )
* {
* return true;
* }
* }
* }
* return false;
* }
* /****************************************************************
*/
/*
* Inlining of an alternative
*
*/
public LinkedList inlineAlternative(AAlt alt) {
AElem[] elems = (AElem[]) alt.getElems().toArray(new AElem[0]);
String elem_name;
// This list contains the names of elements to inline within an alternative
// The elem name can be either a production name or name given to it by user
//LinkedList eventualProdIdOrNames = new LinkedList();
int occurenceOfProductionToInlineWithinTheAlternative = 0;
for (int i = 0; i < elems.length; i++) {
elem_name = elems[i].getId().getText();
/*
Element to inline within an alternative is added to
a list of occurrences of the production to inline
*/
if (elem_name.equals(prod_to_inline.getName()) &&
!(elems[i].getSpecifier() instanceof ATokenSpecifier)) {
occurenceOfProductionToInlineWithinTheAlternative++;
/*
if(elems[i].getElemName() != null)
{
eventualProdIdOrNames.add( elems[i].getElemName().getText() );
}
else
{
eventualProdIdOrNames.add( elems[i].getId().getText() );
}
*/
}
}
LinkedList resultingListOfAlts = new TypedLinkedList();
resultingListOfAlts.add(alt);
for (int i = 0; i < occurenceOfProductionToInlineWithinTheAlternative; i++) {
resultingListOfAlts = inline(resultingListOfAlts, i + 1);
}
return resultingListOfAlts;
}
String alt_elem_info = null;
/*
* whichOccurence is used to number an element within the alternative
*/
public LinkedList inline(LinkedList altsList, int whichOccurence) {
LinkedList resultList = new LinkedList();
AAlt[] alts = (AAlt[]) altsList.toArray(new AAlt[0]);
AAlt aParsed_alt;
Map mapOfNewTermNames;
for (int i = 0; i < alts.length; i++) {
aParsed_alt = alts[i];
for (int j = 0; j < prod_to_inline.getNbAlts(); j++) {
mapOfNewTermNames = new TypedHashMap(StringCast.instance,
StringCast.instance);
LinkedList listElems = inlineList(aParsed_alt.getElems(),
prod_to_inline.getAlternative(j).getElems(),
mapOfNewTermNames);
AAltTransform aAltTransform =
(AAltTransform) ((AAltTransform) aParsed_alt.getAltTransform()).clone();
final Map currentMap = prod_to_inline.getAlternative(j).getProdTransform_AlTransformMap();
aAltTransform.apply(new DepthFirstAdapter() {
@Override
public void caseASimpleTerm(ASimpleTerm node) {
if (node.getId().getText().equals(alt_elem_info) &&
!(node.getSpecifier() instanceof ATokenSpecifier)) {
String termTail;
if (node.getSimpleTermTail() != null) {
termTail = node.getSimpleTermTail().getText();
} else {
termTail = prod_to_inline.getName();
}
PTerm term = (PTerm) ((PTerm) currentMap.get(termTail)).clone();
if (currentMap.get(termTail) != null) {
node.replaceBy(term);
}
}
}
@Override
public void caseASimpleListTerm(final ASimpleListTerm node_) {
if (node_.getId().getText().equals(alt_elem_info) &&
!(node_.getSpecifier() instanceof ATokenSpecifier)) {
String termTail;
if (node_.getSimpleTermTail() != null) {
termTail = node_.getSimpleTermTail().getText();
} else {
termTail = prod_to_inline.getName();
}
if (currentMap.get(termTail) != null) {
PTerm term = (PTerm) currentMap.get(termTail);
if (!(currentMap.get(termTail) instanceof ANewListTerm) &&
!(currentMap.get(termTail) instanceof ASimpleListTerm)
) {
term.apply(new DepthFirstAdapter() {
@Override
public void caseANewTerm(ANewTerm node) {
node_.replaceBy(new ANewListTerm((AProdName) node.getProdName().clone(),
(TLPar) node.getLPar().clone(),
(LinkedList) cloneList(node.getParams())
)
);
}
@Override
public void caseASimpleTerm(ASimpleTerm node) {
PSpecifier specifier = null;
TId simpleTermTail = null;
if (node.getSpecifier() != null) {
specifier = (PSpecifier) node.getSpecifier().clone();
}
if (node.getSimpleTermTail() != null) {
simpleTermTail = (TId) node.getSimpleTermTail().clone();
}
node_.replaceBy(new ASimpleListTerm(specifier,
(TId) node.getId().clone(),
simpleTermTail
)
);
}
@Override
public void caseANullTerm(ANullTerm node) {
node_.replaceBy(null);
}
@Override
public void caseAListTerm(AListTerm node) {
AListTerm parent = (AListTerm) node_.parent();
LinkedList oldlistTerms = parent.getListTerms();
LinkedList newlistTerms = new LinkedList();
Object[] oldListTermsArray = (Object[]) oldlistTerms.toArray();
for (int i = 0; i < oldListTermsArray.length; i++) {
if (oldListTermsArray[i] != node_) {
if (oldListTermsArray[i] instanceof PTerm) {
newlistTerms.add(((PTerm) oldListTermsArray[i]).clone());
} else {
newlistTerms.add(((PListTerm) oldListTermsArray[i]).clone());
}
} else {
newlistTerms.addAll(cloneList(node.getListTerms()));
}
}
parent.setListTerms(newlistTerms);
}
}
);
} else {
node_.replaceBy(term);
}
}
}
}
}
);
AAltTransform tmpaAltTransform = (AAltTransform) aAltTransform.clone();
fixSimpleTermOrSimpleListTermNames(tmpaAltTransform, mapOfNewTermNames);
String newAltName;
if (aParsed_alt.getAltName() != null) {
newAltName = aParsed_alt.getAltName().getText() + "$" +
prod_to_inline.getAlternative(j).getName() + whichOccurence;
} else {
newAltName = prod_to_inline.getAlternative(j).getName() + whichOccurence;
}
resultList.add(new AAlt(new TId(newAltName),
listElems,
tmpaAltTransform)
);
}
}
return resultList;
}
public LinkedList inlineList(LinkedList oldElemsList,
AElem[] inliningProductionsElems,
Map mapOfNewTermNames) {
int position = 0;
AElem[] listElems = (AElem[]) oldElemsList.toArray(new AElem[0]);
for (int i = 0; i < listElems.length; i++) {
//We are looking for the position of the element inside the alternative.
if (listElems[i].getId().getText().equals(prod_to_inline.getName()) &&
!(listElems[i].getSpecifier() instanceof ATokenSpecifier)) {
position = i;
if (listElems[i].getElemName() != null) {
alt_elem_info = listElems[i].getElemName().getText();
} else {
alt_elem_info = listElems[i].getId().getText();
}
break;
}
}
LinkedList list = new LinkedList();
// int elemPosition = 1;
//Before the inlined element (old alternative elements)
for (int i = 0; i < position; i++) {
list.add(((AElem) oldElemsList.get(i)).clone());
}
// The inline element (new element added to the alternative)
for (int i = 0; i < inliningProductionsElems.length; i++) {
list.add(inliningProductionsElems[i].clone());
}
// After the inlined element (old alternative elements)
for (int i = position + 1; i < listElems.length; i++) {
list.add(((AElem) oldElemsList.get(i)).clone());
}
AElem[] listOfAltElems = (AElem[]) list.toArray(new AElem[0]);
for (int i = 0; i < listOfAltElems.length; i++) {
String old_name = listOfAltElems[i].getId().getText();
TId elemName = (TId) listOfAltElems[i].getElemName();
if (elemName != null) {
elemName = (TId) elemName;
old_name = elemName.getText();
}
String elemNameString = (elemName != null ? elemName.getText() : "@elem@");
elemNameString += (i + 1);
listOfAltElems[i].setElemName(new TId(elemNameString));
mapOfNewTermNames.put(old_name, elemNameString);
}
return list;
}
private void fixSimpleTermOrSimpleListTermNames(AAltTransform tmpaAltTransform,
final Map mapOldNameNewNames) {
tmpaAltTransform.apply(new DepthFirstAdapter() {
@Override
public void caseASimpleTerm(ASimpleTerm node) {
if (mapOldNameNewNames.get(node.getId().getText()) != null) {
node.setId(new TId((String) mapOldNameNewNames.get(node.getId().getText())));
}
}
@Override
public void caseASimpleListTerm(ASimpleListTerm node) {
if (mapOldNameNewNames.get(node.getId().getText()) != null) {
node.setId(new TId((String) mapOldNameNewNames.get(node.getId().getText())));
}
}
}
);
}
private List cloneList(List list) {
List clone = new LinkedList();
for (Iterator i = list.iterator(); i.hasNext(); ) {
clone.add(((Node) i.next()).clone());
}
return clone;
}
class BooleanEx {
boolean value;
BooleanEx(boolean value) {
this.value = value;
}
void setValue(boolean value) {
this.value = value;
}
boolean getValue() {
return value;
}
}
}