Browse Source

Check for cyclic dependencies in property references.

git-svn-id: https://www.prismmodelchecker.org/svn/prism/prism/trunk@4501 bbc10eb1-c90d-0410-af57-cb519fbb1720
master
Dave Parker 15 years ago
parent
commit
fd968a89d1
  1. 11
      prism/src/parser/ast/ASTElement.java
  2. 303
      prism/src/parser/ast/PropertiesFile.java
  3. 53
      prism/src/parser/visitor/GetAllProps.java

11
prism/src/parser/ast/ASTElement.java

@ -357,6 +357,17 @@ public abstract class ASTElement
return (ASTElement) accept(visitor); return (ASTElement) accept(visitor);
} }
/**
* Get all references to properties (by name) (i.e. ExpressionProp objects), store names in set.
*/
public Vector<String> getAllProps() throws PrismLangException
{
Vector<String> v = new Vector<String>();
GetAllProps visitor = new GetAllProps(v);
accept(visitor);
return v;
}
/** /**
* Find all references to action labels, check they exist and, if required, * Find all references to action labels, check they exist and, if required,
* store their index locally (as defined by the containing ModuleFile). * store their index locally (as defined by the containing ModuleFile).

303
prism/src/parser/ast/PropertiesFile.java

@ -38,22 +38,22 @@ public class PropertiesFile extends ASTElement
{ {
// Associated ModulesFile (for constants, ...) // Associated ModulesFile (for constants, ...)
private ModulesFile modulesFile; private ModulesFile modulesFile;
// Components // Components
private FormulaList formulaList; private FormulaList formulaList;
private LabelList labelList; private LabelList labelList;
private LabelList combinedLabelList; // Labels from both model/here private LabelList combinedLabelList; // Labels from both model/here
private ConstantList constantList; private ConstantList constantList;
private Vector<Property> properties; // Properties private Vector<Property> properties; // Properties
// list of all identifiers used // list of all identifiers used
private Vector<String> allIdentsUsed; private Vector<String> allIdentsUsed;
// actual values of (some or all) constants // actual values of (some or all) constants
private Values constantValues; private Values constantValues;
// Constructor // Constructor
public PropertiesFile(ModulesFile mf) public PropertiesFile(ModulesFile mf)
{ {
setModulesFile(mf); setModulesFile(mf);
@ -65,32 +65,50 @@ public class PropertiesFile extends ASTElement
allIdentsUsed = new Vector<String>(); allIdentsUsed = new Vector<String>();
constantValues = null; constantValues = null;
} }
// Set methods // Set methods
/** Attach to a ModulesFile (so can access labels/constants etc.) */ /** Attach to a ModulesFile (so can access labels/constants etc.) */
public void setModulesFile(ModulesFile mf) { this.modulesFile = mf; }
public void setFormulaList(FormulaList fl) { formulaList = fl; }
public void setLabelList(LabelList ll) { labelList = ll; }
public void setConstantList(ConstantList cl) { constantList = cl; }
public void setModulesFile(ModulesFile mf)
{
this.modulesFile = mf;
}
public void setFormulaList(FormulaList fl)
{
formulaList = fl;
}
public void setLabelList(LabelList ll)
{
labelList = ll;
}
public void setConstantList(ConstantList cl)
{
constantList = cl;
}
public void addProperty(Property prop) public void addProperty(Property prop)
{ {
properties.add(prop); properties.add(prop);
} }
public void addProperty(Expression p, String c) public void addProperty(Expression p, String c)
{ {
properties.addElement(new Property(p, null, c)); properties.addElement(new Property(p, null, c));
} }
public void setPropertyObject(int i, Property prop) { properties.set(i, prop); }
public void setPropertyExpression(int i, Expression p) { properties.get(i).setExpression(p); }
public void setPropertyObject(int i, Property prop)
{
properties.set(i, prop);
}
public void setPropertyExpression(int i, Expression p)
{
properties.get(i).setExpression(p);
}
/** /**
* Insert the contents of another PropertiesFile (just a shallow copy). * Insert the contents of another PropertiesFile (just a shallow copy).
*/ */
@ -122,27 +140,54 @@ public class PropertiesFile extends ASTElement
// Need to re-tidy (some checks should be re-done, some new info created) // Need to re-tidy (some checks should be re-done, some new info created)
tidyUp(); tidyUp();
} }
// Get methods // Get methods
public FormulaList getFormulaList() { return formulaList; }
public LabelList getLabelList() { return labelList; }
public LabelList getCombinedLabelList() { return combinedLabelList; }
public ConstantList getConstantList() { return constantList; }
public int getNumProperties() { return properties.size(); }
public Property getPropertyObject(int i) { return properties.get(i); }
public Expression getProperty(int i) { return properties.get(i).getExpression(); }
public String getPropertyName(int i) { return properties.get(i).getName(); }
public String getPropertyComment(int i) { return properties.get(i).getComment(); }
public FormulaList getFormulaList()
{
return formulaList;
}
public LabelList getLabelList()
{
return labelList;
}
public LabelList getCombinedLabelList()
{
return combinedLabelList;
}
public ConstantList getConstantList()
{
return constantList;
}
public int getNumProperties()
{
return properties.size();
}
public Property getPropertyObject(int i)
{
return properties.get(i);
}
public Expression getProperty(int i)
{
return properties.get(i).getExpression();
}
public String getPropertyName(int i)
{
return properties.get(i).getName();
}
public String getPropertyComment(int i)
{
return properties.get(i).getComment();
}
/** /**
* Look up a property by name from those listed in this properties file. * Look up a property by name from those listed in this properties file.
* (Use {@link #lookUpPropertyObjectByName} to search model file too) * (Use {@link #lookUpPropertyObjectByName} to search model file too)
@ -159,7 +204,23 @@ public class PropertiesFile extends ASTElement
} }
return null; return null;
} }
/**
* Look up the index of a property by name from those listed in this properties file.
* Returns -1 if not found.
*/
public int getPropertyIndexByName(String name)
{
int i, n;
n = getNumProperties();
for (i = 0; i < n; i++) {
if (name.equals(getPropertyName(i))) {
return i;
}
}
return -1;
}
/** /**
* Look up a property by name, currently just locally like {@link #getPropertyObjectByName}. * Look up a property by name, currently just locally like {@link #getPropertyObjectByName}.
* Returns null if not found. * Returns null if not found.
@ -168,7 +229,7 @@ public class PropertiesFile extends ASTElement
{ {
return getPropertyObjectByName(name); return getPropertyObjectByName(name);
} }
/** /**
* Check if an identifier is used by this properties file * Check if an identifier is used by this properties file
* (as a formula or constant) * (as a formula or constant)
@ -179,13 +240,13 @@ public class PropertiesFile extends ASTElement
} }
// method to tidy up (called after parsing) // method to tidy up (called after parsing)
public void tidyUp() throws PrismLangException public void tidyUp() throws PrismLangException
{ {
// Clear lists that will generated by this method // Clear lists that will generated by this method
// (in case it has already been called previously). // (in case it has already been called previously).
allIdentsUsed.clear(); allIdentsUsed.clear();
// Check formula identifiers // Check formula identifiers
checkFormulaIdents(); checkFormulaIdents();
// Find all instances of formulas (i.e. locate idents which are formulas), // Find all instances of formulas (i.e. locate idents which are formulas),
@ -198,41 +259,42 @@ public class PropertiesFile extends ASTElement
formulaList.findCycles(); formulaList.findCycles();
expandFormulas(modulesFile.getFormulaList(), false); expandFormulas(modulesFile.getFormulaList(), false);
expandFormulas(formulaList, false); expandFormulas(formulaList, false);
// Check label identifiers // Check label identifiers
checkLabelIdents(); checkLabelIdents();
// Check constant identifiers // Check constant identifiers
checkConstantIdents(); checkConstantIdents();
// Find all instances of constants (i.e. locate idents which are constants). // Find all instances of constants (i.e. locate idents which are constants).
// Note: We have to look in both constant lists // Note: We have to look in both constant lists
findAllConstants(modulesFile.getConstantList()); findAllConstants(modulesFile.getConstantList());
findAllConstants(constantList); findAllConstants(constantList);
// check constants for cyclic dependencies // check constants for cyclic dependencies
constantList.findCycles(); constantList.findCycles();
// Check property names // Check property names
checkPropertyNames(); checkPropertyNames();
// Find all instances of variables (i.e. locate idents which are variables). // Find all instances of variables (i.e. locate idents which are variables).
findAllVars(modulesFile.getVarNames(), modulesFile.getVarTypes()); findAllVars(modulesFile.getVarNames(), modulesFile.getVarTypes());
// Find all instances of property refs // Find all instances of property refs
findAllProps(null, this); findAllProps(null, this);
// Check property references for cyclic dependencies
findCyclesInPropertyReferences();
// Various semantic checks // Various semantic checks
semanticCheck(modulesFile, this); semanticCheck(modulesFile, this);
// Type checking // Type checking
typeCheck(this); typeCheck(this);
// Set up some values for constants // Set up some values for constants
// (without assuming any info about undefined constants) // (without assuming any info about undefined constants)
setSomeUndefinedConstants(null); setSomeUndefinedConstants(null);
} }
// check formula identifiers // check formula identifiers
private void checkFormulaIdents() throws PrismLangException private void checkFormulaIdents() throws PrismLangException
{ {
int i, n; int i, n;
@ -244,11 +306,9 @@ public class PropertiesFile extends ASTElement
// see if ident has been used elsewhere // see if ident has been used elsewhere
if (modulesFile.isIdentUsed(s)) { if (modulesFile.isIdentUsed(s)) {
throw new PrismLangException("Identifier \"" + s + "\" already used in model file", formulaList.getFormulaNameIdent(i)); throw new PrismLangException("Identifier \"" + s + "\" already used in model file", formulaList.getFormulaNameIdent(i));
}
else if (isIdentUsed(s)) {
} else if (isIdentUsed(s)) {
throw new PrismLangException("Duplicated identifier \"" + s + "\"", formulaList.getFormulaNameIdent(i)); throw new PrismLangException("Duplicated identifier \"" + s + "\"", formulaList.getFormulaNameIdent(i));
}
else {
} else {
allIdentsUsed.add(s); allIdentsUsed.add(s);
} }
} }
@ -256,14 +316,14 @@ public class PropertiesFile extends ASTElement
// check label identifiers // check label identifiers
// also check reference to these identifiers in properties // also check reference to these identifiers in properties
private void checkLabelIdents() throws PrismLangException private void checkLabelIdents() throws PrismLangException
{ {
int i, n; int i, n;
String s; String s;
Vector<String> labelIdents; Vector<String> labelIdents;
LabelList mfLabels; LabelList mfLabels;
// get label list from model file // get label list from model file
mfLabels = modulesFile.getLabelList(); mfLabels = modulesFile.getLabelList();
// add model file labels to combined label list (cloning them just for good measure) // add model file labels to combined label list (cloning them just for good measure)
@ -294,12 +354,12 @@ public class PropertiesFile extends ASTElement
} }
// check constant identifiers // check constant identifiers
private void checkConstantIdents() throws PrismLangException private void checkConstantIdents() throws PrismLangException
{ {
int i, n; int i, n;
String s; String s;
// go thru constants // go thru constants
n = constantList.size(); n = constantList.size();
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
@ -307,11 +367,9 @@ public class PropertiesFile extends ASTElement
// see if ident has been used elsewhere // see if ident has been used elsewhere
if (modulesFile.isIdentUsed(s)) { if (modulesFile.isIdentUsed(s)) {
throw new PrismLangException("Identifier \"" + s + "\" already used in model file", constantList.getConstantNameIdent(i)); throw new PrismLangException("Identifier \"" + s + "\" already used in model file", constantList.getConstantNameIdent(i));
}
else if (isIdentUsed(s)) {
} else if (isIdentUsed(s)) {
throw new PrismLangException("Duplicated identifier \"" + s + "\"", constantList.getConstantNameIdent(i)); throw new PrismLangException("Duplicated identifier \"" + s + "\"", constantList.getConstantNameIdent(i));
}
else {
} else {
allIdentsUsed.add(s); allIdentsUsed.add(s);
} }
} }
@ -326,7 +384,7 @@ public class PropertiesFile extends ASTElement
String s; String s;
Vector<String> propNames; Vector<String> propNames;
LabelList mfLabels; LabelList mfLabels;
// get label list from model file // get label list from model file
mfLabels = modulesFile.getLabelList(); mfLabels = modulesFile.getLabelList();
// Go thru properties // Go thru properties
@ -355,6 +413,73 @@ public class PropertiesFile extends ASTElement
} }
} }
/**
* Find cyclic dependencies in property references.
*/
public void findCyclesInPropertyReferences() throws PrismLangException
{
int i, j, k, l, n, firstCycle = -1;
Vector<String> v;
boolean matrix[][];
boolean foundCycle = false;
Expression e;
// initialise boolean matrix
n = properties.size();
matrix = new boolean[n][n];
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
matrix[i][j] = false;
}
}
// determine which properties reference which other properties
// and store this info in boolean matrix
for (i = 0; i < n; i++) {
e = properties.get(i).getExpression();
v = e.getAllProps();
for (j = 0; j < v.size(); j++) {
k = getPropertyIndexByName(v.elementAt(j));
if (k != -1) {
matrix[i][k] = true;
}
}
}
// check for dependencies
// (loop a maximum of n times)
// (n = max length of possible cycle)
for (i = 0; i < n; i++) {
// see if there is a cycle yet
for (j = 0; j < n; j++) {
if (matrix[j][j]) {
foundCycle = true;
firstCycle = j;
break;
}
}
// if so, stop
if (foundCycle)
break;
// extend dependencies
for (j = 0; j < n; j++) {
for (k = 0; k < n; k++) {
if (matrix[j][k]) {
for (l = 0; l < n; l++) {
matrix[j][l] |= matrix[k][l];
}
}
}
}
}
// report dependency
if (foundCycle) {
String s = "Cyclic dependency in property references from property \"" + getPropertyName(firstCycle) + "\"";
throw new PrismLangException(s, getPropertyObject(firstCycle));
}
}
/** /**
* Get a list of all undefined constants in the properties files * Get a list of all undefined constants in the properties files
* ("const int x;" rather than "const int x = 1;") * ("const int x;" rather than "const int x = 1;")
@ -363,7 +488,7 @@ public class PropertiesFile extends ASTElement
{ {
return constantList.getUndefinedConstants(); return constantList.getUndefinedConstants();
} }
/** /**
* Get a list of undefined (properties file) constants appearing in labels of the properties file * Get a list of undefined (properties file) constants appearing in labels of the properties file
* (including those that appear in definitions of other needed constants) * (including those that appear in definitions of other needed constants)
@ -387,7 +512,7 @@ public class PropertiesFile extends ASTElement
} }
return consts; return consts;
} }
/** /**
* Get a list of undefined (properties file) constants used in a property * Get a list of undefined (properties file) constants used in a property
* (including those that appear in definitions of other needed constants and labels/properties) * (including those that appear in definitions of other needed constants and labels/properties)
@ -397,13 +522,13 @@ public class PropertiesFile extends ASTElement
{ {
return prop.getExpression().getAllUndefinedConstantsRecursively(constantList, combinedLabelList, this); return prop.getExpression().getAllUndefinedConstantsRecursively(constantList, combinedLabelList, this);
} }
/** /**
* Get a list of undefined (properties file) constants used in a list of properties * Get a list of undefined (properties file) constants used in a list of properties
* (including those that appear in definitions of other needed constants and labels/properties) * (including those that appear in definitions of other needed constants and labels/properties)
* (undefined constants are those of form "const int x;" rather than "const int x = 1;") * (undefined constants are those of form "const int x;" rather than "const int x = 1;")
*/ */
public Vector<String> getUndefinedConstantsUsedInProperties(List <Property> props)
public Vector<String> getUndefinedConstantsUsedInProperties(List<Property> props)
{ {
Vector<String> consts, tmp; Vector<String> consts, tmp;
consts = new Vector<String>(); consts = new Vector<String>();
@ -417,7 +542,7 @@ public class PropertiesFile extends ASTElement
} }
return consts; return consts;
} }
/** /**
* Set values for *all* undefined constants and then evaluate all constants. * Set values for *all* undefined constants and then evaluate all constants.
* If there are no undefined constants, {@code someValues} can be null. * If there are no undefined constants, {@code someValues} can be null.
@ -432,7 +557,7 @@ public class PropertiesFile extends ASTElement
// This will usually be done on a per-property basis later // This will usually be done on a per-property basis later
// (and sometimes we don't want to have to define all constants) // (and sometimes we don't want to have to define all constants)
} }
/** /**
* Set values for *some* undefined constants and then evaluate all constants where possible. * Set values for *some* undefined constants and then evaluate all constants where possible.
* If there are no undefined constants, {@code someValues} can be null. * If there are no undefined constants, {@code someValues} can be null.
@ -447,7 +572,7 @@ public class PropertiesFile extends ASTElement
// This will usually be done on a per-property basis later // This will usually be done on a per-property basis later
// (and sometimes we don't want to have to define all constants) // (and sometimes we don't want to have to define all constants)
} }
/** /**
* Check if {@code name} is a *defined* constant in the properties file, * Check if {@code name} is a *defined* constant in the properties file,
* i.e. a constant whose value was *not* left unspecified. * i.e. a constant whose value was *not* left unspecified.
@ -456,7 +581,7 @@ public class PropertiesFile extends ASTElement
{ {
return constantList.isDefinedConstant(name); return constantList.isDefinedConstant(name);
} }
/** /**
* Get access to the values for all constants in the properties file, including the * Get access to the values for all constants in the properties file, including the
* undefined constants set previously via the method {@link #setUndefinedConstants(Values)} * undefined constants set previously via the method {@link #setUndefinedConstants(Values)}
@ -469,7 +594,7 @@ public class PropertiesFile extends ASTElement
} }
// Methods required for ASTElement: // Methods required for ASTElement:
/** /**
* Visitor method. * Visitor method.
*/ */
@ -477,7 +602,7 @@ public class PropertiesFile extends ASTElement
{ {
return v.visit(this); return v.visit(this);
} }
/** /**
* Convert to string. * Convert to string.
*/ */
@ -485,28 +610,32 @@ public class PropertiesFile extends ASTElement
{ {
String s = "", tmp; String s = "", tmp;
int i, n; int i, n;
tmp = "" + formulaList; tmp = "" + formulaList;
if (tmp.length() > 0) tmp += "\n";
if (tmp.length() > 0)
tmp += "\n";
s += tmp; s += tmp;
tmp = "" + labelList; tmp = "" + labelList;
if (tmp.length() > 0) tmp += "\n";
if (tmp.length() > 0)
tmp += "\n";
s += tmp; s += tmp;
tmp = "" + constantList; tmp = "" + constantList;
if (tmp.length() > 0) tmp += "\n";
if (tmp.length() > 0)
tmp += "\n";
s += tmp; s += tmp;
n = getNumProperties(); n = getNumProperties();
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
s += getPropertyObject(i) + ";\n"; s += getPropertyObject(i) + ";\n";
if (i < n-1) s += "\n";
if (i < n - 1)
s += "\n";
} }
return s; return s;
} }
/** /**
* Perform a deep copy. * Perform a deep copy.
*/ */
@ -527,9 +656,9 @@ public class PropertiesFile extends ASTElement
ret.addProperty((Property) getPropertyObject(i).deepCopy()); ret.addProperty((Property) getPropertyObject(i).deepCopy());
} }
// Copy other (generated) info // Copy other (generated) info
ret.allIdentsUsed = (allIdentsUsed == null) ? null : (Vector<String>)allIdentsUsed.clone();
ret.allIdentsUsed = (allIdentsUsed == null) ? null : (Vector<String>) allIdentsUsed.clone();
ret.constantValues = (constantValues == null) ? null : new Values(constantValues); ret.constantValues = (constantValues == null) ? null : new Values(constantValues);
return ret; return ret;
} }
} }

53
prism/src/parser/visitor/GetAllProps.java

@ -0,0 +1,53 @@
//==============================================================================
//
// Copyright (c) 2002-
// Authors:
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford)
//
//------------------------------------------------------------------------------
//
// This file is part of PRISM.
//
// PRISM is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// PRISM is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with PRISM; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//==============================================================================
package parser.visitor;
import java.util.Vector;
import parser.ast.*;
import prism.PrismLangException;
/**
* Get all references to properties (by name) (i.e. ExpressionProp objects), store names in set.
*/
public class GetAllProps extends ASTTraverse
{
private Vector<String> v;
public GetAllProps(Vector<String> v)
{
this.v = v;
}
public void visitPost(ExpressionProp e) throws PrismLangException
{
if (!v.contains(e.getName())) {
v.addElement(e.getName());
}
}
}
Loading…
Cancel
Save