/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package org.sablecc.sablecc; import org.sablecc.sablecc.analysis.*; import org.sablecc.sablecc.node.*; import java.util.LinkedList; import java.util.Map; import java.util.Set; /* * Last Modification date : 23 07 2004 * fix bug : when an inlining of a production does not resolve a conflict * the associated alternatives transformation should not be transformed. * The bug was about transforming this instead. */ /* * ComputeInlining * This class takes SableCC grammar represented by the tree * and a list of production to inline within this grammar and * try to inline those productions. */ @SuppressWarnings({"rawtypes", "unchecked"}) public class ComputeInlining { //Productions implied in a conflict private Set setOfProdToBeInline; //Map of all productions in the grammar private Map productionsMap; private Start tree; public ComputeInlining(Set set , Map productionsMap, Start tree) { this.setOfProdToBeInline = set ; this.productionsMap = productionsMap; this.tree = tree; } /** * This method compute the inline of a all productions implied in a conflict * in the grammar. * It returns : * -- true if at least one production is inlined with success * -- and false otherwise. */ public boolean computeInlining() { final BooleanEx atLeastOneProductionInlined = new BooleanEx(false); String[] nameOfProds = (String[]) setOfProdToBeInline.toArray(new String[0]); for (int i = 0; i < nameOfProds.length; i++) { if (nameOfProds[i].equals("Start")) { continue; } final AProd prod = (AProd) productionsMap.get(nameOfProds[i]); //We proceed inlining only if the production to inline is not recursive //and if it doesn't have more than SableCC.inliningMaxAlts alternatives. if (prod.getAlts().size() <= SableCC.inliningMaxAlts && !isProductionRecursive(prod)) { //This class construct a special data types for the production to inline. final In_Production in_production = new In_Production((AProd) prod.clone()); tree.apply(new DepthFirstAdapter() { @Override public void caseAProd(AProd node) { //We do not inline the production itself. if (node.getId().getText().equals(prod.getId().getText())) { return; } Inlining inliningClass = new Inlining(node, in_production); //The proper inlining is done here(method inlineProduction) if (inliningClass.inlineProduction() && !atLeastOneProductionInlined.getValue()) { atLeastOneProductionInlined.setValue(true); } } } ); } } LinkedList listOfGrammarProds = ((AProductions) ((AGrammar) tree.getPGrammar()).getProductions()).getProds(); //Once the production is inlined, we do not need it anymore, so we remove it from the grammar. String[] inlinedProductionsToRemove = (String[]) Inlining.productionsToBeRemoved.toArray(new String[0]); for (int i = 0; i < inlinedProductionsToRemove.length; i++) { listOfGrammarProds.remove(productionsMap.get(inlinedProductionsToRemove[i])); } Inlining.productionsToBeRemoved.clear(); return atLeastOneProductionInlined.getValue(); } /* * A production is recursive if one of its alternatives contains an occurrence * of itself. */ public boolean isProductionRecursive(final AProd production) { final BooleanEx recursive = new BooleanEx(false); final String currentProdName = production.getId().getText(); production.apply(new DepthFirstAdapter() { @Override public void caseAProd(AProd node) { Object temp[] = node.getAlts().toArray(); for (int i = 0; i < temp.length; i++) { ((PAlt) temp[i]).apply(this); } } @Override public void caseAAlt(AAlt node) { Object temp[] = node.getElems().toArray(); for (int i = 0; i < temp.length; i++) { ((PElem) temp[i]).apply(this); } } @Override public void caseAElem(AElem node) { if (node.getId().getText().equals(currentProdName)) { if (node.getSpecifier() != null && node.getSpecifier() instanceof ATokenSpecifier) { return; } recursive.setValue(true); } } } ); return recursive.getValue(); } /* This class is used to simulate final Boolean. * Since final variable cannot be assigned value more than * one time, we need another class which boolean value field * can be changed so often as necessary. */ class BooleanEx { boolean value; BooleanEx(boolean value) { this.value = value; } void setValue(boolean value) { this.value = value; } boolean getValue() { return value; } } }