//============================================================================== // // Copyright (c) 2002- // Authors: // * Dave Parker (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 // //============================================================================== options { LOOKAHEAD = 1; } PARSER_BEGIN(PTAParser) package pta.parser; import java.io.*; import java.util.*; import pta.*; import prism.PrismLangException; public class PTAParser { //----------------------------------------------------------------------------------- // Main method for testing purposes //----------------------------------------------------------------------------------- public static void main(String[] args) { PTAParser p = null; InputStream str = null; String src = null; try { p = new PTAParser(); str = (args.length > 0) ? new FileInputStream(args[0]) : System.in; src = (args.length > 0) ? "file "+args[0] : "stdin"; System.out.println("Reading from "+src+"...\n"); PTA pta = p.parsePTA(str); System.out.print(pta); } catch (PrismLangException e) { System.out.println("Error in "+src+": " + e.getMessage()+"."); System.exit(1); } catch (FileNotFoundException e) { System.out.println(e); System.exit(1); } } //----------------------------------------------------------------------------------- // Methods called by Prism //----------------------------------------------------------------------------------- // Constructor public PTAParser() { // Call default constructor this(System.in); } // Parse PTA public PTA parsePTA(InputStream str) throws PrismLangException { astPTA pta = null; // (Re)start parser ReInit(str); // Parse try { pta = PTA(); } catch (ParseException e) { throw new PrismLangException(e.getMessage()); } return pta.createDataStructures(); } //------------------------------------------------------------------------------ // Abstract syntax tree classes //------------------------------------------------------------------------------ // Classes used to build AST representing PTA. // Note: locations are indexed by name here, not integer as in the normal PTA class // (this is the main reason for needing separate AST classes here). // For clocks, this approach is not needed: we just take the ordering of the clocks // to be as they appear in the file (unlike locations, which have an explicit ordering // combined with possible forward references). static class astPTA { // Data public ArrayList clockNames; public ArrayList locationNames; public HashMap> invariants; public HashMap> transitions; // Methods public astPTA() { clockNames = new ArrayList(); locationNames = new ArrayList(); invariants = new HashMap>(); transitions = new HashMap>(); } public int getOrAddClock(String name) { int i = clockNames.indexOf(name); if (i == -1) { clockNames.add(name); return clockNames.size(); } else return i+1; } public void addLocation(String name) { locationNames.add(name); invariants.put(name, new LinkedHashSet()); transitions.put(name, new ArrayList()); } public void addInvariantCondition(String locName, Constraint c) { invariants.get(locName).add(c); } public void setInvariantConditions(String locName, LinkedHashSet cs) { invariants.put(locName, cs); } public astTransition addTransition(String locName) { astTransition t = new astTransition(); transitions.get(locName).add(t); return t; } public int getLocationIndex(String name) { return locationNames.indexOf(name); } // Conversion to pta classes public PTA createDataStructures() { int i, n; String name; PTA pta; Transition trans; LinkedHashSet alphabet = new LinkedHashSet(); // Find alphabet n = locationNames.size(); for (i = 0; i < n; i++) { ArrayList tt = transitions.get(locationNames.get(i)); if (tt == null || tt.isEmpty()) continue; for (astTransition t : tt) { if (t.action != null && !t.action.equals("")) { alphabet.add(t.action); } } } // Create new PTA pta = new PTA(new ArrayList (alphabet)); // Add all clocks n = clockNames.size(); for (i = 0; i < n; i++) pta.addClock(clockNames.get(i)); // Add all locations n = locationNames.size(); for (i = 0; i < n; i++) pta.addLocation(locationNames.get(i)); // Add invariants/transitions to locations n = locationNames.size(); for (i = 0; i < n; i++) { name = locationNames.get(i); pta.setInvariantConditions(i, invariants.get(name)); ArrayList tt = transitions.get(name); if (tt == null || tt.isEmpty()) continue; for (astTransition t : tt) { if (!(t.edges.isEmpty())) { trans = pta.addTransition(i, t.action); t.createDataStructures(this, trans); } } } return pta; } } static class astTransition { // Data private String action = null; private ArrayList guard; public ArrayList edges; // Methods public astTransition() { guard = new ArrayList(); edges = new ArrayList(); } public void setAction(String action) { this.action = action; } public void addGuardConstraint(Constraint c) { guard.add(c); } public astEdge addEdge(double prob, String dest) { astEdge e = new astEdge(prob, dest); edges.add(e); return e; } // Conversion to pta classes public void createDataStructures(astPTA pta, Transition trans) { for (Constraint c : guard) trans.addGuardConstraint(c); for (astEdge e : edges) e.createDataStructures(pta, trans); } } static class astEdge { // Data public double prob; public String dest; public HashMap resets; // Methods public astEdge(double prob, String dest) { this.prob = prob; this.dest = dest; resets = new HashMap(); } public void addReset(int clock, int val) { resets.put(clock, val); } // Conversion to pta classes public void createDataStructures(astPTA pta, Transition trans) { int d = pta.getLocationIndex(dest); if (d == -1) { System.err.println("Error: Location \""+dest+"\" does not exist"); System.exit(1); } Edge edge = trans.addEdge(prob, d); for (Map.Entry e : resets.entrySet()) edge.addReset(e.getKey(), e.getValue()); } } } //----------------------------------------------------------------------------------- PARSER_END(PTAParser) // Skip (but store) all other white space SPECIAL_TOKEN : { } // Skip (but store) comments SPECIAL_TOKEN : { } // Tokens TOKEN : { // Keywords < INIT: "init" > | < NODE: "node" > | < NULL: "null" > | < TRAN: "tran" > | < TRUE: "true" > // Punctuation, etc. | < NOT: "!" > | < AND: "&" > | < OR: "|" > | < IMPLIES: "=>" > | < RARROW: "->" > | < COLON: ":" > | < SEMICOLON: ";" > | < COMMA: "," > | < DOTS: ".." > | < LPARENTH: "(" > | < RPARENTH: ")" > | < LBRACKET: "[" > | < RBRACKET: "]" > | < LBRACE: "{" > | < RBRACE: "}" > | < EQ: "=" > | < NE: "!=" > | < LT: "<" > | < GT: ">" > | < LE: "<=" > | < GE: ">=" > | < PLUS: "+" > | < MINUS: "-" > | < TIMES: "*" > | < DIVIDE: "/" > | < PRIME: "'" > | < RENAME: "<-" > | < QMARK: "?" > | < DQUOTE: "\"" > // Regular expressions | < REG_INT: (["1"-"9"](["0"-"9"])*)|("0") > | < REG_DOUBLE: (["0"-"9"])*(".")?(["0"-"9"])+(["e","E"](["-","+"])?(["0"-"9"])+)? > | < REG_IDENTPRIME: ["_","a"-"z","A"-"Z"](["_","a"-"z","A"-"Z","0"-"9"])*"'" > | < REG_IDENT: ["_","a"-"z","A"-"Z"](["_","a"-"z","A"-"Z","0"-"9"])* > // Special catch-all token for lexical errors // (this allows us to throw our usual exceptions in this case) | < LEXICAL_ERROR: ~[] > } //----------------------------------------------------------------------------------- // Top-level production //----------------------------------------------------------------------------------- // PTA astPTA PTA() : { astPTA pta = new astPTA(); } { ( (Location(pta))* ) { return pta; } } void Location(astPTA pta) : { String name; LinkedHashSet constrs; } { ()? name=Identifier() { pta.addLocation(name); } constrs=ConstraintList(pta) { pta.setInvariantConditions(name, constrs); } (Transition(pta, name))* (|) } void Transition(astPTA pta, String locName) : { astTransition tr; } { { tr = pta.addTransition(locName); } (Edge(pta, tr))* } void Edge(astPTA pta, astTransition tr) : { LinkedHashSet constrs; String action = null, dest; double p; astEdge edge; HashMap resets; } { (action=Identifier() )? dest=Identifier() constrs=ConstraintList(pta) resets=Resets(pta) p=Probability() { tr.setAction(action); edge = tr.addEdge(p, dest); for (Map.Entry e : resets.entrySet()) edge.addReset(e.getKey(), e.getValue()); for (Constraint c : constrs) tr.addGuardConstraint(c); } } LinkedHashSet ConstraintList(astPTA pta) : { LinkedHashSet constrs = new LinkedHashSet(); } { ((Constraint(pta, constrs) ( Constraint(pta, constrs) )* ) | ()) { return constrs; } } void Constraint(astPTA pta, LinkedHashSet constrs) : { String clock1Name, clock2Name; int clock1, clock2, val; Token t; } { (clock1Name=Identifier() (t=|t=|t=|t=|t=) (val=Integer() { clock1 = pta.getOrAddClock(clock1Name); switch (t.kind) { case PTAParserConstants.LT: constrs.add(Constraint.buildLt(clock1, val)); break; case PTAParserConstants.LE: constrs.add(Constraint.buildLeq(clock1, val)); break; case PTAParserConstants.GT: constrs.add(Constraint.buildGt(clock1, val)); break; case PTAParserConstants.GE: constrs.add(Constraint.buildGeq(clock1, val)); break; case PTAParserConstants.EQ: constrs.add(Constraint.buildLeq(clock1, val)); constrs.add(Constraint.buildGeq(clock1, val)); break; } } | clock2Name=Identifier() { clock1 = pta.getOrAddClock(clock1Name); clock2 = pta.getOrAddClock(clock2Name); switch (t.kind) { case PTAParserConstants.LT: constrs.add(Constraint.buildLt(clock1, clock2)); break; default: System.err.println("Error: Unsupported constraint type"); System.exit(1); } } )) } HashMap Resets(astPTA pta) : { HashMap resets = new HashMap(); } { ((Reset(pta, resets) ( Reset(pta, resets))*) | ()) { return resets; } } void Reset(astPTA pta, HashMap resets) : { String clockName; int clock; int val; } { (clockName=Identifier() val=Integer()) { clock = pta.getOrAddClock(clockName); resets.put(clock, val); } } double Probability() : { Token t; double d; } { (t= | t=) { return Double.parseDouble(t.image); } } //----------------------------------------------------------------------------------- // Miscellaneous stuff //----------------------------------------------------------------------------------- // Identifier (returns String) String Identifier() : { } { { return getToken(0).image; } } // Integer int Integer() : { } { { return Integer.parseInt(getToken(0).image); } } //------------------------------------------------------------------------------