maria-1.3.5/0000755000175000017500000000000010272511516012757 5ustar msmakelamsmakelamaria-1.3.5/Automata/0000755000175000017500000000000010272511377014537 5ustar msmakelamsmakelamaria-1.3.5/Automata/Ltl/0000755000175000017500000000000010272511377015272 5ustar msmakelamsmakelamaria-1.3.5/Automata/Ltl/LtlGraph.C0000644000175000017500000000506610164633662017124 0ustar msmakelamsmakela// -*- c++ -*- /// @file LtlGraph.C /* * This file is based on code originally written by Mauno Rönkkö, * Copyright © 1998 Mauno Rönkkö . * * Modifications by Heikki Tauriainen * and Marko Mäkelä . * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "LtlGraph.h" #include /// An empty formula set static const class LtlBitVector e; LtlGraph::LtlGraph (const class Ltl& formula) : m_next (1), m_nodes () { std::stack nodes_to_expand; std::set incoming; incoming.insert (0); class LtlBitVector new_set (formula.m_num + 1); new_set.assign_true (formula.m_num); nodes_to_expand.push (new class LtlGraphNode (incoming, new_set, e, e, e)); expand_next_node: while (!nodes_to_expand.empty ()) { class LtlGraphNode& node = *nodes_to_expand.top (); if (unsigned p = node.m_new.nonzero ()) { p--; node.m_old.assign_true (p); node.m_new.assign_false (p); Ltl::fetch (p).expand (node, nodes_to_expand); continue; } nodes_to_expand.pop (); // no new propositions: merge the node with the graph // search for an existing node having the same 'old' and 'next' sets for (iterator i = m_nodes.begin (); i != m_nodes.end (); i++) { if (i->second.m_old == node.m_old && i->second.m_next == node.m_next) { // merge the node with an existing one i->second.m_incoming.insert (node.m_incoming.begin(), node.m_incoming.end()); delete &node; goto expand_next_node; } } // a genuinely new node: insert it to the graph and expand further m_nodes.insert (std::pair (m_next, node)); std::set incoming; incoming.insert (m_next++); nodes_to_expand.push (new class LtlGraphNode (incoming, node.m_next, e, e, e)); delete &node; } } maria-1.3.5/Automata/Ltl/Ltl.C0000644000175000017500000001410310164633662016132 0ustar msmakelamsmakela// -*- c++ -*- /// @file Ltl.C /* * This file is based on code originally written by Mauno Rönkkö, * Copyright © 1998 Mauno Rönkkö . * * Modifications by Heikki Tauriainen * and Marko Mäkelä . * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Ltl.h" #include "LtlGraph.h" #include Ltl::Store Ltl::m_store; class Ltl& Ltl::Store::insert (class Ltl& ltl) { std::pair::iterator,bool> p = m_set.insert (<l); if (!p.second) delete <l; else { // new formula: add it to the translation table unsigned num = m_set.size (); if (!(num & (num - 1))) { const class Ltl** table = new const class Ltl*[num << 1]; memcpy (table, m_table, (num - 1) * sizeof *m_table); delete[] m_table; m_table = table; } m_table[ltl.m_num = num - 1] = <l; } return **p.first; } bool Ltl::operator< (const class Ltl& other) const { if (getKind () < other.getKind ()) return true; if (other.getKind () < getKind ()) return false; switch (getKind ()) { case Atom: return static_cast(*this) < static_cast(other); case Constant: return static_cast(*this) < static_cast(other); case Junct: return static_cast(*this) < static_cast(other); case Iff: return static_cast(*this) < static_cast(other); case Future: return static_cast(*this) < static_cast(other); case Until: return static_cast(*this) < static_cast(other); } assert (false); return false; } void LtlAtom::expand (class LtlGraphNode& node, std::stack& to_expand) const { if (!node.m_old[negClone ().m_num]) node.m_atomic.assign_true (m_num); else { to_expand.pop (); delete &node; } } void LtlConstant::expand (class LtlGraphNode& node, std::stack& to_expand) const { if (!m_true) { to_expand.pop (); delete &node; } } void LtlJunct::expand (class LtlGraphNode& node, std::stack& to_expand) const { if (m_con) { if (!node.m_old[m_left.m_num]) node.m_new.assign_true (m_left.m_num); if (!node.m_old[m_right.m_num]) node.m_new.assign_true (m_right.m_num); } else { class LtlBitVector new_set (node.m_new); if (!node.m_old[m_left.m_num]) new_set.assign_true (m_left.m_num); if (!node.m_old[m_right.m_num]) node.m_new.assign_true (m_right.m_num); to_expand.push (new class LtlGraphNode (node.m_incoming, new_set, node.m_old, node.m_atomic, node.m_next)); } } void LtlIff::expand (class LtlGraphNode& node, std::stack& to_expand) const { class LtlBitVector new_set (node.m_new); class Ltl& neg_left = m_left.negClone (); class Ltl& neg_right = m_right.negClone (); if (!node.m_old[m_left.m_num]) node.m_new.assign_true (m_left.m_num); if (!new_set[neg_left.m_num]) new_set.assign_true (neg_left.m_num); if (m_iff) { if (!node.m_old[m_right.m_num]) node.m_new.assign_true (m_right.m_num); if (!new_set[neg_right.m_num]) new_set.assign_true (neg_right.m_num); } else { if (!node.m_old[neg_right.m_num]) node.m_new.assign_true (neg_right.m_num); if (!new_set[m_right.m_num]) new_set.assign_true (m_right.m_num); } to_expand.push (new class LtlGraphNode (node.m_incoming, new_set, node.m_old, node.m_atomic, node.m_next)); } void LtlUntil::expand (class LtlGraphNode& node, std::stack& to_expand) const { if (m_release) { if (!node.m_old[m_right.m_num]) node.m_new.assign_true (m_right.m_num); class LtlBitVector new_set (node.m_new); if (!node.m_old[m_left.m_num]) node.m_new.assign_true (m_left.m_num); class LtlBitVector next_set (node.m_next); next_set.assign_true (m_num); to_expand.push (new class LtlGraphNode (node.m_incoming, new_set, node.m_old, node.m_atomic, next_set)); } else { class LtlBitVector new_set (node.m_new); if (!node.m_old[m_left.m_num]) new_set.assign_true (m_left.m_num); if (!node.m_old[m_right.m_num]) node.m_new.assign_true (m_right.m_num); class LtlBitVector next_set (node.m_next); next_set.assign_true (m_num); to_expand.push (new class LtlGraphNode (node.m_incoming, new_set, node.m_old, node.m_atomic, next_set)); } } void LtlFuture::expand (class LtlGraphNode& node, std::stack& to_expand) const { switch (m_op) { case next: node.m_next.assign_true (m_formula.m_num); return; case finally: { class LtlBitVector new_set (node.m_new); if (!node.m_old[m_formula.m_num]) new_set.assign_true (m_formula.m_num); to_expand.push (new class LtlGraphNode (node.m_incoming, new_set, node.m_old, node.m_atomic, node.m_next)); } break; case globally: if (!node.m_old[m_formula.m_num]) node.m_new.assign_true (m_formula.m_num); break; #ifndef NDEBUG default: assert (false); #endif // NDEBUG } node.m_next.assign_true (m_num); } maria-1.3.5/Automata/Ltl/Ltl.h0000644000175000017500000004201710164633662016204 0ustar msmakelamsmakela// -*- c++ -*- /// @file Ltl.h /* * This file is based on code originally written by Mauno Rönkkö, * Copyright © 1998 Mauno Rönkkö . * * Modifications by Heikki Tauriainen * and Marko Mäkelä . * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef Ltl_h_ # define Ltl_h_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # ifdef DEBUG # include # endif // DEBUG # include # include /** Abstract base class for LTL formulae */ class Ltl { public: /// LTL formula comparator struct ltless { /// Lexicographic order of LTL formulae /// @param l1 pointer to first formula to compare /// @param l2 pointer to second formula to compare /// @return true if l1 is before l2 bool operator() (const class Ltl* l1, const class Ltl* l2) const { return *l1 < *l2; } }; private: /// Set of instantiated LTL formulae class Store { private: /// Set of LTL formulae std::set m_set; /// Table of LTL formulae, indexed by Ltl::m_num const class Ltl** m_table; /// Copy constructor Store (const class Store&); /// Assignment operator class Store& operator= (const class Store&); public: /// Constructor Store () : m_set (), m_table (0) {} /// Destructor ~Store () { clear (); } /// Clean up the set void clear () { delete[] m_table; m_table = 0; for (std::set::iterator i = m_set.begin (); i != m_set.end (); i++) { delete *i; } m_set.clear (); } /// Insert a formula to the set class Ltl& insert (class Ltl& ltl); /// Translate a formula index to a formula reference /// @param f formula index to be translated /// @return the corresponding formula const class Ltl& fetch (unsigned f) const { return *m_table[f]; } }; static class Store m_store; friend class Store; public: /// Number of the LTL formula unsigned m_num; /// Constructor Ltl () : m_num (0) {} private: /// Copy constructor Ltl (const class Ltl& old); /// Assignment operator class Ltl& operator= (const class Ltl& old); protected: /// Destructor virtual ~Ltl () {} /// Reference registrator /// @param ltl formula to be registered /// @return an equivalent formula static class Ltl& insert (class Ltl& ltl) { return m_store.insert (ltl); } public: /// Clean up the formulae static void clear () { m_store.clear (); } /// Translate a formula index to a formula reference /// @param f formula index to be translated /// @return the corresponding formula static const class Ltl& fetch (unsigned f) { return m_store.fetch (f); } /// Returns a clone of the negation of this Ltl formula. virtual class Ltl& negClone () const = 0; /// Formula kinds enum Kind { Atom, Constant, Junct, Iff, Future, Until }; /// Determine the kind of the formula virtual enum Kind getKind () const = 0; /// Less-than comparison bool operator< (const class Ltl& other) const; /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded virtual void expand (class LtlGraphNode& node, std::stack& to_expand) const = 0; # ifdef DEBUG /// Stream output virtual void display (FILE* out) const = 0; # endif // DEBUG }; /** LTL atom */ class LtlAtom : public Ltl { private: /// The proposition number unsigned m_value; /// Flag: is the proposition negated? bool m_negated; public: /// Constructor /// @param value proposition number /// @param negated flag: is the proposition negated? /// @return an LTL atom static class Ltl& construct (unsigned value, bool negated) { return insert (*new class LtlAtom (value, negated)); } /// Returns a clone of the negation of this Ltl formula. class Ltl& negClone () const { return insert (*new class LtlAtom (m_value, !m_negated)); } private: /// Constructor LtlAtom (unsigned value, bool negated = false) : Ltl (), m_value (value), m_negated (negated) {} /// Copy constructor LtlAtom (const class LtlAtom& old); /// Assignment operator class LtlAtom& operator= (const class LtlAtom& old); protected: /// Destructor ~LtlAtom () {} public: /// Determine the kind of the formula enum Kind getKind () const { return Atom; } /// Less-than comparison bool operator< (const class LtlAtom& other) const { return m_value < other.m_value || (m_value == other.m_value && m_negated < other.m_negated); } /// Determine whether the atom is negated bool isNegated () const { return m_negated; } /// Determine the value of the proposition unsigned getValue () const { return m_value; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { if (m_negated) fputs ("! ", out); fprintf (out, "p%u", m_value); } # endif // DEBUG }; /** LTL constants 'true' and 'false' */ class LtlConstant : public Ltl { private: /// The truth value of the constant bool m_true; public: /// Constructor /// @param true_ the constant 'true' or 'false' /// @return an LTL constant static class Ltl& construct (bool true_) { return insert (*new class LtlConstant (true_)); } /// Returns a clone of the negation of this Ltl formula. class Ltl& negClone () const { return insert (*new class LtlConstant (!m_true)); } private: /// Constructor LtlConstant (bool true_) : Ltl (), m_true (true_) {} /// Copy constructor LtlConstant (const class LtlConstant& old); /// Assignment operator class LtlConstant& operator= (const class LtlConstant& old); protected: /// Destructor ~LtlConstant () {} public: /// Determine the kind of the formula enum Kind getKind () const { return Constant; } /// Less-than comparison bool operator< (const class LtlConstant& other) const { return m_true < other.m_true; } /// Convert to truth value operator bool () const { return m_true; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { putc (m_true ? 't' : 'f', out); } # endif // DEBUG }; /** LTL conjunction and disjunction */ class LtlJunct : public Ltl { private: /// Flag: conjunction instead of disjunction? bool m_con; /// The left-hand-side sub-formula class Ltl& m_left; /// The right-hand-side sub-formula class Ltl& m_right; public: /// Optimizing constructor /// @param con flag: conjunction instead of disjunction /// @param l the left-hand-side formula /// @param r the right-hand-side formula /// @return an equivalent formula static class Ltl& construct (bool con, class Ltl& l, class Ltl& r) { if (l.getKind () == Ltl::Constant) return bool (static_cast(l)) == con ? r : l; if (r.getKind () == Ltl::Constant) return bool (static_cast(r)) == con ? l : r; if (&l == &r) return l; return &l < &r ? insert (*new class LtlJunct (con, l, r)) : insert (*new class LtlJunct (con, r, l)); } /// Returns a clone of the negation of this Ltl formula. class Ltl& negClone () const { return insert (*new class LtlJunct (!m_con, m_left.negClone (), m_right.negClone ())); } private: /// Constructor /// @param con flag: conjunction instead of disjunction /// @param l the left-hand-side formula /// @param r the right-hand-side formula LtlJunct (bool con, class Ltl& l, class Ltl& r) : m_con (con), m_left (l), m_right (r) {} /// Copy constructor LtlJunct (const class LtlJunct& old); /// Assignment operator class LtlJunct& operator= (const class LtlJunct& old); protected: /// Destructor ~LtlJunct () {} public: /// Determine the kind of the formula enum Kind getKind () const { return Junct; } /// Less-than comparison bool operator< (const class LtlJunct& other) const { if (m_con < other.m_con) return true; if (other.m_con < m_con) return false; if (&m_left < &other.m_left) return true; if (&other.m_left < &m_left) return false; return &m_right < &other.m_right; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { fputs (m_con ? "& " : "| ", out); m_left.display (out); putc (' ', out); m_right.display (out); } # endif // DEBUG }; /** LTL equivalence or exclusive disjunction */ class LtlIff : public Ltl { private: /// Flag: equivalence instead of exclusive disjunction? bool m_iff; /// The left-hand-side sub-formula class Ltl& m_left; /// The right-hand-side sub-formula class Ltl& m_right; public: /// Optimizing constructor /// @param iff flag: equivalence instead of exclusive disjunction /// @param l the left-hand-side formula /// @param r the right-hand-side formula /// @return an equivalent formula static class Ltl& construct (bool iff, class Ltl& l, class Ltl& r) { if (l.getKind () == Ltl::Constant) return bool (static_cast(l)) == iff ? r : r.negClone (); if (r.getKind () == Ltl::Constant) return bool (static_cast(r)) == iff ? l : l.negClone (); if (&l == &r) return LtlConstant::construct (iff); return &l < &r ? insert (*new class LtlIff (iff, l, r)) : insert (*new class LtlIff (iff, r, l)); } /// Returns a clone of the negation of this Ltl formula. class Ltl& negClone () const { return insert (*new class LtlIff (!m_iff, m_left, m_right)); } private: /// Constructor /// @param iff flag: equivalence instead of exclusive disjunction /// @param l the left-hand-side formula /// @param r the right-hand-side formula LtlIff (bool iff, class Ltl& l, class Ltl& r) : m_iff (iff), m_left (l), m_right (r) {} /// Copy constructor LtlIff (const class LtlIff& old); /// Assignment operator class LtlIff& operator= (const class LtlIff& old); protected: /// Destructor ~LtlIff () {} public: /// Determine the kind of the formula enum Kind getKind () const {return Iff; } /// Less-than comparison bool operator< (const class LtlIff& other) const { if (m_iff < other.m_iff) return true; if (other.m_iff < m_iff) return false; if (&m_left < &other.m_left) return true; if (&other.m_left < &m_left) return false; return &m_right < &other.m_right; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { fputs (m_iff ? "e " : "^ ", out); m_left.display (out); putc (' ', out); m_right.display (out); } # endif // DEBUG }; /** LTL next-time, globally and finally formulae */ class LtlFuture : public Ltl { public: /// Operator kinds enum Op { next, globally, finally }; private: /// The operator enum Op m_op; /// The formula being quantified class Ltl& m_formula; public: /// Constructor /// @param op the operator /// @param f the formula /// @return an LTL future formula static class Ltl& construct (enum Op op, class Ltl& f) { return insert (*new class LtlFuture (op, f)); } /// Returns a clone of the negation of this formula. class Ltl& negClone () const { switch (m_op) { case next: break; case globally: return insert (*new class LtlFuture (finally, m_formula.negClone ())); case finally: return insert (*new class LtlFuture (globally, m_formula.negClone ())); } return insert (*new class LtlFuture (m_op, m_formula.negClone ())); } private: /// Constructor /// @param op the operator /// @param f the formula /// @param r the right-hand-side formula LtlFuture (enum Op op, class Ltl& f) : m_op (op), m_formula (f) {} /// Copy constructor LtlFuture (const class LtlFuture& old); /// Assignment operator class LtlFuture& operator= (const class LtlFuture& old); protected: /// Destructor ~LtlFuture () {} public: /// Determine the kind of the formula enum Kind getKind () const { return Future; } /// Less-than comparison bool operator< (const class LtlFuture& other) const { if (m_op < other.m_op) return true; if (other.m_op < m_op) return false; return &m_formula < &other.m_formula; } /// Get the temporal operator enum Op getOp () const { return m_op; } /// Get the subformula const class Ltl& getFormula () const { return m_formula; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { switch (m_op) { case next: putc ('X', out); break; case globally: putc ('G', out); break; case finally: putc ('F', out); break; } putc (' ', out); m_formula.display (out); } # endif // DEBUG }; /** LTL 'until' and 'release' operators */ class LtlUntil : public Ltl { private: /// Flag: release instead of until bool m_release; /// The left-hand-side sub-formula class Ltl& m_left; /// The right-hand-side sub-formula class Ltl& m_right; public: /// Constructor /// @param release flag: 'release' instead of 'until' /// @param l the left-hand-side formula /// @param r the right-hand-side formula /// @return an LTL formula static class Ltl& construct (bool release, class Ltl& l, class Ltl& r) { return insert (*new class LtlUntil (release, l, r)); } private: /// Constructor /// @param release flag: 'release' instead of 'until' /// @param l the left-hand-side formula /// @param r the right-hand-side formula LtlUntil (bool release, class Ltl& l, class Ltl& r) : m_release (release), m_left (l), m_right (r) {} /// Copy constructor LtlUntil (const class LtlUntil& old); /// Assignment operator class LtlUntil& operator= (const class LtlUntil& old); public: /// Destructor ~LtlUntil () {} /// Returns a clone of the negation of this Ltl formula. class Ltl& negClone () const { return insert (*new class LtlUntil (!m_release, m_left.negClone (), m_right.negClone ())); } /// Determine the kind of the formula enum Kind getKind () const { return Until; } /// Less-than comparison bool operator< (const class LtlUntil& other) const { if (m_release < other.m_release) return true; if (other.m_release < m_release) return false; if (&m_left < &other.m_left) return true; if (&other.m_left < &m_left) return false; return &m_right < &other.m_right; } /// Determine whether this is a release operator instead of until bool isRelease () const { return m_release; } /// Get the left-hand-side subformula const class Ltl& getLeft () const { return m_left; } /// Get the right-hand-side subformula const class Ltl& getRight () const { return m_right; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { fputs (m_release ? "V " : "U ", out); m_left.display (out); putc (' ', out); m_right.display (out); } # endif // DEBUG }; #endif // Ltl_h_ maria-1.3.5/Automata/Ltl/LtlBitVector.C0000644000175000017500000000017607570454016017762 0ustar msmakelamsmakela// -*- c++ -*- /// @file LtlBitVector.C #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "LtlBitVector.h" maria-1.3.5/Automata/Ltl/LtlBitVector.h0000644000175000017500000001272307570454016020030 0ustar msmakelamsmakela// -*- c++ -*- /// @file LtlBitVector.h /* * Copyright © 2001 Marko Mäkelä * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef LTLBITVECTOR_H_ # define LTLBITVECTOR_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include /** Binary digit (bit) vector */ class LtlBitVector { public: /** machine word */ typedef unsigned long word_t; /** Constructor * @param size number of elements in the vector */ explicit LtlBitVector (unsigned size = 0) : m_size (0), m_allocated (1), m_bits (new word_t[1]) { *m_bits = 0; setSize (size); } /** Copy constructor */ explicit LtlBitVector (const class LtlBitVector& old) : m_size (old.m_size), m_allocated (old.m_allocated), m_bits (0) { memcpy (m_bits = new word_t[m_allocated], old.m_bits, m_allocated * sizeof (word_t)); } private: /** Assignment operator */ class LtlBitVector& operator= (const class LtlBitVector& old); public: /** Destructor */ ~LtlBitVector () { delete[] m_bits; } /** Equality comparison * @param other other bit vector to compare this against * @return true if the bit vectors are identical, * treating missing bits as unset */ bool operator== (const class LtlBitVector& other) const { unsigned tsize = getNumWords (m_size), osize = getNumWords (other.m_size); if (tsize < osize) { if (memcmp (m_bits, other.m_bits, tsize * sizeof (word_t))) return false; for (register const word_t* bits = other.m_bits + osize; bits-- > other.m_bits + tsize; ) if (*bits) return false; } else { if (memcmp (m_bits, other.m_bits, osize * sizeof (word_t))) return false; for (register const word_t* bits = m_bits + tsize; bits-- > m_bits + osize; ) if (*bits) return false; } return true; } /** Determine the number of words the specified amount of bits occupy */ static unsigned getNumWords (unsigned bits) { const unsigned bitsPerWord = CHAR_BIT * sizeof (word_t); return (bits + bitsPerWord - 1) / bitsPerWord; } /** Set the size of the vector * @param size the new size of the vector */ void setSize (unsigned size) { const unsigned numWords = getNumWords (size); if (m_allocated < numWords) { while (m_allocated < numWords) m_allocated <<= 1; word_t* bits = new word_t[m_allocated]; const unsigned init = getNumWords (m_size); memcpy (bits, m_bits, init * sizeof *m_bits); memset (bits + init, 0, (m_allocated - init) * sizeof *m_bits); delete[] m_bits; m_bits = bits; } m_size = size; } /** Determine the size of the vector * @return the size of the vector */ unsigned getSize () const { return m_size; } /** Read a binary digit * @param i zero-based index of the element * @return value of the ternary digit */ bool operator[] (unsigned i) const { return i < m_size && m_bits[i / (CHAR_BIT * sizeof (word_t))] & (word_t (1) << (i % (CHAR_BIT * sizeof (word_t)))); } /** Set a binary digit * @param i zero-based index of the element */ void assign_true (unsigned i) { if (i >= m_size) setSize (i + 1); m_bits[i / (CHAR_BIT * sizeof (word_t))] |= word_t (1) << (i % (CHAR_BIT * sizeof (word_t))); } /** Clear a binary digit * @param i zero-based index of the element */ void assign_false (unsigned i) { m_bits[i / (CHAR_BIT * sizeof (word_t))] &= ~(word_t (1) << (i % (CHAR_BIT * sizeof (word_t)))); } /** Determine whether the whole vector is filled with zero bits * @return 0 if all bits in the vector are clear; * index of a nonzero entry + 1 otherwise */ unsigned nonzero () const { if (!m_size) return 0; return findNext (0); } /** Find the next index at which there is a set bit * @param i the starting index (counting forward) * @return 0 if all following bits in the vector are clear; * index of the next nonzero entry + 1 otherwise */ unsigned findNext (unsigned i) const { if (i >= m_size) return 0; register const word_t* w = &m_bits[i / (CHAR_BIT * sizeof (word_t))]; register word_t bit = 1 << (i % (CHAR_BIT * sizeof (word_t))); if (*w >= bit) { // found in the same word do if (*w & bit) return i + 1; while (i++, bit <<= 1); } const word_t* const w_end = m_bits + getNumWords (m_size); // search in the remaining words while (++w < w_end) { if (!*w) continue; for (i = 1, bit = 1; !(*w & bit); bit <<= 1, i++); return i + (w - m_bits) * CHAR_BIT * sizeof (word_t); } return 0; } private: /** Number of elements in the vector */ unsigned m_size; /** Size of the allocated vector in words */ unsigned m_allocated; /** The vector */ word_t* m_bits; }; #endif // LTLBITVECTOR_H_ maria-1.3.5/Automata/Ltl/LtlGraph.h0000644000175000017500000000756110164633662017173 0ustar msmakelamsmakela// -*- c++ -*- /// @file LtlGraph.h /* * This file is based on code originally written by Mauno Rönkkö, * Copyright © 1998 Mauno Rönkkö . * * Modifications by Heikki Tauriainen * and Marko Mäkelä . * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef LtlGraph_h_ # define LtlGraph_h_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Ltl.h" # include "LtlBitVector.h" # include /** * A node in a graph representing an LTL formula. * * The graph itself is a set of nodes of this kind. * The LtlGraphNode class is merely a front end for the set representation. */ class LtlGraphNode { public: /// From which nodes can one come to this node. std::set m_incoming; /// A set of formulae to be processed. class LtlBitVector m_new; /// A set of formulae that must hold, when this node is entered. class LtlBitVector m_old; /// A set of atomic propositions that must hold, when this node is entered. class LtlBitVector m_atomic; /// A set of formulae that must hold in immediate next nodes. class LtlBitVector m_next; /// Default constructor LtlGraphNode () : m_incoming (), m_new (), m_old (), m_atomic (), m_next () {} /// Constructs a specific node. LtlGraphNode (const std::set& incoming, const class LtlBitVector& neww, const class LtlBitVector& old, const class LtlBitVector& atomic, const class LtlBitVector& next) : m_incoming (incoming), m_new (neww), m_old (old), m_atomic (atomic), m_next (next) {} /// Copy constructor LtlGraphNode (const class LtlGraphNode& node) : m_incoming (node.m_incoming), m_new (node.m_new), m_old (node.m_old), m_atomic (node.m_atomic), m_next (node.m_next) {} private: /// Assignment operator class LtlGraphNode& operator= (const class LtlGraphNode& node); public: /// Destructor ~LtlGraphNode () {} }; /** * Graph representation of a generalized Büchi automaton * corresponding to an LTL formula * * A LtlGraph is automatically constructed from a given * Ltl formula. All relevant information is fully stored to the * graph, so that the formula itself may well be destoyed right after * the conversion. The Ltl operators/operands provide themselves * the knowledge of how to be expanded into a LtlGraph. */ class LtlGraph { public: /*@{*/ /// Map from state numbers to graph nodes typedef std::map Map; /// Iterator to the map typedef Map::iterator iterator; /// Constant iterator to the map typedef Map::const_iterator const_iterator; /*@}*/ private: /// Next available state number unsigned m_next; /// Map from state numbers to graph nodes (0=initial state) std::map m_nodes; private: /// Copy constructor LtlGraph (const class LtlGraph& old); /// Assignment operator class LtlGraph& operator= (const class LtlGraph& other); public: /// Constructs a graph from a given LTL formula. LtlGraph (const class Ltl& formula); /// Destructor ~LtlGraph () {} /** @name Accessors to the graph nodes */ /*@{*/ const_iterator begin () const { return m_nodes.begin (); } const_iterator end () const { return m_nodes.end (); } /*@}*/ }; #endif // LtlGraph_h_ maria-1.3.5/Automata/Ltl/README0000644000175000017500000000032310164633662016152 0ustar msmakelamsmakelaThe files in this directory have been adapted by Marko Mäkelä from lbt-1.2.2. They are necessary for the BUILTIN_LTL option that avoids the error-prone inter-process communication on Microsoft Windows systems. maria-1.3.5/Automata/BitVector.C0000644000175000017500000000206407643247642016557 0ustar msmakelamsmakela// Binary digit (bit) vector -*- c++ -*- /** @file BitVector.C * Bit vector */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BitVector.h" maria-1.3.5/Automata/BitVector.h0000644000175000017500000001475407643247642016635 0ustar msmakelamsmakela// Binary digit (bit) vector -*- c++ -*- #ifndef BITVECTOR_H_ # define BITVECTOR_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include # include /** @file BitVector.h * Bit vector */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Binary digit (bit) vector */ class BitVector { public: /** machine word */ typedef unsigned word_t; /** Constructor * @param size number of elements in the vector */ explicit BitVector (unsigned size = 0) : mySize (0), myAllocated (1), myBits (new word_t[1]) { *myBits = 0; setSize (size); } /** Copy constructor */ explicit BitVector (const class BitVector& old) : mySize (old.mySize), myAllocated (getNumWords (old.mySize)), myBits (0) { memcpy (myBits = new word_t[myAllocated], old.myBits, myAllocated * sizeof (word_t)); } private: /** Assignment operator */ class BitVector& operator= (const class BitVector& old); public: /** Destructor */ ~BitVector () { delete[] myBits; } /** Determine the number of words the specified amount of bits occupy */ static unsigned getNumWords (unsigned bits) { const unsigned bitsPerWord = CHAR_BIT * sizeof (word_t); return (bits + bitsPerWord - 1) / bitsPerWord; } /** Clear the vector */ void clear () { memset (myBits, 0, myAllocated * sizeof *myBits); } /** Truncate the vector * @param size number of elements to leave in the vector */ void truncate (unsigned size = 0) { if (mySize <= size) return; mySize = size; const unsigned init = getNumWords (size); if (const unsigned rest = size % (CHAR_BIT * sizeof (word_t))) assert (init >= 1), myBits[init - 1] &= (1u << rest) - 1; memset (myBits, 0, (myAllocated - init) * sizeof *myBits); } /** Set the size of the vector */ void setSize (unsigned size) { const unsigned numWords = getNumWords (size); if (myAllocated < numWords) { while (myAllocated < numWords) myAllocated <<= 1; word_t* bits = new word_t[myAllocated]; const unsigned init = getNumWords (mySize); memcpy (bits, myBits, init * sizeof *myBits); memset (bits + init, 0, (myAllocated - init) * sizeof *myBits); delete[] myBits; myBits = bits; } mySize = size; } /** Determine the size of the vector */ unsigned getSize () const { return mySize; } /** Read a binary digit * @param i zero-based index of the element * @return value of the ternary digit */ bool operator[] (unsigned i) const { assert (i < mySize); return myBits[i / (CHAR_BIT * sizeof (word_t))] & (1u << (i % (CHAR_BIT * sizeof (word_t)))); } /** Assign a binary digit * @param i zero-based index of the element * @param b new value of the digit */ void assign (unsigned i, bool b) { assert (i < mySize); word_t& word = myBits[i / (CHAR_BIT * sizeof (word_t))]; word_t bit = 1u << (i % (CHAR_BIT * sizeof (word_t))); if (b) word |= bit; else word &= ~bit; } /** Test and set: read and set a binary digit * @param i zero-based index of the element * @return whether the element already was set */ bool tset (unsigned i) { assert (i < mySize); word_t& word = myBits[i / (CHAR_BIT * sizeof (word_t))]; word_t bit = 1u << (i % (CHAR_BIT * sizeof (word_t))); if (word & bit) return true; word |= bit; return false; } /** Test and reset: read and reset a binary digit * @param i zero-based index of the element * @return whether the element already was set */ bool treset (unsigned i) { assert (i < mySize); word_t& word = myBits[i / (CHAR_BIT * sizeof (word_t))]; word_t bit = 1u << (i % (CHAR_BIT * sizeof (word_t))); if (!(word & bit)) return false; word &= ~bit; return true; } /** Assign a binary digit, extending the vector with zeros if required * @param i zero-based index of the element * @param b new value of the digit */ void extend (unsigned i, bool b) { if (i >= mySize) setSize (i + 1); assign (i, b); } /** Determine whether the whole vector is filled with zero bits */ bool allClear () const { unsigned i = mySize / (CHAR_BIT * sizeof (word_t)); if (mySize && (myBits[i] & ((1u << (mySize % (CHAR_BIT * sizeof (word_t)))) - 1))) return false; while (i--) if (myBits[i]) return false; return true; } /** Determine whether the whole vector is filled with zero bits */ bool allSet () const { unsigned i = mySize / (CHAR_BIT * sizeof (word_t)); if (mySize && ~(myBits[i] | ~((1u << (mySize % (CHAR_BIT * sizeof (word_t)))) - 1))) return false; while (i--) if (~myBits[i]) return false; return true; } /** Compute bit wise disjunction with the complement of a bit vector * @param other bit vector whose complement is to be ORed with this */ void orNot (const class BitVector& other) { assert (mySize == other.mySize); for (unsigned i = getNumWords (mySize); i--; ) myBits[i] |= ~other.myBits[i]; } /** Compute bit wise conjunction with the complement of a bit vector * @param other bit vector whose complement is to be ANDed with this * @return true if any bits were left '1' after the operation */ bool andNot (const class BitVector& other) { assert (mySize == other.mySize); bool someset = false; for (unsigned i = getNumWords (mySize); i--; ) if (myBits[i] &= ~other.myBits[i]) someset = true; return someset; } private: /** Number of elements in the vector */ unsigned mySize; /** Size of the allocated vector in words */ unsigned myAllocated; /** The vector */ word_t* myBits; }; #endif // BITVECTOR_H_ maria-1.3.5/Automata/Product.C0000644000175000017500000012633210232531511016256 0ustar msmakelamsmakela// Product automaton -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Product.h" #include "Property.h" #include "GlobalMarking.h" #include "Valuation.h" #include "Net.h" #include "Graph.h" #include "GraphReporter.h" #include "Printer.h" #include "Transition.h" #include "SetList.h" #include /** @file Product.C * Product of reachability graph and the negation of property being verified */ /* Copyright © 1999-2003,2005 Marko Mäkelä (msmakela@tcs.hut.fi). Copyright © 1999-2001 Timo Latvala (timo@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Product automaton state */ class State { public: /** Default constructor */ State (): rg (0), prop (0) {} /** Constructor * @param rg_ number of the reachability graph state * @param prop_ number of the property automaton state */ State (card_t rg_, unsigned prop_) : rg (rg_), prop (prop_) {} /** Copy constructor */ State (const class State& old) : rg (old.rg), prop (old.prop) {} /** Assignment operator */ class State& operator= (const class State& old) { rg = old.rg, prop = old.prop; return *this; } /** Destructor */ ~State () {} /** Equality comparison */ bool operator== (const class State& other) const { return rg == other.rg && prop == other.prop; } /** Less-than comparison */ bool operator< (const class State& other) const { return rg < other.rg || (rg == other.rg && prop < other.prop); } /** Get the hash value */ size_t operator() () const; /** Reachability graph state number */ card_t rg; /** Property automaton state number */ unsigned prop; }; /** Tarjan state */ class Tarjan { public: /** Default constructor */ Tarjan () : state (), depth (0), numSucc (0) {} /** Constructor * @param state_ product automaton state * @param depth_ search depth * @param numSucc_ number of enabled gates */ Tarjan (const class State& state_, unsigned depth_, unsigned numSucc_) : state (state_), depth (depth_), numSucc (numSucc_) {} /** Copy constructor */ Tarjan (const class Tarjan& old) : state (old.state), depth (old.depth), numSucc (old.numSucc) {} /** Assignment operator */ class Tarjan& operator= (const class Tarjan& old) { state = old.state, depth = old.depth, numSucc = old.numSucc; return *this; } /** Destructor */ ~Tarjan () {} /** product automaton state */ class State state; /** search depth */ unsigned depth; /** number of enabled gates */ unsigned numSucc; }; /** Stack of states of the strongly connected component algorithm */ typedef std::list TarjanStack; /** Stack of product automaton states */ typedef std::list StateStack; /** Map of product automaton states to nonzero search depths */ typedef std::map StateMap; /** Look up the search depth associated with a product state * @param visited map of visited states * @param s a visited state * @return the search depth associated with the state */ inline static unsigned lookup (const StateMap& visited, const State& s) { StateMap::const_iterator i = visited.find (s); assert (i != visited.end ()); return i->second; } /** Look up the search depth associated with a product state * @param visited map of visited states * @param s a visited state * @return the search depth associated with the state, or 0 */ inline static unsigned lookup_maybe (const StateMap& visited, const class State& s) { StateMap::const_iterator i = visited.find (s); return i == visited.end () ? 0 : i->second; } /** Look up the search depth associated with a product state and clear it * @param visited map of visited states * @param s a visited state * @param init the new value * @return the search depth associated with the state */ inline static unsigned lookup_clear (StateMap& visited, const State& s, unsigned init = 0) { StateMap::iterator i = visited.find (s); assert (i != visited.end () && i->second); unsigned d = i->second; i->second = init; return d; } /** Offsets to the temporary files */ struct offsets { /** current offset to the automaton file */ unsigned aut; /** current offset to the reachability graph file */ unsigned rg; }; /** The temporary files */ struct files { /** product automaton directory: map from search depth numbers to offsets */ FILE* directory; /** successor state numbers in the property automaton */ FILE* aut_succ; /** successor state numbers in the reachability graph */ FILE* rg_succ; /** offsets in the files */ struct offsets offset; }; /** Open temporary files * @param f (output) the temporary files * @return true if everything succeeded */ inline static bool openFiles (struct files& f) { if (!(f.directory = tmpfile ())); else if (!(f.aut_succ = tmpfile ())) fclose (f.directory), f.directory = 0; else if (!(f.rg_succ = tmpfile ())) fclose (f.directory), fclose (f.aut_succ), f.directory = f.aut_succ = 0; else { f.offset.aut = f.offset.rg = 0; return true; } perror ("tmpfile"); return false; } /** Close temporary files * @param f the temporary files */ inline static void closeFiles (struct files& f) { fclose (f.directory); fclose (f.aut_succ); fclose (f.rg_succ); } /** Write the successors to the temporary files * @param f the temporary files * @param aut property automaton successor states (aut[1..*aut]) * @param rgsize number of reachability graph successor states * @param rgbegin begin iterator for reachability graph successor states * @param rgend end iterator for reachability graph successor states */ inline static bool writeArcs (struct files& f, const unsigned* aut, size_t rgsize, const SearchList::const_iterator& rgbegin, const SearchList::const_iterator& rgend) { assert (f.offset.aut == ftell (f.aut_succ) / sizeof (unsigned)); assert (f.offset.rg == ftell (f.rg_succ) / sizeof (unsigned)); if (1 != fwrite (&f.offset, sizeof f.offset, 1, f.directory) || *aut + 1 != fwrite (aut, sizeof *aut, *aut + 1, f.aut_succ)) return false; unsigned s = rgsize; if (1 != fwrite (&s, sizeof s, 1, f.rg_succ)) return false; for (SearchList::const_iterator i = rgbegin; i != rgend; i++) { s = *i; if (1 != fwrite (&s, sizeof s, 1, f.rg_succ)) return false; } f.offset.aut += *aut + 1; f.offset.rg += rgsize + 1; return true; } /** Fetch the offsets for the arc files * @param f the files * @param depth dfs number for the source state * @param ofs (output) offsets to the arcs of source state */ inline static void fetchOffsets (const struct files& f, unsigned depth, struct offsets& ofs) { if (fseek (f.directory, (depth - 1) * sizeof f.offset, SEEK_SET)) { perror ("Product: fseek (directory)"); assert (false); } else if (1 != fread (&ofs, sizeof ofs, 1, f.directory)) { perror ("Product: fread (directory)"); assert (false); } } /** A strongly connected component for Streett emptiness check */ struct components { /** number of temporary states */ unsigned numTemp; /** the Streett transition relation */ class SetList* trans; /** the L sets */ class SetList* l; /** the U sets */ class SetList* u; /** the component states (comp[1..*comp]) */ unsigned* comp; }; /** Read the arcs of a product state * @param rg state numbers in the reachability graph * @param prop state numbers in the property automaton * @param prod state numbers in the product automaton * @param f pointer to the arc files */ static void freadArc (unsigned*& rg, unsigned*& prop, unsigned*& prod, struct files& f) { if ((1 != fread (&rg[1], sizeof *rg, 1, f.rg_succ)) || (1 != fread (&prop[1], sizeof *prop, 1, f.aut_succ))) assert (false); if (rg[1] > *rg) { register unsigned u = rg[1]; delete[] rg; rg = new unsigned[u + 2]; *rg = rg[1] = u; } if (prop[1] > *prop) { register unsigned u = prop[1]; delete[] prop; prop = new unsigned[u + 2]; *prop = prop[1] = u; } register unsigned u = prop[1] * rg[1]; if (u > *prod) { delete[] prod; prod = new unsigned[u + 1]; *prod = u; } if (rg[1] != fread (rg + 2, sizeof *rg, rg[1], f.rg_succ) || prop[1] != fread (prop + 2, sizeof *prop, prop[1], f.aut_succ)) { perror ("decodeArc():fread"); assert (false); } } /** Decode the arcs of one product state * @param visited statemap for checking in component * @param trans the transition relation (output param) * @param minDepth minimum value for being in the component * @param maxDepth maximum value for being in the component * @param parent index of the parent state * @param rg state numbers in the reachability graph * @param prop state numbers in the property automaton * @param prod state numbers in the product automaton * @param f pointer to the arc files */ static void decodeArc (const StateMap& visited, class SetList& trans, unsigned minDepth, unsigned maxDepth, unsigned parent, unsigned*& rg, unsigned*& prop, unsigned*& prod, struct files& f) { struct offsets ofs; fetchOffsets (f, maxDepth - parent, ofs); fseek (f.rg_succ, ofs.rg * sizeof *rg, SEEK_SET); fseek (f.aut_succ, ofs.aut * sizeof *prop, SEEK_SET); freadArc (rg, prop, prod, f); // compute the product: number of items, plus 1 unsigned u = 1; //because of dfs num recycling all dfs nums in one component are contiguous //therefore we can use the dfs number to check if a state is in the component for (unsigned i = rg[1]; i--; ) { for (unsigned j = prop[1]; j--; ) { register unsigned p = lookup (visited, State (rg[i + 2], prop[j + 2])); //if the edge leads out of the component, don't add it if (p < minDepth || p > maxDepth) continue; prod[u++] = maxDepth - p; // adjust the index } } if (unsigned v = --u) { u = *prod, *prod = v; trans.copy (parent, prod); *prod = u; } } /** Decode the arcs of one product state, not translating product state indices * @param visited statemap for checking in component * @param trans the transition relation (output param) * @param maxDepth maximum value for being in the component * @param parent index of the parent state * @param rg state numbers in the reachability graph * @param prop state numbers in the property automaton * @param prod state numbers in the product automaton * @param f pointer to the arc files */ static void decodeProductArc (const StateMap& visited, class SetList& trans, unsigned maxDepth, unsigned parent, unsigned*& rg, unsigned*& prop, unsigned*& prod, struct files& f) { struct offsets ofs; fetchOffsets (f, parent, ofs); fseek (f.rg_succ, ofs.rg * sizeof *rg, SEEK_SET); fseek (f.aut_succ, ofs.aut * sizeof *prop, SEEK_SET); freadArc (rg, prop, prod, f); // compute the product: number of items, plus 1 unsigned u = 1; //because of dfs num recycling all dfs nums in one component are contiguous //therefore we can use the dfs number to check if a state is in the component for (unsigned i = rg[1]; i--; ) { for (unsigned j = prop[1]; j--; ) { register unsigned p = lookup_maybe (visited, State (rg[i + 2], prop[j + 2])); if (!p || p > maxDepth) continue; prod[u++] = maxDepth - p; } } if (unsigned v = --u) { u = *prod, *prod = v; trans.copy (parent, prod); *prod = u; } } /** Add intermediate states connected to a given source state; * update the transition relation and fairness set information * @param prodSucc place holder for the successors * @param visited the statemap * @param c the component for the Streett check * @param ci index to the Streett transition relation * @param fair the accepting successors of the property automaton * @param prop the successor states in the property automaton * @param minDepth the minimum dfs num for being in the component * @param maxDepth the maximum dfs num for being in the component * @param rgSucc the successor in the reachability graph */ inline static void memberships (unsigned* prodSucc, const StateMap& visited, struct components& c, unsigned ci, const unsigned* fair, const unsigned* prop, unsigned minDepth, unsigned maxDepth, unsigned rgSucc) { unsigned cnt = 1, i; // check those successor product states that are in the component for (i = *prop; i; ) { prodSucc[cnt] = ::lookup_maybe (visited, State (rgSucc, prop[i--])); if (prodSucc[cnt] >= minDepth && prodSucc[cnt] <= maxDepth) prodSucc[cnt] = maxDepth - prodSucc[cnt], cnt++; // adjust the index } // we only make intermediate state for arcs // for the successors of this transition instance if ((*prodSucc = --cnt)) { unsigned oldCnt = c.trans->getNumSets (); for (i = cnt, cnt = 0; i; i--) { unsigned s = prodSucc[i]; for (unsigned j = c.trans->getSize (ci); j--; ) { if ((*c.trans)[ci][j] != s) continue; (*c.trans)[ci][j] = oldCnt + cnt; c.trans->grow (oldCnt + cnt + 1); unsigned buffer[2] = {1, s}; c.trans->copy (oldCnt + cnt, buffer); c.numTemp++; cnt++; break; } } assert (cnt == *prodSucc); //fix set memberships of the intermediate state c.u->grow (oldCnt + cnt); while (cnt--) c.u->copy (oldCnt + cnt, fair); } } /** Recover the arcs from the temporary files * @param f the temporary files * @param visited map of visited states * @param states the states in the strongly connected component * @param reporter the reachability graph interface * @param property the property automaton * @param minDepth minimum value for being in the component * @param maxDepth maximum value for being in the component * @param c (output) the component for the Streett check */ static void readArcs (struct files& f, StateMap& visited, StateStack& states, class GraphReporter& reporter, const class Property& property, unsigned minDepth, unsigned maxDepth, struct components& c) { unsigned size = maxDepth - minDepth + 1; c.numTemp = 0; c.trans = new class SetList (size); c.l = new class SetList (size); c.u = new class SetList (size); c.comp = 0; // assign the L-sets from the system and the property unsigned i, j, *t; for (i = size; i--; ) { j = property.getNumSets () + reporter.net.getNumWeaklyFair (); for (*(t = new unsigned[j + 1]) = j; j; j--) t[j] = j - 1; c.l->assign (i, t); } /** placeholder for reachability graph successors */ unsigned* rg = new unsigned[2]; *rg = 0; /** placeholder for property automaton successors */ unsigned* prop = new unsigned[2]; *prop = 0; /** placeholder for product automaton successors */ unsigned* prod = new unsigned[1]; *prod = 0; StateStack::const_iterator psi = states.begin (); for (unsigned s = 0; s < size; s++) { assert (psi != states.end ()); const class State& ps = *psi++; // assign the U-sets from the property for (j = 0, i = property.getNumSets (); i--; ) if (property.accepts (ps.prop, i)) j++; if (j) { *(t = new unsigned[j + 1]) = j; for (i = property.getNumSets (); i--; ) if (property.accepts (ps.prop, i)) t[j--] = i; c.u->assign (s, t); } // get the successors in the reachability graph /** Encoded transition instances */ word_t* data; /** Interface for decoding the transition instances */ class BitUnpacker* u; /** Successors in the reachability graph */ card_t* rgSucc = reporter.prepareFair (ps.rg, data, u); // no successors: go to next state if (!rgSucc) continue; // read the transition relation decodeArc (visited, *c.trans, minDepth, maxDepth, s, rg, prop, prod, f); // assign the L- and U-sets from the system class BitVector stateWeak (reporter.net.getNumWeaklyFair ()); /** successors within component */ unsigned* prodSucc = new unsigned[prop[1] + 1]; *prodSucc = 0; for (i = 1; i <= *rgSucc; i++) { /** enabled strong fairness sets */ unsigned* sfair; /** enabled weak fairness sets */ unsigned* wfair = reporter.computeFair (ps.rg, u, &sfair); if (!wfair) break; /** current number of states in the component */ const unsigned oldCnt = size + c.numTemp; if (*wfair) { for (j = *wfair; j; j--) wfair[j] += property.getNumSets (); memberships (prodSucc, visited, c, s, wfair, prop + 1, minDepth, maxDepth, rgSucc[i]); for (j = *wfair; j; j--) stateWeak.assign (wfair[j] - property.getNumSets (), true); } if (*sfair) { for (j = *sfair; j; j--) sfair[j] += property.getNumSets () + reporter.net.getNumWeaklyFair (); // assign the memberships for the intermediate states if (*wfair) for (j = *prodSucc; j--; ) c.u->copy (oldCnt + j, sfair); else memberships (prodSucc, visited, c, s, sfair, prop + 1, minDepth, maxDepth, rgSucc[i]); c.l->copy (s, sfair); } //allocate space for sets of intermediate states if (oldCnt < size + c.numTemp) c.l->grow (size + c.numTemp); } delete u; delete[] data; delete[] prodSucc; delete[] rgSucc; c.u->assign (s, stateWeak, property.getNumSets (), true); } delete[] rg; delete[] prop; delete[] prod; } /** Check whether a strongly connected component of the product automaton * fulfills the generalized Buchi acceptance conditions * @param prop the property automaton * @param states states of the product automaton * @param selfLoops bit vector of self loop states * @param visited map from states to bit vector indices * @param numStates number of states to process, minus 1 * @return true if the acceptance condition is fulfilled */ static bool checkBuchi (const class Property& prop, const StateStack& states, const class BitVector& selfLoops, const StateMap& visited, unsigned numStates) { /** number of acceptance sets */ const unsigned numSets = prop.getNumSets (); assert (numStates < states.size ()); if (!numStates) { /** product automaton state */ const class State& state = states.front (); /** property automaton state number */ const unsigned ps = state.prop; unsigned d = ::lookup (visited, state); for (unsigned s = numSets; s--; ) if (!prop.accepts (ps, s)) return false; return selfLoops[d]; } else { /** Acceptance sets that are visited */ class BitVector visitedSets (prop.getNumSets ()); StateStack::const_iterator si = states.begin (); for (unsigned i = numStates + 1; i--; ) { /** product automaton state */ const class State& state = *si++; /** property automaton state number */ const unsigned ps = state.prop; assert (visited.find (state) != visited.end ()); for (unsigned s = numSets; s--; ) if (prop.accepts (ps, s)) visitedSets.assign (s, true); } return visitedSets.allSet (); } } /** Check whether weak fairness holds in a strongly connected component * @param reporter the reachability graph interface * @param prop the property automaton * @param states the successor states in the product automaton * @param visited map from states to bit vector indices * @param minDepth minimum Tarjan depth in the component * @param maxDepth maximum Tarjan depth in the component * @return true if the fairness constraints hold */ static bool checkWeaklyFair (class GraphReporter& reporter, const class Property& prop, const StateStack& states, const StateMap& visited, unsigned minDepth, unsigned maxDepth) { const unsigned numWeak = reporter.net.getNumWeaklyFair (); if (!numWeak) return true; /** States for which a fair transition is enabled */ class BitVector stateWeak (numWeak); /** Looping states for which a fair transition is enabled */ class BitVector staticWeak (numWeak); unsigned numStates = maxDepth - minDepth + 1; for (StateStack::const_iterator si = states.begin (); numStates--; si++) { assert (si != states.end ()); const class State& state = *si; const class PropertyState& propState = prop[state.prop]; /** Encoded transition instances */ word_t* data; /** Interface for decoding the transition instances */ class BitUnpacker* u; /** Successors in the reachability graph */ card_t* rgSucc = reporter.prepareFair (state.rg, data, u); if (!rgSucc) continue; for (card_t s = 1; s <= *rgSucc; s++) { unsigned* wf = reporter.computeFair (state.rg, u, 0); if (!wf) { delete u; delete[] data; delete[] rgSucc; return false; } unsigned nWeak = *wf; for (const card_t rgState = rgSucc[s]; nWeak; nWeak--) { const unsigned weak = wf[nWeak]; stateWeak.assign (weak, true); for (unsigned i = propState.getNumSuccessors (); i--; ) { unsigned d = ::lookup_maybe (visited, State (rgState, propState[i])); if (d >= minDepth && d <= maxDepth) { staticWeak.assign (weak, true); break; } } } } staticWeak.orNot (stateWeak); stateWeak.clear (); delete u; delete[] data; delete[] rgSucc; } return staticWeak.allSet (); } /** Remove all bad states from the component * @param c the component * @param l (working area) the L set (and the Bad set) * @param u (working area) the U set * @param removed (output) bit vector of removed states * @return true if any states were removed */ inline static bool removeBad (struct components& c, class BitVector& l, class BitVector& u, class BitVector& removed) { unsigned i, j; bool status = false; for (;;) { l.clear (); u.clear (); for (i = *c.comp; i; i--) { const unsigned node = c.comp[i]; // compute L for (j = c.l->getSize (node); j--; ) l.assign ((*c.l)[node][j], true); // compute U for (j = c.u->getSize (node); j--; ) u.assign ((*c.u)[node][j], true); } if (!l.andNot (u)) return status; status = true; for (i = *c.comp; i; i--) { const unsigned node = c.comp[i]; // compute L for (j = c.l->getSize (node); j--; ) if (l[(*c.l)[node][j]]) goto remove; continue; remove: removed.assign (node, true); c.comp[i] = c.comp[(*c.comp)--]; } } } /** Tarjan state */ struct tarjan { /** reachability graph state */ card_t state; /** number of unprocessed successors */ unsigned numSucc; }; /** Flag: has the analysis been interrupted? */ extern volatile bool interrupted; /** Compute the MSCCs of a component * @param c the transition relation and the component * @param compStore place holder for new MSCCs * @param removed bit vector of removed states * @param visited (working area) visited states * @param modified (working area) processed states * @param compNums (working area) component numbers */ static void computeMSCC (const struct components& c, std::list& compStore, const class BitVector& removed, class BitVector& visited, class BitVector& processed, unsigned* compNums) { /** Current and allocated length of the component stack */ unsigned cstsize = 0, cstalloc = 128; /** Component stack */ card_t* cst = new card_t[cstalloc]; std::list st; // Combinations for visited[state] and processed[state]: // initially 0 0 // visited in the search 1 0 // visited; depth adjusted 0 1 // processed component 1 1 visited.clear (); processed.clear (); /** Search depth */ unsigned depth = 1; for (unsigned k = *c.comp; !interrupted && k; k--) { card_t state = c.comp[k]; unsigned compNr = compNums[state + 1]; while (!interrupted) { // compute a strongly connected component while (!interrupted) { if (processed[state] || visited.tset (state)) break; // push the state on the component stack if (cstsize == cstalloc) { if (card_t* ncst = new card_t[cstalloc <<= 1]) { memcpy (ncst, cst, cstsize * sizeof *cst); delete[] cst; cst = ncst; } else { delete[] cst; interrupted = true; return; } } cst[cstsize++] = state; compNums[state + 1] = depth++; // determine the successors of the state struct tarjan t = { state, c.trans->getSize (state) }; for (; t.numSucc; t.numSucc--) { unsigned s = (*c.trans)[state][t.numSucc - 1]; if (visited[s] == processed[s] && (compNums[s + 1] != compNr || removed[s])) c.trans->delElement (state, t.numSucc - 1); else if (!processed[s] || !visited[s]) { state = s; break; } } st.push_front (t); } // backtrack while (!interrupted) { if (st.empty ()) goto compDone; /** Minimum search depth in the state */ const card_t minDepth = processed[state] && visited[state] ? CARD_T_MAX : compNums[state + 1]; struct tarjan& t = st.front (); state = t.state; if (compNums[state + 1] > minDepth) { compNums[state + 1] = minDepth; if (processed.tset (state)) assert (!visited[state]); else assert (visited[state]), visited.assign (state, false); } if (t.numSucc-- > 1) { assert (c.trans->getSize (state) > t.numSucc); for (; t.numSucc; t.numSucc--) { card_t s = (*c.trans)[state][t.numSucc - 1]; if (visited[s] == processed[s] && (compNums[s + 1] != compNr || removed[s])) c.trans->delElement (state, t.numSucc - 1); else if (!(processed[s] && visited[s])) { state = s; break; } } if (t.numSucc) break; } st.pop_front (); if (processed[state]) continue; // split the component (*compNums)++; unsigned i; for (i = cstsize;; ) { card_t s = cst[--i]; assert (processed[s] != visited[s]); processed.assign (s, true); visited.assign (s, true); compNums[s + 1] = *compNums; if (s == state) break; assert (i > 0); } card_t* comp = new card_t[cstsize - i + 1]; *comp = cstsize - i; memcpy (comp + 1, cst + i, (cstsize - i) * sizeof *comp); cstsize = i; compStore.push_back (comp); } } compDone: continue; } delete[] cst; } /** Check whether the strong fairness constraints hold * @param c the transition relation and fairness sets * @param selfLoops bitvector indicating states with arcs to themselves * @param size maximum size of the L and U sets * @param maxDepth maximum Tarjan depth in the component * @return component root, or UINT_MAX if no counterexample */ inline static unsigned checkStreett (struct components& c, const class BitVector& selfLoops, unsigned size, unsigned maxDepth) { class BitVector l (size); class BitVector u (size); unsigned ssize = c.trans->getNumSets (); class BitVector removed (ssize); /** Component numbers for Tarjan's algorithm * (index 0 = highest component number) */ unsigned* compNums = reinterpret_cast(calloc (ssize + 1, sizeof *compNums)); if (!compNums) return UINT_MAX; unsigned i; /** Strongly connected component */ c.comp = new unsigned[ssize + 1]; for (i = ssize - c.numTemp; i; i--) c.comp[i] = ssize - c.numTemp - i; for (i = ssize - c.numTemp; i < ssize; i++) c.comp[i + 1] = i; *c.comp = ssize; for (std::list compStore;;) { if (removeBad (c, l, u, removed) && *c.comp) { l.setSize (ssize), u.setSize (ssize); computeMSCC (c, compStore, removed, l, u, compNums); l.setSize (size), u.setSize (size); } else if (*c.comp && (*c.comp > 1 || (c.comp[1] < ssize - c.numTemp && selfLoops[maxDepth - c.comp[1]]))) { // ensure that the component root is not an intermediate state for (i = *c.comp; c.comp[i] >= ssize - c.numTemp; i--) assert (i > 0); // there must be a non-intermediate state in c.comp i = c.comp[i]; while (!compStore.empty ()) { delete[] compStore.front (); compStore.pop_front (); } free (compNums); return i; } delete[] c.comp; if (compStore.empty ()) { c.comp = 0; break; } c.comp = compStore.front (); compStore.pop_front (); } free (compNums); return UINT_MAX; } /** Append the traversed path to the counterexample path * @param state the tail state of the path * @param unmatchedL number of encountered unmatched L sets * @param c the component and the fairness sets * @param l encountered L sets * @param u encountered U sets * @param father map from visited states to their ancestors * @return the new counterexample path (product automaton states) */ static card_t* lockPath (unsigned state, unsigned& unmatchedL, const struct components& c, class BitVector& l, class BitVector& u, unsigned* father, card_t* witness) { unsigned size = c.trans->getNumSets (), i; /** path being constructed */ std::list path; do { assert (state < size); if (state < size - c.numTemp) // intermediate state? path.push_front (state); // no, add to witness path for (i = c.u->getSize (state); i--; ) { unsigned s = (*c.u)[state][i]; if (!u.tset (s) && l[s]) unmatchedL--; } unsigned t = state; state = father[state]; // climb up the path father[t] = UINT_MAX; // reset the ancestor relation } while (state != UINT_MAX && (!*witness || state != witness[*witness])); memset (father, 0xff, (size - c.numTemp) * sizeof *father); // append the constructed path to the witness path i = path.size (); card_t* w = new card_t[*witness + i + 1]; *w = *witness + i; memcpy (w + 1, witness + 1, *witness * sizeof *witness); delete[] witness; witness = w; for (w += *w - i + 1; i--; path.pop_front ()) *w++ = path.front (); return witness; } /** Check whether the path can be locked * @param state the tail state of the path * @param unmatchedL number of encountered unmatched L sets * @param c the component and the fairness sets * @param l encountered L sets * @param u encountered U sets * @return true if the path can be locked */ static bool checkState (unsigned state, unsigned& unmatchedL, const struct components& c, class BitVector& l, class BitVector& u) { /** flag: can the path be locked? */ bool lock = false; unsigned i, s; for (i = c.l->getSize (state); i--; ) { s = (*c.l)[state][i]; if (!l.tset (s)) { lock = true; if (!u[s]) unmatchedL++; } } for (i = c.u->getSize (state); i--; ) { s = (*c.u)[state][i]; if (l[s] && !u.tset (s)) { lock = true; unmatchedL--; } } return lock; } /** Determine whether an element belongs to a set * @param e the element to be sought * @param s array representation of the set (s[1..*s]) * @return an index of s[] corresponding to e, or 0 if not found */ inline static unsigned memberIndex (card_t e, const card_t* s) { register const card_t* t = s + *s; for (register unsigned i = 1; s++ < t; i++) if (*s == e) return i; return 0; } /** Generate a counterexample path * @param c the component and the fairness sets * @param root root state of the component * @param size size of the L and U sets */ static card_t* streettWitness (const struct components& c, unsigned root, unsigned size) { /** breadth-first search queue */ std::list bfs; /** Encountered L and U sets */ class BitVector l (size), u (size); size = c.trans->getNumSets (); assert (size >= 1); /** Visited states */ class BitVector visited (size); /** Map from visited states to states through which they were entered */ unsigned* father = new unsigned[size - c.numTemp]; /** The witness path */ card_t* witness = new card_t[1]; *witness = 0; /** Number of encountered unmatched L sets */ unsigned unmatchedL = 0; // Display a message here, since the construction can take a long time extern class Printer thePrinter; thePrinter.printRaw ("constructing counterexample"); thePrinter.finish (); memset (father, 0xff, (size - c.numTemp) * sizeof *father); bfs.push_back (root); visited.assign (root, true); if (checkState (root, unmatchedL, c, l, u)) witness = lockPath (root, unmatchedL, c, l, u, father, witness); if (size == 1) { assert (witness && *witness == 1); card_t* w = new card_t[3]; *w = 2, w[1] = w[2] = witness[1]; delete[] witness; delete[] father; return w; } while (!bfs.empty ()) { unsigned s = bfs.front (); bfs.pop_front (); for (unsigned i = c.trans->getSize (s); i--; ) { /** flag: lock the path */ bool lock = false; /** successor state */ unsigned t = (*c.trans)[s][i]; // if the state is not in a good component, proceed to the next state if (c.comp && !memberIndex (t, c.comp)) { (*c.trans).delElement (s, i); continue; } if (t >= size - c.numTemp) { // intermediate state assert (*witness); if ((lock = checkState (t, unmatchedL, c, l, u)) && s != witness[*witness]) witness = lockPath (s, unmatchedL, c, l, u, father, witness); t = (*c.trans)[t][0]; // skip to next state assert (t < size - c.numTemp); } if (father[t] == UINT_MAX) father[t] = s; if (t == root && !unmatchedL) { witness = lockPath (t, unmatchedL, c, l, u, father, witness); delete[] father; return witness; } else if (checkState (t, unmatchedL, c, l, u) || lock) { bfs.clear (); visited.clear (); if (!*witness || t != witness[*witness] || lock) witness = lockPath (t, unmatchedL, c, l, u, father, witness); visited.assign (t, true); bfs.push_back (t); break; } else if (!visited.tset (t)) bfs.push_back (t); } } delete[] father; delete[] witness; assert (false); return 0; } /** Compute a path leading to the counterexample loop * @param visited map of visited states * @param maxDepth maximum Tarjan depth in the component * @param witness array containing the loop of the witness * @param f the arc relation files */ static void computePrefix (StateMap& visited, unsigned maxDepth, card_t *&witness, struct files& f) { assert (witness && *witness); assert (witness[*witness] == witness[1]); /** Transition relation */ class SetList trans (maxDepth + 1); /** breadth-first search queue */ std::list bfs; /** Visited states (indexes are maxDepth - state) */ class BitVector vis (maxDepth); /** Map from visited states to states through which they were entered */ unsigned* father = new unsigned[maxDepth + 1]; /** placeholder for reachability graph successors */ unsigned* rg = new unsigned[2]; *rg = 0; /** placeholder for property automaton successors */ unsigned* prop = new unsigned[2]; *prop = 0; /** placeholder for product automaton successors */ unsigned* prod = new unsigned[1]; *prod = 0; memset (father, 0xff, (maxDepth + 1) * sizeof *father); unsigned length = 0; /* Start the search from the initial state (1) of the product automaton */ bfs.push_back (1); vis.assign (maxDepth - 1, true); do { unsigned s = bfs.front (); bfs.pop_front (); length++; if (!trans.getSize (s)) decodeProductArc (visited, trans, maxDepth, s, rg, prop, prod, f); for (unsigned i = trans.getSize (s); i--; ) { unsigned t = trans[s][i]; assert (t < maxDepth); if (father[t] == UINT_MAX) father[t] = maxDepth - s; if (unsigned mi = memberIndex (t, witness)) { //Construct the witness path card_t* w = new card_t[length + *witness + 1]; *w = length + *witness; memcpy (w + length + 1, witness + mi, (*witness - mi + 1) * sizeof *w); memcpy (w + length + 1 + (*witness - mi + 1), witness + 2, (mi - 1) * sizeof (card_t)); do w[length--] = t = father[t]; while (length && t != UINT_MAX); if (t == UINT_MAX) { length++; memmove (w + 1, w + length + 1, (*w - length) * sizeof *w); *w -= length; } delete[] witness; witness = w; goto finish; } else if (!vis.tset (t)) bfs.push_back (maxDepth - t); } } while (!bfs.empty ()); finish: delete[] rg; delete[] prop; delete[] prod; delete[] father; } /** Convert the product automaton states in the witness path * to reachability graph states * @param states the product automaton states * @param witness the witness path */ inline static void project (StateStack& states, card_t* witness) { register card_t* w = witness + *witness + 1; while (--w > witness) { StateStack::const_iterator psi = states.begin(); assert (*w < states.size ()); for (register card_t i = *w; i--; psi++); *w = psi->rg; } } /** Check the product component for a fair counterexample * @param reporter the reachability graph interface * @param property the property automaton * @param states the component * @param selfLoops bitvector indicating states with arcs to themselves * @param visited map of visited states * @param minDepth minimum Tarjan depth in the component * @param maxDepth maximum Tarjan depth in the component * @param f the temporary files * @return the counterexample path, or NULL if no counterexample */ static card_t* checkStronglyFair (class GraphReporter& reporter, const class Property& property, StateStack& states, const class BitVector& selfLoops, StateMap& visited, unsigned minDepth, unsigned maxDepth, struct files& f) { /** data structure for strong fairness check and counterexample generation */ struct components c; /** root state of the accepting component */ unsigned root = 0; /* recover the transition relation */ readArcs (f, visited, states, reporter, property, minDepth, maxDepth, c); /** maximum size of the L and U sets */ unsigned size = property.getNumSets () + reporter.net.getNumWeaklyFair () + reporter.net.getNumStronglyFair (); /* check the strong fairness constraints */ if (reporter.net.getNumStronglyFair () && (root = checkStreett (c, selfLoops, size, maxDepth)) == UINT_MAX) { delete c.trans; delete c.l; delete c.u; delete[] c.comp; return 0; } /** counterexample path */ card_t* witness = streettWitness (c, root, size); if (witness) { computePrefix (visited, maxDepth, witness, f); project (states, witness); } delete c.trans; delete c.l; delete c.u; delete[] c.comp; return witness; } /** mix -- mix two 32-bit values * Based on lookup2.c, by Bob Jenkins, December 1996, Public Domain. * Note that this version assumes that sizeof(unsigned)==4. * @param a the first 32-bit value * @param b the second 32-bit value * @return a mix of the two values */ inline static unsigned mix (unsigned a, unsigned b) { unsigned c = 0; a -= b, a -= c, a ^= c >> 13; b -= c, b -= a, b ^= a << 8; c -= a, c -= b, c ^= b >> 13; a -= b, a -= c, a ^= c >> 12; b -= c, b -= a, b ^= a << 16; c -= a, c -= b, c ^= b >> 5; a -= b, a -= c, a ^= c >> 3; b -= c, b -= a, b ^= a << 10; c -= a, c -= b, c ^= b >> 15; return c; } size_t State::operator() () const { return mix (rg, prop); } card_t* Product::analyze (card_t state) const { assert (!myProp.isFinite ()); /** Temporary files for the arcs */ struct files f; if (!::openFiles (f)) { myReporter.flagFatal (); return 0; } /** Stack of father states (whose children are being investigated) */ StateStack father; /** Stack of child states */ StateStack children; /** Depth-first search stack for Tarjan's algorithm */ TarjanStack dfs; /** Map of visited states for Tarjan's algorithm */ StateMap visited; /** Search depth */ unsigned depth = 1; /** Bit vector indexed by product automaton states: '1'=self loop present */ class BitVector selfLoops; /** Current state of the product automaton */ class State s (state, myProp.getInitialState ()); while (!interrupted && !myReporter.isFatal ()) { // compute a strongly connected component while (!interrupted && !myReporter.isFatal ()) { std::pair p = visited.insert (StateMap::value_type (s, depth)); if (!p.second) break; father.push_front (s); class SearchList& rgSucc = myReporter.getSuccessors (s.rg); if (interrupted || myReporter.isFatal ()) { ::closeFiles (f); return 0; } const unsigned* enabled = myReporter.eval (s.rg, s.prop, myProp[s.prop]); if (!enabled) { ::closeFiles (f); return 0; } assert (*enabled <= myProp[s.prop].getNumSuccessors ()); if (rgSucc.empty ()) rgSucc.push (s.rg); // add a self loop for deadlock state SearchList::const_iterator rgSuccBegin = rgSucc.begin (); SearchList::const_iterator rgSuccEnd = rgSucc.end (); if (!::writeArcs (f, enabled, rgSucc.size (), rgSuccBegin, rgSuccEnd)) { myReporter.eval_done (enabled); ::closeFiles (f); myReporter.flagFatal (); return 0; } /** number of enabled successors */ unsigned numEnabled = *enabled; // check for self loops in the product automaton for (unsigned pi = numEnabled; pi; pi--) { const unsigned propSucc = enabled[pi]; numEnabled--; if (propSucc == s.prop) { for (SearchList::const_iterator i = rgSuccBegin; i != rgSuccEnd; i++, numEnabled++) { class State child (*i, propSucc); children.push_front (child); if (child.rg == s.rg) selfLoops.extend (depth, true); } } else for (SearchList::const_iterator i = rgSuccBegin; i != rgSuccEnd; i++, numEnabled++) children.push_front (State (*i, propSucc)); } rgSucc.clear (); myReporter.eval_done (enabled); dfs.push_front (Tarjan (s, depth++, numEnabled)); if (!numEnabled) break; assert (!children.empty ()); s = children.front (); children.pop_front (); } if (interrupted || myReporter.isFatal ()) break; /** Minimum search depth in the product state */ unsigned minDepth = ::lookup (visited, s); // backtrack for (;;) { if (dfs.empty ()) { ::closeFiles (f); return 0; } class Tarjan& t = dfs.front (); unsigned sDepth = t.depth; if (minDepth && minDepth < sDepth) t.depth = sDepth = minDepth; else minDepth = t.depth; if (t.numSucc-- > 1) { assert (!children.empty ()); s = children.front (); children.pop_front (); break; } s = t.state; dfs.pop_front (); if (sDepth == ::lookup (visited, s)) { unsigned maxDepth = ::lookup (visited, father.front ()); assert (maxDepth >= sDepth); selfLoops.setSize (maxDepth + 1); if (::checkBuchi (myProp, father, selfLoops, visited, maxDepth - sDepth) && ::checkWeaklyFair (myReporter, myProp, father, visited, sDepth, maxDepth)) { if (card_t* witness = ::checkStronglyFair (myReporter, myProp, father, selfLoops, visited, sDepth, maxDepth, f)) { ::closeFiles (f); return witness; } } for (depth = maxDepth + 1; depth > sDepth; depth--) ::lookup_clear (visited, father.front ()), father.pop_front (); selfLoops.truncate (depth = sDepth); fetchOffsets (f, depth, f.offset); fseek (f.directory, -sizeof f.offset, SEEK_CUR); fseek (f.aut_succ, f.offset.aut * sizeof (unsigned), SEEK_SET); fseek (f.rg_succ, f.offset.rg * sizeof (unsigned), SEEK_SET); } } } ::closeFiles (f); return 0; } maria-1.3.5/Automata/Product.h0000644000175000017500000000443010232531472016323 0ustar msmakelamsmakela// Product automaton -*- c++ -*- #ifndef PRODUCT_H_ # define PRODUCT_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "typedefs.h" # include # include # include # include /** @file Product.h * Product of reachability graph and the negation of property being verified */ /* Copyright © 1999-2002,2005 Marko Mäkelä (msmakela@tcs.hut.fi). Copyright © 1999-2001 Timo Latvala (timo@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Product automaton */ class Product { public: /** Constructor * @param reporter interface to the reachability graph * @param prop the property automaton */ Product (class GraphReporter& reporter, const class Property& prop) : myReporter (reporter), myProp (prop) {} private: /** Copy constructor */ Product (const class Product& old); /** Assignment operator */ class Product& operator= (const class Product& old); public: /** Destructor */ ~Product () {} /** Check whether the property expressed by the property automaton holds, * calculating the product of the reachability graph and the automaton, * performing on-the-fly analysis * @param state number of the state where to start the analysis * @return the counterexample path, or NULL if the propery holds */ card_t* analyze (card_t state) const; private: /** The reachability graph */ class GraphReporter& myReporter; /** The property automaton */ const class Property& myProp; }; #endif // PRODUCT_H_ maria-1.3.5/Automata/Property.C0000644000175000017500000005305407643247642016507 0ustar msmakelamsmakela// Property automaton -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation # ifdef __sgi # define _POSIX_C_SOURCE 199309L # endif #endif // __GNUC__ #include "Property.h" // #define DEBUG_AUTOMATON // to display the automaton on stdout #ifdef BUILTIN_LTL # include "LtlGraph.h" # include #else // BUILTIN_LTL # ifdef __WIN32 # undef __STRICT_ANSI__ # include # include # include # undef pipe # define pipe(fds) _pipe (fds, 0, _O_TEXT | _O_NOINHERIT) # endif // __WIN32 # ifdef __CYGWIN__ # undef __STRICT_ANSI__ # endif // __CYGWIN__ # include # ifdef __DECCXX # include # else // __DECCXX # include # endif // __DECCXX #endif // BUILTIN_LTL #include #include #include #ifndef unix # if defined __unix||defined __unix__ # define unix # elif defined _AIX||defined __NetBSD__||defined __APPLE__ # define unix # endif #endif #if !defined BUILTIN_LTL && defined unix #include /** Handle a child termination * @param pid process number of the terminated child */ extern "C" void childterm (pid_t pid); /** Handle a signal * @param num number of the signal */ extern "C" void sig (int num); #endif // !BUILTIN_LTL && unix #include "PropertyState.h" #include "Constant.h" #include "BooleanBinop.h" #include "NotExpression.h" #include "LeafValue.h" #include "BoolType.h" #include "Net.h" /** @file Property.C * Automaton representing the negation of a property being verified */ /* Copyright © 1999-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Property::Property () : #ifdef BUILTIN_LTL myNegated (true), #else // BUILTIN_LTL myFD (0), #endif // BUILTIN_LTL myNumExprs (0), myExprs (0), myNumStates (0), myStates (0), myStatesAccept (0), myInitialState (UINT_MAX), myFinalState (UINT_MAX), myNumSets (0) { } Property::~Property () { delete[] myExprs; delete[] myStates; delete myStatesAccept; } typedef std::map NumberMap; #ifdef BUILTIN_LTL /** Translate a gate condition for a transition * @param gba the generalized Büchi automaton * @param state the state whose successor arcs are to be displayed * @param numProps number of atomic propositions * @param props atomic propositions * @param stateMap map for state numbers * @param s (output) the property state in the automaton */ static void translateGates (const class LtlGraph& gba, unsigned state, unsigned numProps, class Expression** props, NumberMap& stateMap, class PropertyState& s) { for (LtlGraph::const_iterator n = gba.begin (); n != gba.end (); n++) { if (n->second.m_incoming.find (state) == const_cast&>(n->second.m_incoming).end ()) continue; const class LtlBitVector& propositions = n->second.m_atomic; /** The gate expression */ class Expression* gate = 0; std::pair p = stateMap.insert (NumberMap::value_type (n->first, stateMap.size ())); # ifdef DEBUG_AUTOMATON fprintf (stdout, "%u ", p.first->second); # endif // DEBUG_AUTOMATON for (unsigned i = propositions.nonzero (); i; ) { const class LtlAtom& atom = static_cast(Ltl::fetch (i - 1)); if (i) i = propositions.findNext (i); assert (atom.getValue () < numProps); class Expression* prop = props[atom.getValue ()]->copy (); if (atom.isNegated ()) prop = NotExpression::construct (*prop); # ifdef DEBUG_AUTOMATON if (i) fputs ("& ", stdout); fprintf (stdout, atom.isNegated () ? "! p%u " : "p%u ", atom.getValue ()); # endif // DEBUG_AUTOMATON gate = gate ? BooleanBinop::construct (true, *gate, *prop) : prop; } # ifdef DEBUG_AUTOMATON if (!gate) putc ('t', stdout); putc ('\n', stdout); # endif // DEBUG_AUTOMATON if (!gate) gate = (new class Constant (*new class LeafValue (Net::getBoolType (), true)))->cse (); s.addSuccessor (p.first->second, *gate); } # ifdef DEBUG_AUTOMATON fputs ("-1\n", stdout); # endif // DEBUG_AUTOMATON } bool Property::create (class Expression& expr) { assert (myNegated && !myNumExprs && !myNumStates && !myNumSets); class Ltl* ltl = expr.toFormula (*this); assert (ltl); /** The generalized Büchi automaton */ class LtlGraph gba (*ltl); /** acceptance set number and proposition */ typedef std::pair acceptance_set_t; typedef std::map acceptance_map_t; acceptance_map_t acceptance_sets; /** iterator to states */ LtlGraph::const_iterator s; // construct the acceptance sets for (s = gba.begin (); s != gba.end (); s++) { myNumStates++; const class LtlBitVector& temporal = s->second.m_old; for (unsigned i = temporal.nonzero (); i; ) { const class Ltl& f = Ltl::fetch (i - 1); switch (f.getKind ()) { case Ltl::Until: if (!static_cast(f).isRelease ()) acceptance_sets.insert (std::pair (&f, acceptance_set_t (acceptance_sets.size (), &static_cast (f).getRight ()))); break; case Ltl::Future: if (static_cast(f).getOp () == LtlFuture::finally) acceptance_sets.insert (std::pair (&f, acceptance_set_t (acceptance_sets.size (), &static_cast (f).getFormula ()))); break; default: break; } if (i) i = temporal.findNext (i); } } if (!myNumStates++) { fputs ("the property automaton is empty: tautology?\n", stderr); semanticError: Ltl::clear (); delete[] myExprs; myNumExprs = 0, myExprs = 0; delete[] myStates; delete myStatesAccept; myNumStates = 0, myStates = 0, myStatesAccept = 0; myNegated = true, myInitialState = UINT_MAX, myNumSets = 0; return false; } myNumSets = acceptance_sets.size (); if (myNumSets && myNumStates >= UINT_MAX / myNumSets) { fprintf (stderr, "too many states and acceptance sets: %u,%u\n", myNumStates, myNumSets); goto semanticError; } if (!(myStates = new class PropertyState[myNumStates])) { fprintf (stderr, "cannot allocate %u property automaton states\n", myNumStates); goto semanticError; } if (myNumSets && !(myStatesAccept = new class BitVector (myNumStates * myNumSets))) { fprintf (stderr, "cannot allocate %u*%u acceptance sets\n", myNumStates, myNumSets); goto semanticError; } # ifdef DEBUG_AUTOMATON fprintf (stdout, "%u %u\n0 1 -1\n", myNumStates, myNumSets); # endif // DEBUG_AUTOMATON /** map from state numbers to a continuous sequence */ NumberMap stateMap; stateMap.insert (NumberMap::value_type (0, 0)); translateGates (gba, myInitialState = 0, myNumExprs, myExprs, stateMap, myStates[0]); for (s = gba.begin (); s != gba.end (); s++) { const class LtlBitVector& temporal = s->second.m_old; /** mapped state number */ std::pair p = stateMap.insert (NumberMap::value_type (s->first, stateMap.size ())); # ifdef DEBUG_AUTOMATON printf ("%u 0", p.first->second); # endif // DEBUG_AUTOMATON // determine the acceptance sets the state belongs to for (acceptance_map_t::iterator a = acceptance_sets.begin (); a != acceptance_sets.end (); a++) { /** flag: does the state belong to the acceptance set? */ bool accepting = true; for (unsigned i = temporal.nonzero (); i; ) { const class Ltl* f = &Ltl::fetch (i - 1); if (f == a->second.second) { accepting = true; break; } else if (f == a->first) accepting = false; if (i) i = temporal.findNext (i); } if (accepting) { # ifdef DEBUG_AUTOMATON fprintf (stdout, " %u", a->second.first); # endif // DEBUG_AUTOMATON myStatesAccept->assign (p.first->second * myNumSets + a->second.first, true); } } # ifdef DEBUG_AUTOMATON fputs (" -1\n", stdout); # endif // DEBUG_AUTOMATON translateGates (gba, s->first, myNumExprs, myExprs, stateMap, myStates[p.first->second]); } if (!myNumSets) { // no final state and 0 acceptance sets: // this is an infinite-word automaton whose all states accept if (!(myStatesAccept = new class BitVector (myNumStates))) { fprintf (stderr, "cannot allocate %u acceptance sets\n", myNumStates); goto semanticError; } myNumSets = 1; for (unsigned i = myNumStates; i--; ) myStatesAccept->assign (i, true); } Ltl::clear (); return true; } #else // BUILTIN_LTL /** Parse a gate condition for a transition * @param file the input stream * @param numProps number of atomic propositions * @param props atomic propositions * @return the parsed condition */ static class Expression* parseGate (FILE* file, unsigned numProps, class Expression** props) { int ch; # ifdef DEBUG_AUTOMATON do ch = fgetc (file), fputc (ch, stdout); while (isspace (ch)); # else // DEBUG_AUTOMATON while (isspace (ch = fgetc (file))); # endif // DEBUG_AUTOMATON switch (ch) { case 't': case 'f': return (new class Constant (*new class LeafValue (Net::getBoolType (), ch == 't')))->cse (); case '!': if (class Expression* expr = parseGate (file, numProps, props)) return NotExpression::construct (*expr); return 0; case '|': case '&': case 'i': case 'e': if (class Expression* l = parseGate (file, numProps, props)) { if (class Expression* r = parseGate (file, numProps, props)) { switch (ch) { case '|': return BooleanBinop::construct (false, *l, *r); case '&': return BooleanBinop::construct (true, *l, *r); case 'i': return BooleanBinop::construct (false, *NotExpression::construct (*l), *r); case 'e': return BooleanBinop::construct (false, *BooleanBinop::construct (true, *l, *r), *NotExpression::construct (*BooleanBinop::construct (false, *l->copy (), *r->copy ()))); } } l->destroy (); } return 0; case 'p': { unsigned num; if (1 != fscanf (file, "%u", &num)) fputs ("error in proposition number\n", stderr); else if (num > numProps) fprintf (stderr, "unknown proposition p%u\n", num); else return # ifdef DEBUG_AUTOMATON fprintf (stdout, "%u", num), # endif // DEBUG_AUTOMATON props[num]->copy (); } return 0; case EOF: fputs ("unexpected end of file while parsing formula\n", stderr); return 0; default: fprintf (stderr, "unknown character 0x%02x", ch); return 0; } } bool Property::create (const char* translator, class Expression& expr) { assert (translator && !myFD && !myNumExprs && !myNumStates); /** pipes for the formula and for the automaton */ int pipe_formula[2], pipe_automaton[2]; if (pipe (pipe_formula)) { perror ("pipe"); return false; } if (pipe (pipe_automaton)) { perror ("pipe"); close (pipe_formula[0]), close (pipe_formula[1]); return false; } # if defined __WIN32 /* * Since Windows does fork(2)/exec(2) in single pass, we have to * duplicate the file descriptors before executing the child process. */ int old_in = _dup (STDIN_FILENO), old_out = _dup (STDOUT_FILENO); dup2 (pipe_formula[0], STDIN_FILENO); dup2 (pipe_automaton[1], STDOUT_FILENO); /* Create the child process */ HANDLE pid = reinterpret_cast (_spawnlp (_P_NOWAIT, translator, translator, 0)); _dup2 (old_in, STDIN_FILENO), _dup2 (old_out, STDOUT_FILENO); close (old_in), close (old_out); if (!pid || pid == INVALID_HANDLE_VALUE) { perror (translator); close (pipe_formula[0]), close (pipe_formula[1]); close (pipe_automaton[0]), close (pipe_automaton[1]); return false; } # elif defined unix signal (SIGCHLD, SIG_DFL); pid_t pid = fork (); if (!pid) { /* child process */ dup2 (pipe_formula[0], STDIN_FILENO); dup2 (pipe_automaton[1], STDOUT_FILENO); close (pipe_formula[0]), close (pipe_formula[1]); close (pipe_automaton[0]), close (pipe_automaton[1]); setsid (); execlp (translator, translator, 0); perror (translator); exit (0); } else if (pid < 0) { perror ("fork"); close (pipe_automaton[0]), close (pipe_automaton[1]); close (pipe_formula[0]), close (pipe_formula[1]); return false; } # else # error "unsupported operating system" # endif myFD = pipe_formula[1]; close (pipe_formula[0]), close (pipe_automaton[1]); write (myFD, "!", 1); expr.toFormula (*this); close (myFD); myFD = 0; /** file handle for parsing the automaton */ FILE* f = fdopen (pipe_automaton[0], "r"); if (!f) { perror ("fdopen"); close (pipe_automaton[0]); goto semanticError; } /** character read from the file */ int ch; # ifdef unix for (;;) { int status = 0; pid_t child = wait (&status); if (child == pid) { if (!status) break; fprintf (stderr, "%s returned %d\n", translator, status); goto statusError; } else if (child < 0) { perror ("wait"); statusError: signal (SIGCHLD, sig); goto semanticError; } else childterm (pid); } signal (SIGCHLD, sig); # endif // unix if (2 != fscanf (f, "%u%u", &myNumStates, &myNumSets)) { parseError: fputs ("error in translated automaton\n", stderr); semanticError: # if defined __WIN32 TerminateProcess (pid, 0); # elif defined unix kill (pid, SIGKILL); # endif // unix delete[] myExprs; myNumExprs = 0, myExprs = 0; delete[] myStates; delete myStatesAccept; myNumStates = 0, myStates = 0, myStatesAccept = 0; myInitialState = UINT_MAX, myNumSets = 0; if (f) fclose (f); return false; } if (!myNumStates) { fputs ("the property automaton is empty: tautology?\n", stderr); goto semanticError; } if (myNumSets && myNumStates >= UINT_MAX / myNumSets) { fprintf (stderr, "too many states and acceptance sets: %u,%u\n", myNumStates, myNumSets); goto semanticError; } if (!(myStates = new class PropertyState[myNumStates])) { fprintf (stderr, "cannot allocate %u property automaton states\n", myNumStates); goto semanticError; } if (myNumSets && !(myStatesAccept = new class BitVector (myNumStates * myNumSets))) { fprintf (stderr, "cannot allocate %u*%u acceptance sets\n", myNumStates, myNumSets); goto semanticError; } /** map from state numbers to a continuous sequence */ NumberMap stateMap; /** map from acceptance set numbers to a continuous sequence */ NumberMap setMap; # ifdef DEBUG_AUTOMATON fprintf (stdout, "%u %u\n", myNumStates, myNumSets); # endif // DEBUG_AUTOMATON for (unsigned i = myNumStates; i--; ) { unsigned num, initial; // state number and "initial state" flag if (2 != fscanf (f, "%u%u", &num, &initial) || initial > unsigned (1 + !myNumSets)) goto parseError; std::pair p = stateMap.insert (NumberMap::value_type (num, stateMap.size ())); // translated number of the state const unsigned state = p.first->second; if (myStates[state].getNumSuccessors ()) { fprintf (stderr, "redefinition of state %u\n", num); goto semanticError; } if (initial == 2) { if (myFinalState != UINT_MAX) { fprintf (stderr, "redefinition of final state as %u\n", num); goto semanticError; } myFinalState = state; } else if (initial) { if (myInitialState != UINT_MAX) { fprintf (stderr, "redefinition of initial state as %u\n", num); goto semanticError; } myInitialState = state; } # ifdef DEBUG_AUTOMATON fprintf (stdout, "%u %u ", state, initial); # endif // DEBUG_AUTOMATON // acceptance sets that the state belongs to for (;;) { while (isspace (ch = fgetc (f))); if (ch == '-') { if (1 != fscanf (f, "%u", &num) || 1 != num) { fputs ("unexpected data after '-'\n", stderr); goto semanticError; } # ifdef DEBUG_AUTOMATON fputs ("-1\n", stdout); # endif // DEBUG_AUTOMATON break; } ungetc (ch, f); if (!isdigit (ch) || 1 != fscanf (f, "%u", &num)) goto parseError; p = setMap.insert (NumberMap::value_type (num, setMap.size ())); if (p.second && setMap.size () > myNumSets) { fprintf (stderr, "too many acceptance sets: set number %u\n", num); goto semanticError; } # ifdef DEBUG_AUTOMATON fprintf (stdout, "%u ", p.first->second); # endif // DEBUG_AUTOMATON myStatesAccept->assign (state * myNumSets + p.first->second, true); } // transitions for (;;) { while (isspace (ch = fgetc (f))); if (ch == '-') { if (1 != fscanf (f, "%u", &num) || 1 != num) { fputs ("unexpected data after '-'\n", stderr); goto semanticError; } # ifdef DEBUG_AUTOMATON fputs ("-1\n", stdout); # endif // DEBUG_AUTOMATON break; } ungetc (ch, f); if (!isdigit (ch) || 1 != fscanf (f, "%u", &num)) goto parseError; p = stateMap.insert (NumberMap::value_type (num, stateMap.size ())); if (p.second && stateMap.size () > myNumStates) { fputs ("too many states\n", stderr); goto semanticError; } # ifdef DEBUG_AUTOMATON fprintf (stdout, "%u", p.first->second); # endif // DEBUG_AUTOMATON if (class Expression* e = ::parseGate (f, myNumExprs, myExprs)) { if (p.first->second == myFinalState) { fputs ("ignoring transition from final state\n", stderr); e->destroy (); } else myStates[state].addSuccessor (p.first->second, *e); } else goto parseError; # ifdef DEBUG_AUTOMATON fputc ('\n', stdout); # endif // DEBUG_AUTOMATON } } while (isspace (ch = fgetc (f))); if (ch != EOF) { fputs ("extraneous non-whitespace data at end of input\n", stderr); goto semanticError; } if (!myNumSets && myFinalState == UINT_MAX) { // no final state and 0 acceptance sets: // this is an infinite-word automaton whose all states accept if (!(myStatesAccept = new class BitVector (myNumStates))) { fprintf (stderr, "cannot allocate %u acceptance sets\n", myNumStates); goto semanticError; } myNumSets = 1; for (unsigned i = myNumStates; i--; ) myStatesAccept->assign (i, true); } fclose (f); return true; } #endif // BUILTIN_LTL class Ltl* Property::addConstant (bool b) { #ifdef BUILTIN_LTL return &LtlConstant::construct (b != myNegated); #else // BUILTIN_LTL assert (myFD); write (myFD, b ? " t" : " f", 2); return 0; #endif // BUILTIN_LTL } class Ltl* Property::addUnop (enum Unop op, class Expression& expr) { #ifdef BUILTIN_LTL if (op == opNot) myNegated = !myNegated; class Ltl* ltl = expr.toFormula (*this); if (op == opNot) myNegated = !myNegated; switch (op) { case opNot: break; case opFinally: ltl = &LtlFuture::construct (myNegated ? LtlFuture::globally : LtlFuture::finally, *ltl); break; case opGlobally: ltl = &LtlFuture::construct (myNegated ? LtlFuture::finally : LtlFuture::globally, *ltl); break; case opNext: ltl = &LtlFuture::construct (LtlFuture::next, *ltl); break; } return ltl; #else // BUILTIN_LTL assert (myFD); switch (op) { case opNot: write (myFD, " !", 2); break; case opFinally: write (myFD, " F", 2); break; case opGlobally: write (myFD, " G", 2); break; case opNext: write (myFD, " X", 2); break; } return expr.toFormula (*this); #endif // BUILTIN_LTL } class Ltl* Property::addBinop (enum Binop op, class Expression& left, class Expression& right) { #ifdef BUILTIN_LTL class Ltl* l = left.toFormula (*this); class Ltl* r = right.toFormula (*this); switch (op) { case opAnd: return &LtlJunct::construct (!myNegated, *l, *r); case opOr: return &LtlJunct::construct (myNegated, *l, *r); case opRelease: return &LtlUntil::construct (!myNegated, *l, *r); case opUntil: return &LtlUntil::construct (myNegated, *l, *r); } assert (false); return 0; #else // BUILTIN_LTL assert (myFD); switch (op) { case opAnd: write (myFD, " &", 2); break; case opOr: write (myFD, " |", 2); break; case opUntil: write (myFD, " U", 2); break; case opRelease: write (myFD, " V", 2); break; } left.toFormula (*this); right.toFormula (*this); return 0; #endif // BUILTIN_LTL } class Ltl* Property::addExpression (class Expression& expr) { #ifndef BUILTIN_LTL assert (myFD); #endif // !BUILTIN_LTL unsigned i; for (i = 0; i < myNumExprs; i++) if (myExprs[i] == &expr) break; if (i == myNumExprs) { class Expression** exprs = new class Expression*[i + 1]; assert (myExprs ? i : !i); if (myExprs) { memcpy (exprs, myExprs, i * sizeof *exprs); delete[] myExprs; } (myExprs = exprs)[myNumExprs++] = &expr; } #ifdef BUILTIN_LTL return &LtlAtom::construct (i, myNegated); #else // BUILTIN_LTL char num[23]; write (myFD, num, snprintf (num, sizeof num, " p%u", i)); return 0; #endif // BUILTIN_LTL } maria-1.3.5/Automata/Property.h0000644000175000017500000001175007643247642016551 0ustar msmakelamsmakela// Property automaton -*- c++ -*- #ifndef PROPERTY_H_ # define PROPERTY_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "PropertyState.h" # include "BitVector.h" /** @file Property.h * Automaton representing the negation of a property being verified */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Property automaton */ class Property { public: /** Unary operators */ enum Unop { opNot, opFinally, opGlobally, opNext }; /** Binary operators */ enum Binop { opAnd, opOr, opUntil, opRelease }; /** Constructor */ Property (); private: /** Copy constructor */ explicit Property (const class Property& old); /** Assignment operator */ class Property operator= (const class Property& old); public: /** Destructor */ ~Property (); # ifdef BUILTIN_LTL /** Create the property automaton from an expression * @param expr expression to be translated to an automaton */ bool create (class Expression& expr); # else // BUILTIN_LTL /** Create the property automaton from an expression * @param translator command line for invoking an external translator * @param expr expression to be translated to an automaton * @return true if the automaton was successfully generated */ bool create (const char* translator, class Expression& expr); # endif // BUILTIN_LTL /** Append a constant to the formula string * @param b the constant (true or false) * @return the translated object */ class Ltl* addConstant (bool b); /** Append a unary operator to the formula string * @param op operator to be appended * @param expr the operand * @return the translated object */ class Ltl* addUnop (enum Unop op, class Expression& expr); /** Append a unary operator to the formula string * @param op operator to be appended * @param left the first operand * @param right the second operand * @return the translated object */ class Ltl* addBinop (enum Binop op, class Expression& left, class Expression& right); /** Append a proposition to the formula string * @param expr proposition to be appended * @return the translated object */ class Ltl* addExpression (class Expression& expr); /** Determine the index number of the initial state */ unsigned getInitialState () const { return myInitialState; } /** Determine the index number of the accepting state */ unsigned getFinalState () const { return myFinalState; } /** Determine the number of states in the property automaton */ unsigned getNumStates () const { return myNumStates; } /** Determine the number of acceptance sets in the property automaton */ unsigned getNumSets () const { return myNumSets; } /** Access a state of the automaton * @param i number of the state * @return the state */ const class PropertyState& operator[] (unsigned i) const { assert (i < myNumStates); return myStates[i]; } /** Determine whether a state belongs to an acceptance set * @param i number of the state * @param acc number of the acceptance set */ bool accepts (unsigned i, unsigned acc) const { assert (!isFinite ()); assert (myStatesAccept && i < myNumStates); assert (acc < myNumSets); return (*myStatesAccept)[myNumSets ? i * myNumSets + acc : i]; } /** Determine whether the automaton is a finite-word automaton */ bool isFinite () const { return !myNumSets; } private: # ifdef BUILTIN_LTL /** Flag: is the formula negated? */ bool myNegated; # else // BUILTIN_LTL /** File handle for translating the formula */ int myFD; # endif // BUILTIN_LTL /** Number of atomic propositions */ unsigned myNumExprs; /** The atomic propositions (boolean expressions, the alphabet) */ class Expression** myExprs; /** Number of states */ unsigned myNumStates; /** The states */ class PropertyState* myStates; /** Acceptance sets the states belong to */ class BitVector* myStatesAccept; /** Index number of the initial state */ unsigned myInitialState; /** Index number of the accepting state (for finite-word automata) */ unsigned myFinalState; /** Number of acceptance sets */ unsigned myNumSets; }; #endif // PROPERTY_H_ maria-1.3.5/Automata/PropertyState.C0000644000175000017500000001104007643247642017475 0ustar msmakelamsmakela// A state in the property automaton -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "PropertyState.h" #include "Constant.h" #include "BitVector.h" #include "LeafValue.h" #include /** @file PropertyState.C * A state in the property automaton */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ PropertyState::~PropertyState () { delete[] mySuccessors; while (myNumSuccessors--) myGates[myNumSuccessors]->destroy (); delete[] myGates; } void PropertyState::addSuccessor (unsigned num, class Expression& gate) { /** Flag: is this a constant (constantly enabled) gate */ bool constant = gate.getKind () == Expression::eConstant; if (constant) { const class Value& v = static_cast(gate).getValue (); assert (v.getKind () == Value::vLeaf); // Ignore constantly disabled gates if (!bool (static_cast(v))) { gate.destroy (); return; } } unsigned i = myNumSuccessors++; unsigned* successors = new unsigned[myNumSuccessors]; class Expression** gates = new class Expression*[myNumSuccessors]; if (constant) { // add constantly enabled gates to the beginning of the array memcpy (successors + 1, mySuccessors, i * sizeof *successors); memcpy (gates + 1, myGates, i * sizeof *gates); *successors = num; *gates = &gate; } else { // add conditionally enabled gates to the end of the array memcpy (successors, mySuccessors, i * sizeof *successors); memcpy (gates, myGates, i * sizeof *gates); successors[i] = num; gates[i] = &gate; } delete[] mySuccessors; delete[] myGates; mySuccessors = successors; myGates = gates; } bool PropertyState::eval (const class Valuation& valuation, unsigned*& result, unsigned final) const { assert (valuation.isOK ()); *(result = new unsigned[myNumSuccessors + 1]) = 0; for (unsigned i = myNumSuccessors; i--; ) { if (class Value* v = myGates[i]->eval (valuation)) { assert (valuation.isOK ()); assert (v->getKind () == Value::vLeaf); if (bool (static_cast(*v))) { result[++(*result)] = mySuccessors[i]; delete v; if (mySuccessors[i] == final) return false; } else delete v; } else { assert (!valuation.isOK ()); return false; } } return true; } #ifdef EXPR_COMPILE # include "CExpression.h" void PropertyState::compileGates (class CExpression& cexpr, unsigned indent, const char* result, unsigned final) const { class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append ("*"), out.append (result), out.append ("=0;\n"); for (unsigned i = myNumSuccessors; i--; ) { if (myGates[i]->getKind () == Expression::eConstant) { const class Value& v = static_cast(myGates[i])->getValue (); assert (v.getKind () == Value::vLeaf); if (!bool (static_cast(v))) continue; out.indent (indent); } else { const char* work = cexpr.getFlag (); myGates[i]->compile (cexpr, indent, work, 0); out.indent (indent); out.append ("if ("), out.append (work), out.append (") "); } if (mySuccessors[i] == final) { out.append ("{\n"); cexpr.compileError (indent + 2, errNone); out.indent (indent + 2); } out.append (result); out.append ("[++(*"), out.append (result); out.append (")]="); out.append (mySuccessors[i]), out.append (";\n"); if (mySuccessors[i] == final) { out.indent (indent + 2), out.append ("return errComp;\n"); out.indent (indent), out.append ("}\n"); } } cexpr.compileError (indent, errNone); } #endif // EXPR_COMPILE maria-1.3.5/Automata/PropertyState.h0000644000175000017500000000606407643247642017554 0ustar msmakelamsmakela// A state in the property automaton -*- c++ -*- #ifndef PROPERTYSTATE_H_ # define PROPERTYSTATE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include /** @file PropertyState.h * A state in the property automaton */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** A state in the property automaton */ class PropertyState { public: /** Default constructor */ PropertyState () : myNumSuccessors (0), mySuccessors (0), myGates (0) {} private: /** Copy constructor */ explicit PropertyState (const class PropertyState& old); /** Assignment operator */ class PropertyState& operator= (const class PropertyState& old); public: /** Destructor */ ~PropertyState (); /** Determine the number of successor states */ unsigned getNumSuccessors () const { return myNumSuccessors; } /** Access a successor * @param i zero-based index number to the successor * @return the successor */ unsigned operator[] (unsigned i) const { assert (i < myNumSuccessors); return mySuccessors[i]; } /** Add a successor state * @param num the successor state number * @param gate enabling condition */ void addSuccessor (unsigned num, class Expression& gate); /** Evaluate the gates * @param valuation Valuation for evaluating the gates * @param result (out) amount and numbers of enabled successors * @param final number of the final state (UINT_MAX if none) * @return whether the evaluation was successful */ bool eval (const class Valuation& valuation, unsigned*& result, unsigned final = UINT_MAX) const; # ifdef EXPR_COMPILE /** Compile the gate evaluator * @param cexpr the compiled expression * @param indent indentation level * @param result name of the result vector * @param final number of the final state (UINT_MAX if none) */ void compileGates (class CExpression& cexpr, unsigned indent, const char* result, unsigned final) const; # endif // EXPR_COMPILE private: /** Number of successor states */ unsigned myNumSuccessors; /** The successor states */ unsigned* mySuccessors; /** The successor gates */ class Expression** myGates; }; #endif // PROPERTYSTATE_H_ maria-1.3.5/Automata/SetList.C0000644000175000017500000000706507643247642016253 0ustar msmakelamsmakela// List of sets -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "SetList.h" #include "BitVector.h" #include /** @file SetList.C * A collection of sets of numbers */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). Copyright © 2000 Timo Latvala (timo@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ SetList::SetList (unsigned numSets) : myNumSets (numSets), myAllocatedSets (0), mySets (0) { for (myAllocatedSets = 1; myAllocatedSets < numSets; myAllocatedSets <<= 1); mySets = new unsigned*[myAllocatedSets]; memset (mySets, 0, myAllocatedSets * sizeof *mySets); } SetList::~SetList () { for (unsigned i = myNumSets; i--; ) delete[] mySets[i]; delete[] mySets; } void SetList::assign (unsigned i, unsigned* array) { assert (i < myNumSets && array && *array); if (!mySets[i]) mySets[i] = array; else { unsigned* sets = new unsigned[*mySets[i] + *array + 1]; memcpy (sets, mySets[i], (*mySets[i] + 1) * sizeof *sets); memcpy (sets + *sets + 1, array + 1, *array * sizeof *sets); *sets += *array; delete[] mySets[i]; delete[] array; mySets[i] = sets; } } void SetList::assign (unsigned i, const class BitVector& bv, unsigned offset, bool complement) { assert(i < myNumSets); if (!bv.getSize()) return; unsigned numTrue = 0, b; for (b = bv.getSize(); b--; ) if(bv[b] != complement) numTrue++; if (!numTrue) return; unsigned* s = new unsigned[numTrue + 1]; *s = numTrue; for (b = bv.getSize();; ) if(bv[--b] != complement) if ((s[numTrue] = b + offset), !--numTrue) break; assign (i, s); } void SetList::copy (unsigned i, const unsigned* array) { assert (i < myNumSets && array && *array); if (!mySets[i]) { mySets[i] = new unsigned[*array + 1]; memcpy (mySets[i], array, (*array + 1) * sizeof *array); } else { unsigned* sets = new unsigned[*mySets[i] + *array + 1]; memcpy (sets, mySets[i], (*mySets[i] + 1) * sizeof *sets); memcpy (sets + *sets + 1, array + 1, *array * sizeof *sets); *sets += *array; delete[] mySets[i]; mySets[i] = sets; } } void SetList::grow (unsigned numSets) { assert (numSets > myNumSets); if (numSets <= myAllocatedSets) { memset (mySets + myNumSets, 0, (numSets - myNumSets) * sizeof *mySets); myNumSets = numSets; return; } for (; myAllocatedSets < numSets; myAllocatedSets <<= 1); unsigned** sets = new unsigned*[myAllocatedSets]; memcpy (sets, mySets, myNumSets * sizeof *sets); memset (sets + myNumSets, 0, (numSets - myNumSets) * sizeof *sets); delete[] mySets; mySets = sets; myNumSets = numSets; } void SetList::shrink (unsigned numSets) { assert (numSets <= myNumSets); while (myNumSets > numSets) delete[] mySets[--myNumSets]; } maria-1.3.5/Automata/SetList.h0000644000175000017500000000713207643247642016313 0ustar msmakelamsmakela// List of sets -*- c++ -*- #ifndef SETLIST_H_ # define SETLIST_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include /** @file SetList.h * A collection of sets of numbers */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). Copyright © 2000 Timo Latvala (timo@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** List of sets */ class SetList { public: /** Constructor * @param numSets number of sets */ explicit SetList (unsigned numSets); private: /** Copy constructor */ SetList (const class SetList& old); /** Assignment operator */ class SetList& operator= (const class SetList& old); public: /** Destructor */ ~SetList (); /** Assign an array to a set * @param i index number of the set * @param array array to be assigned (length==array[0]) */ void assign (unsigned i, unsigned* array); /** Assign a bit vector to a set * @param i index number to the set * @param bv BitVector to be assigned * @param offset offset for index numbers * @param complement flag: treat BitVector as its complement */ void assign (unsigned i, const class BitVector& bv, unsigned offset, bool complement); /** Copy an array to a set * @param i index number of the set * @param array array to be copied (length==array[0]) */ void copy (unsigned i, const unsigned* array); /** Grow the list * @param numSets new size of the list */ void grow (unsigned numSets); /** Shrink the list * @param numSets new size of the list */ void shrink (unsigned numSets); /** Determine the number of sets */ unsigned getNumSets () const { return myNumSets; } /** Determine the size of a set * @param i index number of the set * @return number of elements in the set */ unsigned getSize (unsigned i) const { assert (i < myNumSets); return mySets[i] ? *mySets[i] : 0; } /** Access a set * @param i index number of the set * @return pointer to the first element in the set */ const unsigned* operator[] (unsigned i) const { assert (i < myNumSets); return mySets[i] + 1; } /** Access a set * @param i index number of the set * @return pointer to the first element in the set */ unsigned* operator[] (unsigned i) { assert (i < myNumSets); return mySets[i] + 1; } /** Remove an element of a set by assigning the last element to its place * @param i index number of the set * @param elem index of the element */ void delElement (unsigned i, unsigned elem) { assert(i < myNumSets && elem < *mySets[i]); mySets[i][elem + 1] = mySets[i][(*mySets[i])--]; } private: /** Number of sets */ unsigned myNumSets; /** Number of allocated sets */ unsigned myAllocatedSets; /** The sets */ unsigned** mySets; }; #endif // SETLIST_H_ maria-1.3.5/Automata/property.html0000644000175000017500000002025107461221670017311 0ustar msmakelamsmakela The property automaton translator interface

The property automaton translator interface

Maria relies on external programs translating LTL formulae into generalised Büchi automata or finite-word automata. It communicates with these programs by writing a formula to the standard input of the translator and by reading the translated automaton from the standard output of the translator. Each formula is translated in a separate run of the external program. The program is invoked without arguments.

Grammar Definitions

The grammars are presented in Backus-Naur Form, one grammar rule per line. Comments delimited by the symbols /* and */ are not part of the formal grammar. Non-terminal symbols are enclosed within single quotes or presented as Flex-style regular-expressions.

Output format for LTL formulae

Currently, Maria does not make use of the implication, equivalence or exclusive disjunction operators, but they might be generated in the future.

Propositional operators

<f> ::= 't' /* true */
<f> ::= 'f' /* false */
<f> ::= 'p'[0-9]+ /* proposition */
<f> ::= '!' <f> /* negation */
<f> ::= '|' <f> <f> /* disjunction */
<f> ::= '&' <f> <f> /* conjunction */
<f> ::= 'i' <f> <f> /* implication: "i <f1> <f2>" is short-hand for "| ! <f1> <f2>" */
<f> ::= 'e' <f> <f> /* equivalence */
<f> ::= '^' <f> <f> /* exclusive disjunction (xor) */
<f> ::= [ \t\n\r\v\f] <f> /* white space is ignored */
<f> ::= <f> [ \t\n\r\v\f] /* white space is ignored */

Temporal operators

<f> ::= 'X' <f> /* next */
<f> ::= 'F' <f> /* finally, eventually */
<f> ::= 'G' <f> /* globally, henceforth */
<f> ::= 'U' <f> <f> /* until */
<f> ::= 'V' <f> <f> /* release */

Input format for automata

The same grammar is used for both finite automata (safety properties) and for generalised Büchi automata (liveness properties). A finite automaton has zero acceptance sets and exactly one final state that does not have any successor states. A generalised Büchi automaton has no final state. If the number of acceptance sets of a generalised Büchi automaton is zero, this means that the automaton has one acceptance set to which all states belong.

<automaton> ::= [0-9]+ <space> [0-9]+ <states> /* first the number of states, then the number of acceptance sets (if the latter is 0, it is a generalised Büchi automaton whose all states accept, or a finite automaton) */
<space> ::= [ \n]+
<states> ::= /* empty */
<states> ::= <states> <space> <state>
<state> ::= [0-9]+ <space> <finitial?> <space> <acceptance sets> '-1' <transitions> '-1' /* state identifiers can be arbitrary unsigned integers */
<finitial?> ::= '0' /* not an initial or a final state */
<finitial?> ::= '1' /* initial state (exactly one state must be initial) */
<finitial?> ::= '2' /* final state (exactly one state must be final for finite automata) */
<acceptance sets> ::= /* empty */
<acceptance sets> ::= <acceptance sets> [0-9]+ <space> /* acceptance set identifiers can be arbitrary unsigned integers */
<transitions> ::= /* empty */
<transitions> ::= <transitions> <space> <transition>
<transition> ::= [0-9]+ <space> 't' /* constantly enabled transition to a state */
<transition> ::= [0-9]+ <space> <gate> /* conditionally enabled transition to a state */
<gate> ::= 'p'[0-9]+ /* proposition */
<gate> ::= '!' <space> <gate> /* negation */
<gate> ::= '|' <space> <gate> <space> <gate> /* disjunction */
<gate> ::= '&' <space> <gate> <space> <gate> /* conjunction */

Hints for Debugging

Maria maps the state numbers in the property automata to a contiguous sequence. If you want to see the automata after this mapping, define the preprocessor symbol DEBUG_AUTOMATON when compiling the file Property.C. In that way, Maria will dump the mapped automaton to the standard output. The automaton can be visualised with the lbt2dot tool of LBT.

To grab the formula sent by Maria to the external translator, write a wrapper shell script for the translator that does something like tee formula.txt | exec the-real-translator.

maria-1.3.5/Doxyfile0000644000175000017500000000162707300010165014463 0ustar msmakelamsmakela# Doxygen configuration file for Maria, much like a -*- makefile -*- PROJECT_NAME = Maria WARNINGS = YES HAVE_DOT = YES GRAPHICAL_HIERARCHY = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = YES INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES INPUT = Expression Type Value Net Graph Automata parser \ Compilation/base FILE_PATTERNS = *.C *.h *.c EXCLUDE_PATTERNS = lex.* *.tab.? INCLUDE_PATH = Expression Net Type Value Graph Automata parser \ Compilation/base ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES FULL_PATH_NAMES = YES GENERATE_LATEX = NO COMPACT_LATEX = YES PDF_HYPERLINKS = YES PAPER_TYPE = a4 GENERATE_RTF = NO GENERATE_MAN = NO GENERATE_HTML = YES SEARCHENGINE = YES CGI_NAME = maria CGI_URL = http://siphon.tcs.hut.fi/cgi-bin DOC_URL = http://siphon.tcs.hut.fi/maria DOC_ABSPATH = /var/www/maria BIN_ABSPATH = /usr/lib/cgi-bin maria-1.3.5/INSTALL0000644000175000017500000000546507575071071014033 0ustar msmakelamsmakelaCompiling Maria (on Unix-like platforms): Prerequisites ------------- To compile Maria, you will need: - C and C++ compilers. (The main development platform is Linux and GCC 2.95, and the code is occasionally also compiled with Compaq cxx v6.3.) - A POSIX.1 compliant "make" utility, such as GNU Make or the native one of Digital UNIX 4.0. - The GNU Readline library (unless you disable the HAS_READLINE option) - GNU Bison 1.28 and flex 2.5.4 if you want to recompile the parsers Basic compilation ----------------- To invoke the compilation, type make -f Makefile.`uname` where `uname` is the type of your system. (Makefile.BSD is common for FreeBSD, NetBSD, OpenBSD and IBM AIX.) If there is no Makefile for your system, make a copy of an existing file, adapt it, and send it to me, so that it will be included in the next version. Multi-processor compilation --------------------------- On a multi-processor system, you may want to use the -j option of GNU Make. Determine the number of processors you want to use (try "uptime" and "/usr/sbin/psrinfo" or "mpadmin -s"), and compile the files: nice make -f Makefile.`uname` depend nice make -f Makefile.`uname` -j 8 The target "depend" should be made on a single processor, since the targets involving Bison and Flex interfere with the -j option. The argument of the -j option specifies the number of processors to be utilised. Installation ------------ To install Maria on a Unix-like system, use the pseudo-target "install". You may want to specify the target directory tree, like below: make PREFIX=/usr/local install If install(1) does not support the -c switch, you may need to adjust the variables INSTALLBIN and INSTALLDATA in Makefile. Other tools ----------- You may wish to install also the following tools in order to fully use the potential of Maria: LBT, LTL to generalized Büchi automaton translator http://www.tcs.hut.fi/Software/maria/tools/lbt/ http://www.tcs.hut.fi/Software/maria/src/lbt-1.2.1.tar.gz GraphViz, the Graph Visualization Project of AT&T http://www.graphviz.org http://www.graphviz.org/pub/graphviz/ http://www.research.att.com/sw/tools/graphviz/ The core features of Maria will work also without these tools. The GraphViz-based graphical user interface only works on Unix-like platforms for the time being. Recompiling with different options ---------------------------------- If you modify the HAS_READLINE compilation option, remove parser/marde.tab.o and parser/cmdline.o and invoke make. If you modify the USE_MMAP compilation option, touch Graph/file.h and invoke make. If you modify the BUILTIN_LTL compilation option, touch Automata/Property.h, remove parser/marde.tab.o and invoke make. If you modify other options, it is best to invoke "make clean" and to compile everything from the scratch. Marko Mäkelä (msmakela@tcs.hut.fi) maria-1.3.5/Makefile0000644000175000017500000001704007642015230014420 0ustar msmakelamsmakela### Modular Reachability Analyzer -*- makefile -*- ### User-configurable section begins # Installation directory prefix for Debian GNU/Linux DESTDIR = # Generic installation directory prefix PREFIX = /usr # Where to find GraphViz lefty? LEFTYBIN = $(PREFIX)/bin/lefty # Where to put binaries on 'make install'? BINDIR = $(PREFIX)/bin # Where to put architecture-independent runtime files on 'make install'? RTDIR = $(PREFIX)/share/maria/runtime # Where to put architecture-independent example files on 'make install'? EXDIR = $(PREFIX)/share/maria/examples # Where to put on-line documentation on 'make installinfo'? INFODIR = $(PREFIX)/share/info # Where to put manual pages on 'make installman'? MANDIR = $(PREFIX)/share/man/man1 ## Extra definitions ### use mmap(2) if available, to optimise performance EXTRA_DEFINES = -DUSE_MMAP ### emulate mmap(2) with malloc(3) to obtain reliable memory usage statistics #EXTRA_DEFINES := $(EXTRA_DEFINES) -DUSE_MMAP -DNO_MMAP ### in modular analysis, enable the caching of local successor states #EXTRA_DEFINES := $(EXTRA_DEFINES) -DSYNC_CACHE ### in modular analysis, enable the caching of pre-synchronisation states #EXTRA_DEFINES := $(EXTRA_DEFINES) -DADD_CACHE ## Debugging ### -DNDEBUG omits assert(3) macros ### -DYYDEBUG enables grammar debugging if DEBUG=1 (see parser/maria.C) ### -g includes debugging symbols in the objects and the executable DEBUG = -DNDEBUG #DEBUG = -g # -DYYDEBUG ## Profiling #PROF = -pg PROF = ### Installation commands INSTALLDIR = install -d INSTALLBIN = install -c INSTALLDATA = install -c -m 444 RM = rm -f ### User-configurable section ends LTL_INCLUDES = $(BUILTIN_LTL:yes=-IAutomata/Ltl) LTL_DEFINES = $(BUILTIN_LTL:yes=-DBUILTIN_LTL) COMP_INCLUDES = $(EXPR_COMPILE:yes=-ICompilation/base) COMP_DEFINES = $(EXPR_COMPILE:yes=-DEXPR_COMPILE) CPPFLAGS = $(EXTRA_INCLUDES) $(INCLUDES) $(LTL_INCLUDES) $(COMP_INCLUDES) \ $(DEFINES) $(EXTRA_DEFINES) $(LTL_DEFINES) $(COMP_DEFINES) $(DEBUG) LEX=flex LFLAGS=-o$@ YACC=bison YFLAGS=-d TARGET = maria COMMONSRCS = \ parser/util.C \ parser/StringBuffer.C \ parser/VariableStackMap.C \ parser/Printer.C \ parser/NameList.C AUTSRCS = \ Automata/Property.C \ Automata/PropertyState.C \ Automata/BitVector.C \ Automata/SetList.C \ Automata/Product.C GRAPHSRCS = \ Graph/Graph.C \ Graph/ComponentGraph.C \ Graph/Search.C \ Graph/BitBuffer.C \ Graph/ByteBuffer.C \ Graph/BTree.C \ Graph/States.C \ Graph/StateReporter.C \ Graph/StateSetReporter.C \ Graph/GraphReporter.C \ Graph/DummyReporter.C \ Graph/SyncStates.C \ Graph/StateSet.C \ Graph/FullSet.C \ Graph/ParSet.C \ Graph/CompactSet.C \ Graph/HashGraph.C \ Graph/StateList.C \ Graph/LSTS.C EXPRSRCS = \ Expression/Function.C \ Expression/Substitution.C \ Expression/ExpressionList.C \ Expression/ExpressionSet.C \ Expression/ExpressionMSet.C \ Expression/Expression.C \ Expression/Typecast.C \ Expression/Variable.C \ Expression/Constant.C \ Expression/Undefined.C \ Expression/StructExpression.C \ Expression/StructComponent.C \ Expression/StructAssign.C \ Expression/UnionExpression.C \ Expression/UnionComponent.C \ Expression/UnionTypeExpression.C \ Expression/VectorExpression.C \ Expression/VectorIndex.C \ Expression/VectorAssign.C \ Expression/VectorShift.C \ Expression/UnopExpression.C \ Expression/BinopExpression.C \ Expression/BufferExpression.C \ Expression/BufferWrite.C \ Expression/BufferUnop.C \ Expression/BufferRemove.C \ Expression/BufferIndex.C \ Expression/IfThenElse.C \ Expression/BooleanBinop.C \ Expression/NotExpression.C \ Expression/RelopExpression.C \ Expression/SetExpression.C \ Expression/TemporalUnop.C \ Expression/TemporalBinop.C \ Expression/CardinalityExpression.C \ Expression/TransitionQualifier.C \ Expression/PlaceContents.C \ Expression/Submarking.C \ Expression/Mapping.C \ Expression/EmptySet.C \ Expression/Quantifier.C \ Expression/Marking.C \ Expression/Token.C \ Expression/VariableSet.C NETSRCS = \ Net/LNet.C \ Net/Net.C \ Net/Place.C \ Net/Transition.C \ Net/Arc.C \ Net/PlaceMarking.C \ Net/GlobalMarking.C \ Net/VariableDefinition.C TYPESRCS = \ Type/Type.C \ Type/IntType.C \ Type/CardType.C \ Type/BoolType.C \ Type/CharType.C \ Type/EnumType.C \ Type/IdType.C \ Type/StructType.C \ Type/UnionType.C \ Type/VectorType.C \ Type/BufferType.C \ Type/ComponentList.C \ Type/Range.C \ Type/Constraint.C VALUESRCS = \ Value/Value.C \ Value/ValueList.C \ Value/LeafValue.C \ Value/StructValue.C \ Value/UnionValue.C \ Value/VectorValue.C \ Value/BufferValue.C \ Value/Valuation.C LTLSRCS = \ Automata/Ltl/Ltl.C \ Automata/Ltl/LtlGraph.C \ Automata/Ltl/LtlBitVector.C LTLOPTSRCS = \ $(BUILTIN_LTL:yes=Automata/Ltl/Ltl.C) \ $(BUILTIN_LTL:yes=Automata/Ltl/LtlGraph.C) \ $(BUILTIN_LTL:yes=Automata/Ltl/LtlBitVector.C) COMPSRCS = \ Compilation/base/CExpression.C \ Compilation/base/Compilation.C COMPOPTSRCS = \ $(EXPR_COMPILE:yes=Compilation/base/CExpression.C) \ $(EXPR_COMPILE:yes=Compilation/base/Compilation.C) PARSERSRCS = \ parser/maria.tab.C parser/lex.pn.C \ parser/marde.tab.C parser/lex.de.C PARSERHDRS = \ parser/maria.tab.h parser/marde.tab.h AUX = $(PARSERSRCS) $(PARSERHDRS) CSRCS = parser/cmdline.c CORESRCS = $(COMMONSRCS) $(EXPRSRCS) $(NETSRCS) $(TYPESRCS) $(VALUESRCS) \ $(GRAPHSRCS) $(AUTSRCS) $(LTLOPTSRCS) $(COMPOPTSRCS) CXXSRCS = $(CORESRCS) parser/maria.C parser/server.C parser/Dotty.C SRCS = $(CXXSRCS) $(PARSERSRCS) $(CSRCS) OBJS = $(CXXSRCS:.C=.o) $(PARSERSRCS:.C=.o) $(CSRCS:.c=.o) LIBS = $(EXTRA_LIBS) $(LIBREADLINE) INCLUDES = -Iparser -IExpression -INet -IType -IValue \ -IGraph -IAutomata $(INCREADLINE) INFO = doc/maria.info MANPAGES = maria.1 maria-cso.1 maria-vis.1 error: @echo "Type 'make -f Makefile.`uname`' to compile Maria"; exit 1 real-all: $(TARGET) clean: $(RM) $(OBJS) $(LTLSRCS:.C=.o) $(COMPSRCS:.C=.o) reallyclean: clean $(RM) $(TARGET) $(AUX) $(INFO) install: $(TARGET) $(INSTALLDIR) $(DESTDIR)$(BINDIR) $(INSTALLDIR) $(DESTDIR)$(RTDIR) $(INSTALLDIR) $(DESTDIR)$(EXDIR) $(INSTALLBIN) maria $(DESTDIR)$(BINDIR) $(INSTALLBIN) maria-vis $(DESTDIR)$(BINDIR) $(INSTALLBIN) maria-cso $(DESTDIR)$(BINDIR) sed -e 's:^#!/.*/lefty$$:#!$(LEFTYBIN):' maria-vis > $(DESTDIR)$(BINDIR)/maria-vis sed -e 's:^ *INCLUDES=.*:INCLUDES="-I$(RTDIR)":' maria-cso > $(DESTDIR)$(BINDIR)/maria-cso for i in Compilation/runtime/*.h; do $(INSTALLDATA) "$$i" $(DESTDIR)$(RTDIR); done for i in parser/test/*.pn; do $(INSTALLDATA) "$$i" $(DESTDIR)$(EXDIR); done installinfo: $(INFO) $(INSTALLDIR) $(DESTDIR)$(INFODIR) $(INSTALLDATA) $(INFO) $(DESTDIR)$(INFODIR) installman: $(MANPAGES) $(INSTALLDIR) $(DESTDIR)$(MANDIR) for i in $(MANPAGES); do $(INSTALLDATA) "$$i" $(DESTDIR)$(MANDIR); done info: $(INFO) depend: touch $@ && makedepend -f$@ -Y $(CPPFLAGS) $(SRCS) 2> /dev/null $(TARGET): $(OBJS) $(CXX) $(LDFLAGS) $(PROF) -o $@ $(OBJS) $(LIBS) parser/maria.tab.C parser/maria.tab.h: parser/maria.y (cd parser && $(YACC) $(YFLAGS) -p pn maria.y) mv parser/maria.tab.c parser/maria.tab.C parser/marde.tab.C parser/marde.tab.h: parser/marde.y (cd parser && $(YACC) $(YFLAGS) -p de marde.y) mv parser/marde.tab.c parser/marde.tab.C parser/lex.pn.C: parser/maria.lex parser/maria.tab.h $(LEX) $(LFLAGS) parser/maria.lex parser/lex.de.C: parser/marde.lex parser/marde.tab.h $(LEX) $(LFLAGS) parser/marde.lex .phony: all clean reallyclean install installinfo installman info .SUFFIXES: .SUFFIXES: .o .c .C .info .texinfo .c.o: $(CC) $(CPPFLAGS) $(PROF) $(CFLAGS) -c $< -o $@ .C.o: $(CXX) $(CPPFLAGS) $(PROF) $(CXXFLAGS) -c $< -o $@ .texinfo.info: makeinfo --no-split $< -o $@ include depend maria-1.3.5/Makefile.BSD0000644000175000017500000000125307574121225015034 0ustar msmakelamsmakela### Target-specific definitions for compiling Maria -*- makefile -*- ### (Free|Open|Net)BSD and GNU Compiler Collection (2.95 and 3.x) ## The GNU Readline library (if enabled, check also the directories) #HAS_READLINE = yes HAS_READLINE = LIBREADLINE = $(HAS_READLINE:yes=-L/usr/local/lib -lreadline -lcurses) INCREADLINE = $(HAS_READLINE:yes=-I/usr/local/include -DHAS_READLINE) ## Support for compiled expressions EXPR_COMPILE = yes #EXPR_COMPILE = CXX = g++ CC = gcc EXTRA_INCLUDES = EXTRA_LIBS = # -lstlport DEFINES = -DHAS_REGEX CFLAGS = -Wall -ansi -pedantic -O3 CXXFLAGS = $(CFLAGS) -Iport -fno-exceptions -fno-rtti# -I/usr/include/stlport all: real-all include Makefile maria-1.3.5/Makefile.Darwin0000644000175000017500000000122507574121225015647 0ustar msmakelamsmakela### Target-specific definitions for compiling Maria -*- makefile -*- ### Darwin 6.0 with Apple cc (GCC) 3.1 20020420 (prerelease) ## The GNU Readline library (if enabled, check also the directories) HAS_READLINE = yes #HAS_READLINE = LIBREADLINE = $(HAS_READLINE:yes=-lreadline -lncurses) INCREADLINE = $(HAS_READLINE:yes=-DHAS_READLINE) ## Support for compiled expressions EXPR_COMPILE = yes #EXPR_COMPILE = CXX = cc CC = cc EXTRA_INCLUDES = -I/sw/include EXTRA_LIBS = -lstdc++ -L/sw/lib $(EXPR_COMPILE:yes=-ldl) DEFINES = -DHAS_REGEX CFLAGS = -O3 -fomit-frame-pointer CXXFLAGS = $(CFLAGS) -Iport -fno-exceptions -fno-rtti all: real-all include Makefile maria-1.3.5/Makefile.HP-UX0000644000175000017500000000116307575067764015307 0ustar msmakelamsmakela### Target-specific definitions for compiling Maria -*- makefile -*- ### aCC: HP ANSI C++/C B3910B A.05.36 [May 20 2002] ## The GNU Readline library (if enabled, check also the directories) HAS_READLINE = yes HAS_READLINE = LIBREADLINE = $(HAS_READLINE:yes=-L/usr/local/lib -lreadline -lncurses) INCREADLINE = $(HAS_READLINE:yes=-I/usr/local/include -DHAS_READLINE) ## Support for compiled expressions EXPR_COMPILE = yes #EXPR_COMPILE = ## HP ANSI C++/C compiler CXX = aCC CC = cc EXTRA_INCLUDES = EXTRA_LIBS = DEFINES = -DHAS_REGEX CFLAGS = -fast CXXFLAGS = $(CFLAGS) -Iport -AA +noeh +nrv all: real-all include Makefile maria-1.3.5/Makefile.IRIX640000644000175000017500000000144507574121225015354 0ustar msmakelamsmakela### Target-specific definitions for compiling Maria -*- makefile -*- ### SGI IRIX 6.5 and native CC or GNU Compiler Collection (2.95.x and 3.0.x) ## The GNU Readline library (if enabled, check also the directories) #HAS_READLINE = yes HAS_READLINE = LIBREADLINE = $(HAS_READLINE:yes=-L/usr/local/lib -lreadline -lncurses) INCREADLINE = $(HAS_READLINE:yes=-I/usr/local/include -DHAS_READLINE) ## Support for compiled expressions EXPR_COMPILE = yes #EXPR_COMPILE = ## IRIX 6.5 CC CXX = CC -n32 CC = cc -n32 EXTRA_INCLUDES = EXTRA_LIBS = DEFINES = -DHAS_REGEX CFLAGS = -O2 CXXFLAGS = $(CFLAGS) -Iport -LANG:std -LANG:exceptions=OFF ## GNU Compiler Collection #CXX = g++ #CC = gcc #CFLAGS = -Wall -ansi -pedantic -O3 #CXXFLAGS = $(CFLAGS) -Iport -fno-exceptions -fno-rtti all: real-all include Makefile maria-1.3.5/Makefile.Linux0000644000175000017500000000131007575071232015520 0ustar msmakelamsmakela### Target-specific definitions for compiling Maria -*- makefile -*- ### Linux and GNU Compiler Collection (2.95, 3.0 and 3.2) ## The GNU Readline library (if enabled, check also the directories) HAS_READLINE = yes #HAS_READLINE = LIBREADLINE = $(HAS_READLINE:yes=-L/usr/local/lib -lreadline -lncurses) INCREADLINE = $(HAS_READLINE:yes=-I/usr/local/include -DHAS_READLINE) ## Support for compiled expressions EXPR_COMPILE = yes #EXPR_COMPILE = CXX = g++ CC = gcc EXTRA_INCLUDES = EXTRA_LIBS = -ldl# -lstlport DEFINES = -DHAS_REGEX -D_GNU_SOURCE -DHAS_GETOPT_LONG CFLAGS = -Wall -ansi -pedantic -O3 CXXFLAGS = $(CFLAGS) -Iport -fno-exceptions -fno-rtti# -I/usr/include/stlport all: real-all include Makefile maria-1.3.5/Makefile.OSF10000644000175000017500000000212107574121225015127 0ustar msmakelamsmakela### Target-specific definitions for compiling Maria -*- makefile -*- ### Digital C++ compiler (last tested with v6.5-028) ## The GNU Readline library (if enabled, check also the directories) HAS_READLINE = yes HAS_READLINE = LIBREADLINE = $(HAS_READLINE:yes=-L/usr/local/lib -lreadline -lncurses) INCREADLINE = $(HAS_READLINE:yes=-I/usr/local/include -DHAS_READLINE) ## Support for compiled expressions EXPR_COMPILE = yes #EXPR_COMPILE = ## Digital C++ compiler CXX = cxx CC = cc EXTRA_INCLUDES = EXTRA_LIBS = DEFINES = -DHAS_REGEX -D_POSIX_PII CFLAGS = -arch host -tune host -assume trusted_short_alignment -assume noptrs_to_globals -compress -w1 -std strict_ansi_errors CXXFLAGS = $(CFLAGS) -Iport -nocleanup -nortti ## Note that static linking disables the use of EXPR_COMPILE, ## as statically linked executables cannot successfully invoke dlopen() #LDFLAGS = -non_shared -om ## GNU Compiler Collection 3.2.1 (same DEFINES as above) #CXX = g++ #CC = gcc #EXTRA_INCLUDES = #CFLAGS = -Wall -ansi -pedantic# -O3 #CXXFLAGS = $(CFLAGS) -Iport -fno-exceptions -fno-rtti all: real-all include Makefile maria-1.3.5/Makefile.SunOS0000644000175000017500000000167107574121225015437 0ustar msmakelamsmakela### Target-specific definitions for compiling Maria -*- makefile -*- ### SunOS 5.x (Solaris) and GNU Compiler Collection (2.95.x and 3.0.x) ## The GNU Readline library (if enabled, check also the directories) HAS_READLINE = yes #HAS_READLINE = LIBREADLINE = $(HAS_READLINE:yes=-L/usr/local/lib -lreadline -ltermcap) INCREADLINE = $(HAS_READLINE:yes=-I/usr/local/include -DHAS_READLINE) ## Support for compiled expressions EXPR_COMPILE = yes #EXPR_COMPILE = CXX = g++ CC = gcc EXTRA_INCLUDES = EXTRA_LIBS = -ldl -lnsl -lsocket DEFINES = -DHAS_REGEX CFLAGS = -Wall -pedantic -O3 CXXFLAGS = $(CFLAGS) -Iport -fno-exceptions -fno-rtti ## The following is for Sun WorkShop 6 update 2 C 5.3 2001/05/15 # CXX = CC # CC = cc # DEFINES = -DHAS_REGEX -D__EXTENSIONS__ # CFLAGS = -fast -xtarget=native64 # CXXFLAGS = $(CFLAGS) -Iport -features=no%except # LDFLAGS = -Qoption ld -64 -xarch=v9 -M /usr/lib/ld/sparcv9/map.above4G all: real-all include Makefile maria-1.3.5/Makefile.win320000644000175000017500000000157707574121225015377 0ustar msmakelamsmakela### Target-specific definitions for compiling Maria -*- makefile -*- ### GNU Compiler Collection 2.95 for mingw-msvcrt, compiled on Linux ## No GNU Readline library HAS_READLINE = LIBREADLINE = INCREADLINE = ## No support for compiled expressions EXPR_COMPILE = ## Use built-in LTL formula translator BUILTIN_LTL = yes ## Location where the cross-compiler has been installed PATH := /usr/local/cross-tools/bin:/usr/local/cross-tools/i386-mingw32msvc/bin:$(PATH) CXX = g++ CC = gcc EXPR_COMPILE = EXTRA_INCLUDES = EXTRA_LIBS = -liberty -lwsock32 DEFINES = -D__THROW_BAD_ALLOC='abort()' -DYY_NEVER_INTERACTIVE ## Cygwin (gcc-2.95) on Windows #EXTRA_LIBS = #DEFINES = -D__THROW_BAD_ALLOC='abort()' -DHAS_GETOPT_LONG CFLAGS = -Wall -ansi -pedantic -O3 CXXFLAGS = $(CFLAGS) -Iport -fno-exceptions -fno-rtti all: maria.exe maria.exe: maria cp maria maria.exe strip maria.exe include Makefile maria-1.3.5/NEWS0000644000175000017500000002121310272505744013463 0ustar msmakelamsmakelaMaria NEWS -- history of user-visible changes. 29th July 2005 Copyright © 2002,2003,2004,2005 Marko Mäkelä See the end for copying conditions. * Maria 1.3.5 is a maintenance release with performance and portability fixes ** Identified performance bottlenecks with OProfile on GNU/Linux x86 *** Wrote non-looping log() functions for systems with 32-bit card_t. The function is 2 to 3 times faster than the original. This improvement may reduce the time for state space exploration by a couple of percent. *** In interpreter-based operation, dynamic memory management consumes almost half the execution time. This is a fundamental problem of the expression evaluator, which makes extensive use of dynamic memory allocation. *** In compiler-based operation, decoding and encoding states may consume 80% of the time spent in compiled code, depending on the data types used in place markings and the number and complexity of the transitions. This may amount to 10-20% of the total execution time, depending on the state storage method and other options chosen. *** The built-in LTL formula translator has been updated to lbt-1.2.2. ** Portability fixes *** Replaced the non-standard slist template with std::list. ** Bug fixes *** The output of error traces in graphless search leaked memory. *** Memory could be leaked when an error was detected during transition instance analysis. *** Transition identifiers were improperly encoded by generated C code in modular state space exploration. *** The output of "dump" differed from "visual dump". Thanks to Charles Lakos for pointing out the problem. * Maria 1.3.4 is a maintenance release with bug fixes mainly for modular state space exploration ** New features *** The C code generator supports modular nets. *** The graphical browser (maria-vis) supports multiple modular state spaces. ** Bug fixes *** Clearing the common subexpression cache caused problems with modular nets. It is not cleared any more. *** The root node of B-trees was split incorrectly when USE_MMAP is disabled. *** The lexical order of marking expressions was not total. Now it should be. *** "reject" states will not be expanded by default. In graph-based analysis, the "succ" command will still expand them. *** If an error occurs in a prioritised transition, transitions with other priority levels will not be explored. In other words, the faulty transition instance is treated as if it were enabled, although it does not generate any successor state. *** LSTS output is now disabled for modular state spaces. *** Modular nets are implicitly flattened in the following circumstances: **** non-modular state space exploration **** unfolding **** pretty-printing ("dump" command) *** In modular nets, the synchronisation transition can now have input and output arcs and define functions. Thanks to Charles Lakos for contributing an elegant patch. *** Transitions in modules can now synchronise on multiple labels. *** Graph files can now be reopened also when memory-mapped I/O is not used. In other words, the -g option now works on Win32. * Maria 1.3.3 is a maintenance release mainly with improved portability. ** Bug fixes *** Possible memory leak in the computation of strongly connected components ** New targets *** Debian GNU/Linux on Digital Alpha *** Debian GNU/Linux on HP-PA *** IBM AIX 4.3.2 with gcc 3.2.1 (use Makefile.BSD) * Maria 1.3.2 is a maintenance release mainly with Win32 improvements. ** New features *** The [VISUAL] DUMPGRAPH command exports the reachability graph. ** Bug fixes *** The -Y option fix in Maria 1.3.1 introduced another bug. It is now fixed. ** Win32 inter-process communication bug work-arounds *** lbt 1.2.1 is built-in when the compile-time option BUILTIN_LTL is enabled. *** The "visual" commands write the graphs to a file "maria-vis.out". * Maria 1.3.1 is a maintenance release mainly with bug fixes and optimisations. ** Optimisations *** The generated of the C code was slightly optimised. *** Multi-set operations (SetExpression) are simplified and canonised. ** New targets *** HP-UX 11.22 with aCC: HP ANSI C++/C B3910B A.05.36 [May 20 2002] *** FreeBSD, NetBSD, OpenBSD with gcc 2.95 (Makefile.BSD) ** Bug fixes *** Modular analysis did not really work. Now the supplied "modular.pn" works. *** Comparisons "A subset B" with A==empty did not always work. *** Multi-set operations can now be used on input arcs. *** The -Y option now produces correct arc labels for reachability graphs. *** Memory leaks in transition fusion code were eliminated. * Maria 1.3 ** New features *** Automatic interruption at too many errors (-t, --tolerance=NUMBER) *** Modular analysis (-R, --modular) of nested SUBNETs reduces state spaces. The synchronisation labels for transitions are indicated with transition fusion. Each transition participating in a synchronisation must "call" the "label" transition in its parent net. ** Bug fixes *** "deadlock true" in an empty net (broken in version 1.1) works again * Maria 1.2 ** New features *** Added options for transition declarations **** Constantly disabled transition instances belonging to an ENABLED set are reported at the end of each state space exploration run. The enabledness sets are defined in an analogous way to fairness sets. **** The HIDE keyword controls the omission of hidden states (-Y). States that are reached via a hidden transition instance are omitted from the state space, but safety properties are checked also in such states. With some knowledge in the application, this reduction easily outperforms path compression (-Z). **** Prioritised transitions can share priority classes **** Transition fusion eases the modular construction of models *** Rewritten interfaces for generating state spaces **** All reductions can also be applied to reachability graphs, and with some caution to general LTL model checking. **** The executable has become smaller. ** Bug fixes *** Transitions accept "fatal" and "undefined" in gate expressions *** Multi-set quantification conditions are now allocated properly * Maria 1.1 ** New features *** Improved checker for safety properties **** Properties can be input as finite automata (translated from LTL). **** Counterexample traces are generated from the initial state to the error. **** Lossless storage of the reachable state set (option -L) avoids omissions. **** Path compression reduction (option -Z) minimises the memory usage. **** Works on multi-processor computers (-j) and TCP/IP networks (-k). *** Statistics for encoded state vector sizes are maintained and reported. *** The multiplicity mapping operation for multi-sets was made more generic. ** Bug fixes *** C code generation **** The generated code was made compatible with the IRIX and Darwin. **** The translation errors for multi-set mappings were corrected. *** The n-ary selection operator ?: now handles multi-sets. ** The following targets have been successfully tested: *** Apple Darwin 5.3 (Mac OS X 10.1) *** Digital UNIX 4.0F (cxx V6.3-010) *** GNU/Linux on IA-32 (GCC 2.95.4 and GCC 3.0.4) *** SGI IRIX 6.5 **** GCC (32-bit) **** native CC -n32 or CC -64 *** SunOS 5.x (Solaris) **** GCC (32-bit) **** Sun WorkShop 6 update 2 C 5.3 2001/05/15 for sparcv9 (64-bit) *** Win32 (GCC 2.95.2 for mingw or Cygwin) * Maria 1.0.1 is a maintenance release mainly with bug fixes and optimisations. ** Additions to the query language *** The PRED! and SUCC! commands list all predecessors or successors of a state until a branch is found, making it easier to follow deterministic behaviour. *** Anonymous transitions can be fired in the reachability graph. ** Bug fixes *** States may now have more than 65535 successors. *** Some bugs in the liveness property checker were fixed. *** Functions can take multi-sets as parameters. ** New targets *** The Sun compiler is now supported. *** Preliminary support for SGI IRIX was added. ** Optimisations *** The computation of strongly connected components was optimised. *** The liveness property checker was slightly optimised. * Maria 1.0 was the first official release. ---------------------------------------------------------------------- Copyright information: Copyright © 2002,2003,2004,2005 Marko Mäkelä Permission is granted to anyone to make or distribute verbatim copies of this document as received, in any medium, provided that the copyright notice and this permission notice are preserved, thus giving the recipient permission to redistribute in turn. Permission is granted to distribute modified versions of this document, or of portions of it, under the above conditions, provided also that they carry prominent notices stating who last changed them. Local variables: mode: outline paragraph-separate: "[ ]*$" end: maria-1.3.5/foldname.pl0000755000175000017500000000115407321053045015104 0ustar msmakelamsmakela#!/usr/bin/perl # Convert unfolded place and transition names to more readable format while (<>) { s/\b(TR|PL)_([A-Za-z0-9_]*)\b/&demangle($2)/ego; print; } # Demangle an unfolded place or transition name sub demangle () { my($name) = @_; my(@names) = split ("__", $name); map { s/_([0-9A-Fa-f]{2})/pack ("C", hex "$1")/ge } @names; $name = shift @names; if ($#names >= 0) { my($delim) = "<"; while ($#names >= 0) { $name .= $delim . (shift @names); last unless ($#names >= 0); $name .= ":" . (shift @names); $delim = "," } $name .= ">"; } return $name; } maria-1.3.5/maria-cso0000755000175000017500000000622207575067103014574 0ustar msmakelamsmakela#!/bin/sh ## Compile and link the modules in the specified directory to a shared library ## Location of the header files (adjust this to an absolute path) INCLUDES="-I./Compilation/runtime" ## Definitions to pass to the C compiler ## RED_BLACK: ## keep multi-sets in red-black trees instead of unbalanced trees ## (useful if the places in the net have more than a few tokens) ## NO_INVARIANT_CHECK(p) ## even if the (p+1)th place defined in the net ## has a marking-dependent initialization expression, ## do not check its validity when encoding markings ## (use only if you are sure that the invariants hold) ## TRANSITION_EMPTY(t) ## before instance analysis, check whether any of the inputs ## has an insufficient number of tokens for the (t+1)th transition ## defined in the net to be enabled ## (may be useful for seldomly enabled transitions) #: ${DEFINES="-DRED_BLACK"} #: ${DEFINES="-DRED_BLACK -D'NO_INVARIANT_CHECK(p)=1'"} : ${DEFINES="-DRED_BLACK -D'TRANSITION_EMPTY(t)=1' -D'NO_INVARIANT_CHECK(p)=1'"} ## Function to execute compiler and linker commands perform() { eval "$@" || exit $?; } #perform() { echo "$@" >&2; eval "$@" || exit $?; } set -eu <&- case "`uname`" in Linux|FreeBSD|NetBSD|OpenBSD) : ${CC="gcc"} : ${CFLAGS="-ansi -O3 -fomit-frame-pointer"} : ${LD="ld"} : ${LDFLAGS="-shared -s -lc"} ;; AIX) : ${CC="gcc"} : ${CFLAGS="-ansi -O3 -fomit-frame-pointer"} : ${LD="gcc"} : ${LDFLAGS="-shared -s -lc"} ;; OSF1) : ${CC="cc"} : ${CFLAGS="-arch host -assume trusted_short_alignment -O5 -std1"} : ${LD="ld"} : ${LDFLAGS="-shared -s -lc"} ;; HP-UX) : ${CC="cc"} : ${CFLAGS="-fast"} : ${LD="ld"} : ${LDFLAGS="-b -s -lc"} ;; SunOS) : ${CC="gcc"} : ${CFLAGS="-ansi -Werror -O3 -fomit-frame-pointer"} : ${LD="ld"} : ${LDFLAGS="-G -s -lc"} ;; IRIX64) : ${CC="cc"} : ${CFLAGS="-n32 -O2"} : ${LD="ld"} : ${LDFLAGS="-n32 -shared -s -lc"} ;; Darwin) : ${CC="cc"} : ${CFLAGS="-ansi -O3 -fomit-frame-pointer -fno-common"} : ${LD="ld"} : ${LDFLAGS="-dynamic -bundle -lbundle1.o -lc"} ;; *) echo "Unknown operating system." >&2 exit 1 ;; esac DIR="${1:-}" LIB="${2:-}" [ $# -ge 2 -a -d "$DIR" ] || \ { echo "Usage: $0 directory library.so source1.c source2.c ..." >&2 exit 1 } shift 2 if [ $# -eq 1 ] then i="`basename "$1" .c`" perform $CC $DEFINES $CFLAGS -I"$DIR" $INCLUDES \ -c "$DIR/$i.c" -o "$DIR/$i.o" perform $LD -o "$LIB" "$DIR/$i.o" $LDFLAGS exit fi ( cd "$DIR" cksum mset.h > mset.sum1 cmp -s mset.sum mset.sum1 || rm -f c.sum || exit $? mv -f mset.sum1 mset.sum cksum "$@" > c.sum1 touch c.sum ) || exit $? diff "$DIR/c.sum" "$DIR/c.sum1" \ | sed -ne 's/^> [0-9]*[ ]*[0-9]*[ ]*\(.*\)\.c$/\1/p' \ | { NEED_LINK="" while read i do perform $CC $DEFINES $CFLAGS -I"$DIR" $INCLUDES \ -c "$DIR/$i.c" -o "$DIR/$i.o" NEED_LINK=true done mv -f "$DIR/c.sum1" "$DIR/c.sum" if [ -n "$NEED_LINK" -o ! -f "$LIB" ] then perform $LD -o "$LIB" `sed -ne '{i\\ '"$DIR/"' s/[0-9]*[ ]*[0-9]*[ ]*\(.*\)\.c$/\1.o /p }' < "$DIR/c.sum" | tr -d \\\\012` $LDFLAGS fi } maria-1.3.5/maria-cso.10000644000175000017500000000516307523433307014727 0ustar msmakelamsmakela.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH MARIA-CSO 1 "August 10, 2001" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME maria-cso \- shared library generator for maria .SH SYNOPSIS .B maria-cso .RI "" directory " " library.so " " \(file\fB.c\fP ... .br .B maria-cso .RI "" directory " " library.so " " \(file\fB.c\fP .SH DESCRIPTION This manual page documents brie\(fly the .B maria-cso command. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBmaria-cso\fP is a shell script invoked by \fBmaria\fP in order to compile generated C code into dynamically loadable shared object \(files. The script invokes the C compiler and the linker, and it calculates checksums in order to avoid compiling unmodi\(fied modules. .br The \fIdirectory\fP argument speci\(fies the location of the source \(files. When the script is invoked with one \fI\(file\fP\fB.c\fP argument, it translates the \(file to the shared object \fIlibrary.so\fP. .br When \fBmaria-cso\fP is invoked with multiple \fI\(file\fP\fB.c\fP arguments, it computes a checksum of a \(file named \fBmultiset.h\fP and of each argument. When the header \(file \fBmultiset.h\fP has been changed since the previous invocation of \fBmaria-cso\fP, everything will be recompiled. Otherwise only those \fI\(file\fP\fB.c\fP modules that have been modified will be recompiled. The checksum \(files are \fBmultiset.sum\fP and \fBc.sum\fP. .SH SEE ALSO .BR maria (1), .BR sh (1). .SH ENVIRONMENT VARIABLES .TP .I CC Name of the C compiler .TP .I CFLAGS Command-line switches to be passed to the C compiler .TP .I DEFINES Preprocessor macro definitions to be passed to the C compiler .SH FILES .TP .I /usr/share/maria/runtime/*.h Header files for the run-time library .SH AUTHOR This manual page was written by Marko M\(:akel\(:a . The \fBmaria-cso\fP script and the compilation option were designed and implemented by .B Marko M\(:akel\(:a. Please see the copyright file in .I /usr/share/doc/maria for details. maria-1.3.5/maria-vis0000755000175000017500000001545707674542430014624 0ustar msmakelamsmakela#!/usr/local/bin/lefty # This is a graphical user interface for maria(1). # It requires the lefty interpreter and the dotty*.lefty scripts of GraphViz. # # This script was written in 2001 by Marko Mäkelä , # and it is in the public domain. See maria-vis(1) for documentation. # The "subnet" commands (support for modular state spaces) were added in 2003. load ('dotty.lefty'); checkpath = function () { if (tablesize (dotty) > 0) { remove ('checkpath'); } else { writeline (2, 'cannot locate the dotty scripts'); exit (); } }; checkpath (); monitorfile = function (data) { local line; if (~data.fd) { if (~(line = readline (0))) exit (); run (line); return 1; } return dotty.monitorfile (data); }; maria.init = function () { dotty.init (); maria.protovt = [ 'name' = 'Maria Browser'; 'type' = 'normal'; 'menus' = [ 'general' = [ 0 = "undo (u)"; 1 = "command (c)"; 2 = "horizontal layout (h)"; 3 = "vertical layout (v)"; 4 = "cancel layout (k)"; 5 = "redraw ( )"; 6 = "save graph as (s)"; 7 = "copy view"; 8 = "clone view"; 9 = "zoom in (Z)"; 10 = "zoom out (z)"; 11 = "quit (q)"; ]; 'node' = [ 0 = "successors (n)"; 1 = "predecessors (p)"; 2 = "path (P)"; 3 = "delete (d)"; 4 = "Delete (D)"; 5 = "open view (o)"; ]; 'edge' = [ 0 = "delete (d)"; 1 = "Delete (D)"; 2 = "open view (o)"; ]; ]; 'keys' = [ 'general' = [ 'u' = "undo (u)"; 'c' = "command (c)"; 'h' = "horizontal layout (h)"; 'v' = "vertical layout (v)"; 'k' = "cancel layout (k)"; ' ' = "redraw ( )"; 's' = "save graph as (s)"; 'Z' = "zoom in slowly"; 'z' = "zoom out slowly"; 'q' = "quit (q)"; ]; 'node' = [ 'd' = "delete (d)"; 'D' = "Delete (D)"; 'o' = "open view (o)"; 'n' = "successors (n)"; 'p' = "predecessors (p)"; 'P' = "path (P)"; ]; 'edge' = [ 'd' = "delete (d)"; 'D' = "Delete (D)"; 'o' = "open view (o)"; ]; ]; 'uifuncs' = [ 'closeview' = function (data) { maria.gt = null; dotty.protovt.normal.uifuncs.closeview (data); }; 'keyup' = function (data) { maria.gt = dotty.graphs[dotty.views[data.widget].gtid]; dotty.protovt.normal.uifuncs.keyup (data); }; 'rightdown' = function (data) { maria.gt = dotty.graphs[dotty.views[data.widget].gtid]; dotty.protovt.normal.uifuncs.rightdown (data); }; 'middledown' = function (data) { maria.gt = dotty.graphs[dotty.views[data.widget].gtid]; if (data.obj.nid >= 0) writeline (1, concat ("subnet ", maria.gt.graph.name, "; visual visual pred ", data.obj.name)); }; 'leftdown' = function (data) { maria.gt = dotty.graphs[dotty.views[data.widget].gtid]; if (data.obj.nid >= 0) writeline (1, concat ("subnet ", maria.gt.graph.name, "; visual visual succ ", data.obj.name)); }; 'redraw' = function (data) { maria.gt = dotty.graphs[dotty.views[data.widget].gtid]; dotty.protovt.normal.uifuncs.redraw (data); }; ]; ]; maria.protogt = [ 'actions' = [ 'general' = [ "undo (u)" = function (gt, vt, data) { gt.undo (gt, 1); maria.gt = gt; }; "command (c)" = function (gt, vt, data) { writeline (1, ask ("command")); maria.gt = gt; }; "horizontal layout (h)" = function (gt, vt, data) { gt.graph.graphattr.rankdir = 'LR'; gt.layoutgraph (gt); maria.gt = gt; }; "vertical layout (v)" = function (gt, vt, data) { gt.graph.graphattr.rankdir = 'TB'; gt.layoutgraph (gt); maria.gt = gt; }; "cancel layout (k)" = function (gt, vt, data) { gt.cancellayout (gt); maria.gt = gt; }; "redraw ( )" = function (gt, vt, data) { gt.redrawgraph (gt, [vt.vtid = vt;]); maria.gt = gt; }; "save graph as (s)" = function (gt, vt, data) { gt.savegraph (gt, null, 'file', 1); maria.gt = gt; }; "copy view" = function (gt, vt, data) { gt = gt.copygraph (gt); gt.createview (gt, vt); maria.gt = gt; }; "clone view" = function (gt, vt, data) { gt.createview (gt, vt); maria.gt = gt; }; "zoom in (Z)" = function (gt, vt, data) { gt.zoom (gt, vt, 0.5, data.pos); maria.gt = gt; }; "zoom out (z)" = function (gt, vt, data) { gt.zoom (gt, vt, 2, data.pos); maria.gt = gt; }; "zoom in slowly" = function (gt, vt, data) { gt.zoom (gt, vt, 0.9, data.pos); maria.gt = gt; }; "zoom out slowly" = function (gt, vt, data) { gt.zoom (gt, vt, 1.1, data.pos); maria.gt = gt; }; "quit (q)" = function (gt, vt, data) { exit (); }; ]; 'node' = [ "successors (n)" = function (gt, vt, obj, data) { if (obj.nid >= 0) writeline (1, concat ("subnet ", maria.gt.graph.name, "; visual visual succ ", obj.name)); maria.gt = gt; }; "predecessors (p)" = function (gt, vt, obj, data) { if (obj.nid >= 0) writeline (1, concat ("subnet ", maria.gt.graph.name, "; visual visual pred ", obj.name)); maria.gt = gt; }; "path (P)" = function (gt, vt, obj, data) { if (obj.nid >= 0) writeline (1, concat ("subnet ", maria.gt.graph.name, "; visual visual path ", obj.name)); maria.gt = gt; }; "delete (d)" = function (gt, vt, obj, data) { if (obj.eid >= 0) gt.removeedge (gt, obj); else gt.removenode (gt, obj); gt.redrawgraph (gt, gt.views); maria.gt = gt; }; "Delete (D)" = function (gt, vt, obj, data) { gt.removesubtree (gt, obj); gt.redrawgraph (gt, gt.views); maria.gt = gt; }; "open view (o)" = function (gt, vt, obj, data) { local mode; if (obj.nid >= 0) mode = null; else mode = 'support'; gt.cut (gt, obj, 'one', mode, 'copy'); gt = dotty.protogt.creategraph (maria.protogt); gt.createview (gt, maria.protovt); gt.mergegraph (gt, dotty.clipgt.graph, 0); gt.layoutgraph (gt); maria.gt = gt; }; ]; ]; ]; maria.protogt.actions.edge = maria.protogt.actions.node; maria.gt = null; dotty.protogt.layoutmode = 'async'; dotty.mlevel = 0; monitor ('on', 0); }; new = function () { maria.gt = dotty.protogt.creategraph (maria.protogt); maria.gt.createview (maria.gt, maria.protovt); maria.gt.loadgraph (maria.gt, '-', 'file', copy (dotty.protogt.graph), 1); }; add = function () { local gt, nameid, nid, node; gt = dotty.protogt.creategraph (maria.protogt); if (maria.gt == null) { maria.gt = gt; gt.createview (gt, maria.protovt); gt.loadgraph (gt, '-', 'file', copy (dotty.protogt.graph), 0); } else { gt.loadgraph (gt, '-', 'file', copy (dotty.protogt.graph), 0); for (nameid in gt.graph.nodedict) { nid = maria.gt.graph.nodedict[nameid]; if (nid >= 0) { node = maria.gt.graph.nodes[nid]; node.attr = copy (gt.graph.nodes[gt.graph.nodedict[nameid]].attr); maria.gt.unpacknodeattr (maria.gt, node); nid = -1; } } maria.gt.mergegraph (maria.gt, gt.graph, 0); } maria.gt.layoutgraph (maria.gt); }; monitorfile = maria.monitorfile; maria.init (); txtview ('off'); maria-1.3.5/maria-vis.10000644000175000017500000000414607523433316014744 0ustar msmakelamsmakela.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH MARIA-VIS 1 "August 10, 2001" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME maria-vis \- graph visualization script for maria .SH SYNOPSIS .B maria-vis .SH DESCRIPTION This manual page documents brie\(fly the .B maria-vis command. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBmaria-vis\fP is a \fBlefty\fP script invoked by \fBmaria\fP in order to visually present information to the user. The script reads commands and directives from standard input and may write \fBmaria\fP query language commands to standard output. An end-of-file condition on standard input terminates the script. .br The script is built on top of the \fBdotty\fP script that is part of the GraphViz package. The commands prefixed with \fBvisual\fP in \fBmaria\fP issue two kinds of commands to this script: \fInew();\fP or \fIadd();\fP followed by a newline character and a graph definition in the \fBdot\fP input language. The \fInew\fP function in the script displays the graph in a new window, while the \fIadd\fP function copies information from the graph to the last modified graph. .SH SEE ALSO .BR dot (1), .BR dotty (1), .BR lefty (1), .BR maria (1). .SH AUTHOR This manual page was written by Marko M\(:akel\(:a . The \fBmaria-vis\fP script and the visualization option were designed and implemented by .B Marko M\(:akel\(:a. Please see the copyright file in .I /usr/share/doc/maria for details. maria-1.3.5/maria-vis.tcl0000755000175000017500000002164707314375504015400 0ustar msmakelamsmakela#!/bin/sh # next line is a comment in tcl \ exec wish8.3 "$0" ${1+"$@"} package require Tkspline package require Tcldot # Maria reachability graph visualizer # by Marko Mäkelä (msmakela@tcs.hut.fi) # based on the DotEd demo and feedback from John Ellson (ellson@lucent.com) global saveFill tk_library g # as the mouse moves over an object change its shading proc mouse_anyenter {c} { global tk_library saveFill set item [string range [lindex [$c gettags current] 0] 1 end] set saveFill [list $item [lindex [$c itemconfigure 1$item -fill] 4]] $c itemconfigure 1$item -fill black \ -stipple @$tk_library/demos/images/gray25.bmp } # as the mouse moves out of an object restore its shading proc mouse_anyleave {c} { global saveFill $c itemconfigure 1[lindex $saveFill 0] \ -fill [lindex $saveFill 1] -stipple {} } # if button is pressed over a node, perform a command on it proc mouse_press {c x y cmd} { global g set x [$c canvasx $x] set y [$c canvasy $y] foreach item [$c find overlapping $x $y $x $y] { foreach tag [$c gettags $item] { if {[string first "node" $tag] == 1} { set l [[string range $tag 1 end] showname] puts "$cmd $l" return } } } } proc loadDirectory {w type} { if {$type != ""} {set type .$type} $w.d.entry delete 0 end $w.d.entry insert end [pwd] $w.d.l.list delete 0 end if {[pwd] != "/"} { $w.d.l.list insert end ".." } foreach i [lsort [glob -nocomplain *]] { if {[file isdirectory $i]} { $w.d.l.list insert end [file tail $i] } } $w.f.l.list delete 0 end foreach i [lsort [glob -nocomplain *$type]] { if {! [file isdirectory $i]} { $w.f.l.list insert end [file tail $i] } } } proc loadDirectory_list {w type x y} { cd [$w.d.l.list get @$x,$y] loadDirectory $w $type } proc loadDirectory_entry {w type} { cd [$w.d.entry get] loadDirectory $w $type } proc update_entry {w x y} { $w.entry delete 0 end $w.entry insert end [$w.l.list get @$x,$y] } proc positionWindow {w} { set pos [split [wm geometry .] +] set x [expr [lindex $pos 1] - 350] set y [expr [lindex $pos 2] + 20] wm geometry $w +$x+$y } proc saveFileByName {w name type} { if {[file exists $name]} { confirm "File exists. Shall I overwrite it?" \ "saveFileByNameDontAsk $w $name $type" } { saveFileByNameDontAsk $w $name $type } } proc saveFileByNameDontAsk {w name type} { global g if {[catch {open $name w} f]} { warning "Unable to open file for write:\n$name; return" } if {$type == "dot"} { set type canon } $g write $f $type close $f if {$w != {}} {destroy $w} message "Graph written to:\n$name" } proc saveFileByName_list {w x y type} { set dirName [$w.d.entry get] if {[catch {cd $dirName}]} { warning "No such directory:\n$dirName; return" } if {$dirName == "/"} {set dirName ""} saveFileByName $w $dirName/[$w.f.l.list get @$x,$y] $type } proc saveFileByName_entry {w type} { set dirName [$w.d.entry get] if {[catch {cd $dirName}]} { warning "No such directory:\n$dirName; return" } if {$dirName == "/"} {set dirName ""} saveFileByName $w $dirName/[$w.f.entry get] $type } proc saveFileAs {type} { set w .save catch {destroy $w} toplevel $w positionWindow $w wm title $w "Save Dot File" wm iconname $w "Save" frame $w.d label $w.d.label -text "Directory:" frame $w.d.l listbox $w.d.l.list -width 30 -height 10 -yscrollcommand "$w.d.l.scroll set" bind $w.d.l.list "loadDirectory_list $w $type %x %y; break" bind $w.d.l.list <1> "update_entry $w.d %x %y" scrollbar $w.d.l.scroll -command "$w.d.l.list yview" pack $w.d.l.list $w.d.l.scroll -side left -fill y -expand 1 frame $w.d.space1 -height 3m -width 20 entry $w.d.entry -width 30 frame $w.d.space2 -height 3m -width 20 button $w.d.cancel -text Cancel -command "destroy $w" bind $w.d.entry "loadDirectory_entry $w $type" pack $w.d.label $w.d.l $w.d.space1 $w.d.entry $w.d.space2 -side top -anchor w pack $w.d.cancel -side top frame $w.space -height 3m -width 3m frame $w.f label $w.f.label -text "File:" frame $w.f.l listbox $w.f.l.list -width 30 -height 10 -yscrollcommand "$w.f.l.scroll set" bind $w.f.l.list "saveFileByName_list $w %x %y $type; break" bind $w.f.l.list <1> "update_entry $w.f %x %y" scrollbar $w.f.l.scroll -command "$w.f.l.list yview" pack $w.f.l.list $w.f.l.scroll -side left -fill y -expand 1 frame $w.f.space1 -height 3m -width 20 entry $w.f.entry -width 30 frame $w.f.space2 -height 3m -width 20 button $w.f.load -text Save -command "saveFileByName_entry $w $type" bind $w.f.entry "saveFileByName_entry $w $type; break" pack $w.f.label $w.f.l $w.f.space1 $w.f.entry $w.f.space2 -side top -anchor w pack $w.f.load -side top pack $w.d $w.space $w.f -side left -fill y -expand true loadDirectory $w $type } proc confirm {msg cmd} { set w .confirm catch {destroy $w} toplevel $w positionWindow $w wm title $w "Confirm" wm iconname $w "Confirm" label $w.message -text "\n$msg\n" frame $w.spacer -height 3m -width 20 frame $w.buttons button $w.buttons.confirm -text OK -command "$cmd; destroy $w" button $w.buttons.cancel -text Cancel -command "destroy $w" pack $w.buttons.confirm $w.buttons.cancel -side left -expand 1 pack $w.message $w.spacer -side top -anchor w pack $w.buttons -side bottom -expand y -fill x -pady 2m } proc message {m} { set w .message catch {destroy $w} toplevel $w positionWindow $w wm title $w "Message" wm iconname $w "Message" label $w.message -text "\n$m\n" pack $w.message -side top -anchor w update after 2000 "destroy $w" } proc warning {m} { set w .warning catch {destroy $w} toplevel $w positionWindow $w wm title $w "Warning" wm iconname $w "Warning" label $w.message -text "\nWarning:\n\n$m" pack $w.message -side top -anchor w update after 2000 "destroy $w" } # lay the graph out proc layoutgraph {g c} { $c delete all $g layout eval [$g render $c] $c configure -scrollregion [$c bbox all] } proc parse {ch} { global g c set line [gets $ch] if {[eof $ch]} { exit } switch $line { "new();" { if {[catch {dotread $ch} g]} { puts stderr "maria-vis: invalid graph" } else { layoutgraph $g $c } } "add();" { if {[catch {dotread $ch} g2]} { puts stderr "maria-vis: invalid graph" } else { # merge the nodes foreach i [$g2 listnodes] { [$g addnode [$i showname]] setattributes \ [$i queryattributevalues [$i listattributes]] } # merge the edges foreach i [$g2 listedges] { foreach {t h} [$i listnodes] {break} [$g addedge [$t showname] [$h showname]] setattributes \ [$i queryattributevalues [$i listattributes]] } layoutgraph $g $c } } default { puts stderr "maria-vis: unrecognized cmd: $line" } } } set saveFill {} set g [dotnew digraph] wm title . "Maria Browser" wm iconname . "Maria" wm minsize . 50 100 wm geometry . 400x300 frame .m -relief raised -borderwidth 1 frame .a frame .b set c [canvas .a.c -cursor crosshair \ -xscrollcommand ".b.h set" \ -yscrollcommand ".a.v set" \ -width 0 \ -height 0 \ -borderwidth 0] bind $c <1> "mouse_press $c %x %y visual\\ visual\\ succ" bind $c <2> "mouse_press $c %x %y visual\\ visual\\ pred" $c bind all "mouse_anyenter $c" $c bind all "mouse_anyleave $c" scrollbar .b.h -orient horiz -relief sunken -command "$c xview" scrollbar .a.v -relief sunken -command "$c yview" menubutton .m.file -text "File" -underline 0 -menu .m.file.m menu .m.file.m .m.file.m add command -label "Save As ..." -underline 5 \ -command "saveFileAs dot" .m.file.m add separator .m.file.m add cascade -label "Export" -underline 1 \ -menu .m.file.m.export menu .m.file.m.export .m.file.m.export add command -label "PNG ..." -underline 0 \ -command "saveFileAs png" .m.file.m.export add command -label "GIF ..." -underline 0 \ -command "saveFileAs gif" .m.file.m.export add command -label "SVG ..." -underline 0 \ -command "saveFileAs svg" .m.file.m.export add command -label "ISMAP ..." -underline 0 \ -command "saveFileAs ismap" .m.file.m.export add command -label "HPGL ..." -underline 0 \ -command "saveFileAs hpgl" .m.file.m.export add command -label "MIF ..." -underline 0 \ -command "saveFileAs mif" .m.file.m.export add command -label "PCL ..." -underline 1 \ -command "saveFileAs pcl" .m.file.m.export add command -label "PostScript ..." -underline 0 \ -command "saveFileAs ps" .m.file.m add separator .m.file.m add command -label "Exit" -underline 0 -command "exit" pack append .m .m.file {left} pack append .a $c {left expand fill} .a.v {right filly} pack append .b .b.h {left expand fillx} pack append . .m {top fillx} .a {expand fill} .b {bottom fillx} tk_menuBar .m.file fileevent stdin readable "parse stdin" maria-1.3.5/maria.10000644000175000017500000002451007523433265014145 0ustar msmakelamsmakela.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH MARIA 1 "August 5, 2002" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME maria \- Modular Reachability Analyzer for high-level Petri nets .SH SYNOPSIS .B maria .RI [ options ] " \(files" ... .SH DESCRIPTION This manual page documents brie\(fly the .B maria command. More complete documentation is available in the GNU Info format; see below. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invoke bold face and italics, .\" respectively. \fBmaria\fP is a program that analyzes models of concurrent systems, described in its input language that is based on Algebraic System Nets. The formalism was presented by Ekkart Kindler and Hagen V\(:olzer at ICATPN'98, .IR "Flexibility in Algebraic Nets". .br Algebraic System Nets is a framework that does not de\(fine any data types or algebraic operations. The data type system and the operations in Maria are designed with high-level programming and speci\(fication languages in mind. Despite that, each Maria model has a \(finite unfolding. .br To ensure interoperability with low-level Petri net tools, Maria translates identi\(fiers in unfolded nets to strings of alpha-numerical characters and underscores. The \(filter \fBfoldname.pl\fP can be used or adapted to improve the readability of the identi\(fiers. .SH OPTIONS Maria follows the usual GNU command line syntax, with long options starting with two dashes (`\fB-\fP'). A summary of options is included below. For a complete description, see the Info \(files. .TP .B -a \fIlimit\fP, --array-limit=\fIlimit\fP Limit the size of array index types to \fIlimit\fP possible values. A limit of 0 disables the checks. .TP .B -b \fImodel\fP, --breadth-first-search=\fImodel\fP Generate the reachability graph of \fImodel\fP using breadth-\(first search. .TP .B -C \fIdirectory\fP, --compile=\fIdirectory\fP Generate C code in \fIdirectory\fP for evaluating expressions and for the low-level routines of the transition instance analysis algorithm. When this option is used, evaluation errors are reported in a slightly di\(fferent way. The interpreter displays the valuation and expression that caused the \(first error in a state; the compiled code displays the number of errors. For performance reasons, the generated code does not check for over\(flow errors when adding items to multi-sets. .TP .B -c, --no-compile The opposite of \fB-C\fP. Evaluate all expressions in the built-in interpreter. This is the default behavior. .TP .B -D \fIsymbol\fP, --define=\fIsymbol\fP De\(fine the preprocessor symbol \fIsymbol\fP. .TP .B -d \fImodel\fP, --depth-first-search=\fImodel\fP Generate the reachability graph of \fImodel\fP using depth-\(first search. .TP .B -E \fIinterval\fP, --edges=\fIinterval\fP When generating the reachability graph, report the size of the graph after every \fIinterval\fP generated edges. .TP .B -e \fIstring\fP, --execute=\fIstring\fP Execute \fIstring\fP. .TP .B -g \fIgraph\(file\fP, --graph=\fIgraph\(file\fP Load a previously generated reachability graph from \fIgraph\(file\fP\fB.rgh\fP. .TP .B -H \fIh\fP\fR[\fP,\fIf\fP\fR[\fP,\fIt\fP\fR]]\fP, --hashes=\fIh\fP\fR[\fP,\fIf\fP\fR[\fP,\fIt\fP\fR]]\fP Con\(figure the parameters for probabilistic veri\(fication (\fB-P\fP). Allocate \fIt\fP universal hash functions of \fIf\fP elements and corresponding hash tables of \fIh\fP bits each. Both \fIh\fP and \fIf\fP will be rounded up to next suitable values. .TP .B -?, -h, --help Print a summary of the command-line options to Maria and exit. .TP .B -I \fIdirectory\fP, --include=\fIdirectory\fP Append \fIdirectory\fP to the list of directories searched for include \(files. .TP .B -i \fIcolumns\fP, --width=\fIcolumns\fP Set the right margin of the output to \fIcolumns\fP. The default is 80. .TP .B -j \fIprocesses\fP, --jobs=\fIprocesses\fP When checking safety properties (options \fB-L\fP, \fB-M\fP and \fB-P\fP), use this many worker processes to speed up the analysis on a multiprocessor computer. See also \fB-k\fP and \fB-Z\fP. .TP .B -k \fIport\fP\fR[\fP/\fIhost\fP\fR]\fP, --connect=\fIport\fP\fR[\fP/\fIhost\fP\fR]\fP Distribute safety model checking (options \fB-L\fP, \fB-M\fP and \fB-P\fP) in a TCP/IP network. For the server, only \fIport\fP is speci\(fied as a 16-bit unsigned integer, usually between 1024 and 65535. For the worker processes, \fIport\fP\fB/\fP\fIhost\fP speci\(fies the port and the address of the server. See also \fB-j\fP. .TP .B -L \fImodel\fP, --lossless=\fImodel\fP Load \fImodel\fP and prepare for analyzing it by constructing a set of reachable states in disk \(files. See also \fB-M\fP, \fB-P\fP, \fB-j\fP and \fB-k\fP. .TP .B -m \fImodel\fP, --model=\fImodel\fP Load \fImodel\fP and clear its reachability graph. .TP .B -M \fImodel\fP, --md5-compacted=\fImodel\fP Load \fImodel\fP and prepare for analyzing it by constructing an over-approximation of set of reachable states in the main memory. See also \fB-P\fP, \fB-L\fP, \fB-j\fP and \fB-k\fP. .TP .B -N \fIc\fP\fIregexp\fP, --name=\fIc\fP\fIregexp\fP Specify the names allowed in context \fIc\fP as the extended regular expression \fIregexp\fP. The context is identi\(fied by the \(first character of the parameter string; the succeeding characters constitute the regular expression that allowed names must match. .TP .B -n \fIc\fP\fIregexp\fP, --no-name=\fIc\fP\fIregexp\fP Specify the names not allowed in context \fIc\fP as the extended regular expression \fIregexp\fP. .br If both \fB-N\fP and and \fB-n\fP are speci\(fied for a context \fIc\fP, then the allowing match takes precedence. For instance, to require that all user de\(fined type names be terminated with \fB_t\fP, specify \fB-nt -Nt'_t$'\fP. The quotes in the latter parameter are required to remove the special meaning from \fB$\fP in the command line shell you are probably using to invoke Maria. .TP .B -P \fImodel\fP, --probabilistic=\fImodel\fP Load \fImodel\fP and prepare for analyzing it by constructing a set of reachable states in the main memory by using a technique called \fIbitstate hashing\fP. .TP .B -p \fIcommand\fP, --property-translator=\fIcommand\fP Specify the command to use for translating property automata. The command should read a formula from the standard input and write a corresponding automaton description to the standard output. The translator \fBlbt\fP is compatible with this option. .TP .B -q \fIlimit\fP, --quantification-limit=\fIlimit\fP Prevent quanti\(fication (multi-set sum) of types having more than \fIlimit\fP possible values. A limit of 0 disables the checks. .TP .B -U \fIsymbol\fP, --undefine=\fIsymbol\fP Unde\(fine the preprocessor symbol \fIsymbol\fP. .TP .B -u \fR[\fP\fIa\fP\fR][\fP\fIf\fP\fR[\fP\fIout\(file\fP\fR]]\fP, --unfold=\fR[\fP\fIa\fP\fR][\fP\fIf\fP\fR[\fP\fIout\(file\fP\fR]]\fP Unfold the net using algorithm \fIa\fP and write it in format \fIf\fP to \fIout\(file\fP. If \fIout\(file\fP is not speci\(fied, dump the unfolded net to the standard output. Possible formats are \fBm\fP (Maria (human-readable), default), \fBl\fP (LoLA), \fBp\fP (PEP), and \fBr\fP (PROD). There are two algorithms: traditional (default) and reduced by constructing a \fIcoverable marking\fP (\fBM\fP). .TP .B -V, --version Print the version number of Maria and exit. .TP .B -v, --verbose Display verbose information on di\(fferent stages of the analysis. .TP .B -W, --warnings Enable warnings about suspicious net constructs. This is the default behavior. .TP .B -w, --no-warnings The opposite of \fB-W\fP. Disable all warnings. .TP .B -x \fInumberbase\fP, --radix=\fInumberbase\fP Specify the number base for diagnostic output. Allowed values for \fInumberbase\fP are \fBoct\fP, \fBoctal\fP, \fB8\fP, \fBhex\fP, \fBhexadecimal\fP, \fB16\fP, \fBdec\fP, \fBdecimal\fP and \fB10\fP. The default is to use decimal numbers. .TP .B -Y, --compress-hidden Reduce the set of reachable states by not storing the successor states of transitions instances for which a \fBhide\fP condition holds. The hidden successors are stored to a separate state set. This option may save memory (\fB-L\fP or \fB-m\fP) or reduce the probability that states are omitted (\fB-M\fP or \fB-P\fP), and it may improve the e\(Ficiency of parallel analysis (\fB-j\fP or \fB-k\fP), but it may also considerably increase the processor time requirement. The option also works with liveness model checking, but there is no guarantee that the truth values of liveness properties remain unchanged. This option can be combined with \fB-Z\fP. .TP .B -y, --no-compress-hidden The opposite of \fB-Y\fP. This is the default behavior. .TP .B -Z, --compress-paths Reduce the set of reachable states by not storing intermediate states that have at most one successor. This option may save memory (\fB-L\fP or \fB-m\fP) or reduce the probability that states are omitted (\fB-M\fP or \fB-P\fP), and it may improve the e\(Ficiency of parallel analysis (\fB-j\fP or \fB-k\fP), but it may also considerably increase the processor time requirement. The option also works with liveness model checking, but there is no guarantee that the truth values of liveness properties remain unchanged. This option can be combined with \fB-Y\fP. .TP .B -z, --no-compress-paths The opposite of \fB-Z\fP. This is the default behavior. .SH SEE ALSO .BR lbt (1), .BR maria-vis (1), .BR maria-cso (1). .SH FILES .TP .I /usr/share/maria/runtime/*.h The run-time library for the compilation option .TP .I /usr/share/doc/maria/foldname.pl Script for demangling identi\(fiers in unfolded net output .br The programs are documented fully by .IR "Maria" , available via the Info system. .SH AUTHOR This manual page was written by Marko M\(:akel\(:a . Maria was written by .B Marko M\(:akel\(:a, and some algorithms were designed by .B Kimmo Varpaaniemi, .B Timo Latvala and .B Emil Falck. Please see the copyright \(file in .I /usr/share/doc/maria for details. maria-1.3.5/Compilation/0000755000175000017500000000000010272511377015242 5ustar msmakelamsmakelamaria-1.3.5/Compilation/base/0000755000175000017500000000000010272511377016154 5ustar msmakelamsmakelamaria-1.3.5/Compilation/base/CExpression.C0000644000175000017500000003177507643253065020544 0ustar msmakelamsmakela// Auxiliary structure for compiling an expression -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "CExpression.h" #include "Variable.h" #include "VariableDefinition.h" #include "PlaceContents.h" #include "Net.h" #include "Transition.h" #include "Place.h" #include "Constant.h" #include "Value.h" #include "Type.h" #include /** @file CExpression.C * Auxiliary structure for compiling expressions */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Flag: generated the evaluating code for an expression */ #define FLAG_COMPUTED 1 /** Flag: generated conversion from an expression result to a number */ #define FLAG_CONVERTED 2 /** Flag: the expression is a multi-set */ #define FLAG_MULTISET 4 CExpression::CExpression (class StringBuffer& decl, const class Net& net, const class Transition* transition) : myNumVariables (0), myVariables (0), myFlags (0), myNumIterators (0), myIterators (0), myVarCount (false), myVarTmpCount (false), myFlag (false), myTmpFlag (false), myNumLabels (0), myValuation (0), myMultiset (0), myFatalError (0), myOut (), myDecl (decl), myNet (net), myTransition (transition) { } CExpression::~CExpression () { delete[] myVariables; delete[] myFlags; delete[] myIterators; } /** Get the built-in name of an expression if available * @param cexpr the compilation * @param expr the expression * @return translation for the expression, or NULL */ inline static char* getVariable (const class CExpression& cexpr, const class Expression& expr) { switch (expr.getKind ()) { case Expression::eEmptySet: return static_cast(memcpy (new char[2], "0", 2)); case Expression::ePlaceContents: return static_cast (expr).getPlace ().getMaxNumTokens () == 1 ? 0 : static_cast(expr).getName (cexpr); case Expression::eConstant: if (expr.getType ()->isLeaf ()) { const class Value& value = static_cast(expr).getValue (); class StringBuffer buf; value.compile (buf); return buf.copy (); } // fall through default: break; } return 0; } bool CExpression::getVariable (const class Expression& expr, char*& name) { if ((name = ::getVariable (*this, expr))) return false; unsigned i; if (expr.getKind () == Expression::eConstant) { for (i = myNet.getNumConstants (); i--; ) { if (&myNet.getConstant (i) == &expr) { snprintf (name = new char[22], 22, "c%u", i); return false; } } if (myTransition) { for (i = myTransition->getNumConstants (); i--; ) { if (&myTransition->getConstant (i) == &expr) { snprintf (name = new char[23], 23, "c_%u", i); return false; } } } } bool isNew = true; /** flag: generate a set-valued variable? */ bool isSet = expr.isSet (); if (expr.getKind () == Expression::eVariable) { const class VariableDefinition& var = static_cast(expr).getVariable (); for (i = myNumIterators; i--; ) { if (myIterators[i] == &var) { snprintf (name = new char[22], 22, "i%u", i); isNew = false; goto found; } } assert (!!myValuation); size_t len = strlen (myValuation); name = new char[len + 23]; memcpy (name, myValuation, len); snprintf (name + len, 23, var.isUndefined () ? ".y%u" : ".x%u", var.getNumber ()); } else name = 0; found: for (i = myNumVariables; i--; ) { if (myVariables[i] == &expr) { if (!name) snprintf (name = new char[22], 22, isSet ? "m%u" : "x%u", i); if (expr.getKind () != Expression::eVariable) isNew = !(myFlags[i] & FLAG_COMPUTED); myFlags[i] |= FLAG_COMPUTED; return isNew; } } if (myNumVariables) { const class Expression** variables = new const class Expression*[myNumVariables + 1]; memcpy (variables, myVariables, myNumVariables * sizeof *variables); delete[] myVariables; myVariables = variables; unsigned* flags = new unsigned[myNumVariables + 1]; memcpy (flags, myFlags, myNumVariables * sizeof *flags); delete[] myFlags; myFlags = flags; } else { myVariables = new const class Expression*[1]; myFlags = new unsigned[1]; } if (!name) snprintf (name = new char[22], 22, isSet ? "m%u" : "x%u", myNumVariables); myFlags[myNumVariables] = isSet ? FLAG_COMPUTED | FLAG_MULTISET : FLAG_COMPUTED; myVariables[myNumVariables++] = &expr; return isNew; } bool CExpression::getVariable (const class Constant& c, char*& name) { unsigned i; name = new char[22]; for (i = myNet.getNumConstants (); i--; ) { if (&myNet.getConstant (i) == &c) { snprintf (name, 22, "c%u", i); return false; } } if (myTransition) { for (i = myTransition->getNumConstants (); i--; ) { if (&myTransition->getConstant (i) == &c) { snprintf (name, 22, "c_%u", i); return false; } } } for (i = myNumVariables; i--; ) { if (myVariables[i] == &c) { snprintf (name, 22, "x%u", i); return !(myFlags[i] & FLAG_COMPUTED); } } if (myNumVariables) { const class Expression** variables = new const class Expression*[myNumVariables + 1]; memcpy (variables, myVariables, myNumVariables * sizeof *variables); delete[] myVariables; myVariables = variables; unsigned* flags = new unsigned[myNumVariables + 1]; memcpy (flags, myFlags, myNumVariables * sizeof *flags); delete[] myFlags; myFlags = flags; } else { myVariables = new const class Expression*[1]; myFlags = new unsigned[1]; } snprintf (name, 22, "x%u", myNumVariables); myFlags[myNumVariables] = FLAG_COMPUTED; myVariables[myNumVariables++] = &c; return true; } bool CExpression::getConverted (const class Expression& expr, char*& name) { assert (!expr.isSet ()); for (unsigned i = myNumVariables; i--; ) { if (myVariables[i] == &expr) { assert (!(myFlags[i] & FLAG_MULTISET)); snprintf (name = new char[22], 22, "n%u", i); bool result = myFlags[i] != FLAG_COMPUTED | FLAG_CONVERTED; myFlags[i] |= FLAG_CONVERTED; return result; } } assert (false); return false; } char* CExpression::getIterator (const class VariableDefinition& var) { assert (!var.getNumber ()); char* name = new char[22]; for (unsigned i = myNumIterators; i--; ) { if (myIterators[i] == &var) { snprintf (name, 22, "i%u", i); return name; } } if (myNumIterators) { const class VariableDefinition** iterators = new const class VariableDefinition*[myNumIterators + 1]; memcpy (iterators, myIterators, myNumIterators * sizeof *iterators); delete[] myIterators; myIterators = iterators; } else myIterators = new const class VariableDefinition*[1]; snprintf (name, 22, "i%u", myNumIterators); myIterators[myNumIterators++] = &var; return name; } char* CExpression::isIterator (const class VariableDefinition& var) const { for (unsigned i = myNumIterators; i--; ) { if (myIterators[i] == &var) { char* name = new char[22]; snprintf (name, 22, "i%u", i); return name; } } return 0; } void CExpression::recycle (const class Expression& expr1, const class Expression& expr2) { unsigned i; assert (expr1.getType () == expr2.getType ()); for (i = myNumVariables; i--; ) if (myVariables[i] == &expr2) return; for (i = myNumVariables; i--; ) if (myVariables[i] == &expr1) break; assert (i + 1); myVariables[i] = &expr2; myFlags[i] &= ~FLAG_COMPUTED; } unsigned CExpression::getCheckpoint (bool*& variables) const { variables = new bool[myNumVariables]; for (unsigned i = myNumVariables; i--; ) variables[i] = bool (myFlags[i] & FLAG_COMPUTED); return myNumVariables; } void CExpression::setCheckpoint (unsigned indent, const bool* variables, unsigned number, bool clear) { assert (number <= myNumVariables); register unsigned i; for (i = myNumVariables; i-- > number; ) { if (myFlags[i] & FLAG_COMPUTED && myVariables[i]->isSet ()) { myOut.indent (indent); myOut.append ("FREE (m"), myOut.append (i), myOut.append (");\n"); } if (clear) myFlags[i] &= ~FLAG_COMPUTED; } if (!number) return; for (; i; i--) { if (!variables[i]) { if (myFlags[i] & FLAG_COMPUTED && myVariables[i]->isSet ()) { myOut.indent (indent); myOut.append ("FREE (m"), myOut.append (i), myOut.append (");\n"); } if (clear) myFlags[i] &= ~FLAG_COMPUTED; } } } void CExpression::compileError (unsigned indent, enum Error error) { const char* err = 0; switch (error) { case errNone: err = "errNone"; break; case errConst: err = "errConst"; break; case errVar: err = "errVar"; break; case errUndef: err = "errUndef"; break; case errFatal: err = "errFatal"; break; case errDiv0: err = "errDiv0"; break; case errOver: err = "errOver"; break; case errMod: err = "errMod"; break; case errShift: err = "errShift"; break; case errUnion: err = "errUnion"; break; case errBuf: err = "errBuf"; break; case errCard: err = "errCard"; break; case errComp: err = "errComp"; break; } assert (!!err); /** flag: was any multi-set clean-up code generated? */ bool cleanup = false; for (unsigned i = 0; i < myNumVariables; i++) { if (myFlags[i] & FLAG_COMPUTED && myVariables[i]->isSet ()) { if (!cleanup) { myOut.indent (indent - 2), myOut.append ("{\n"); cleanup = true; } myOut.indent (indent); myOut.append ("FREE (m"), myOut.append (i), myOut.append (");\n"); } } myOut.indent (indent); if (error == errFatal && myFatalError) myOut.append (myFatalError); else myOut.append ("ERROR ("), myOut.append (err), myOut.append (");\n"); if (cleanup) myOut.indent (indent - 2), myOut.append ("}\n"); } void CExpression::compileCleanup (unsigned indent) { for (unsigned i = 0; i < myNumVariables; i++) { if (myFlags[i] & FLAG_COMPUTED && myVariables[i]->isSet ()) { myFlags[i] &= ~FLAG_COMPUTED; myOut.indent (indent); myOut.append ("FREE (m"), myOut.append (i), myOut.append (");\n"); } } } const char* CExpression::getVarCount () { return myVarCount = true, "count"; } const char* CExpression::getVarTmpCount () { return myVarTmpCount = true, "tcount"; } const char* CExpression::getFlag () { return myFlag = true, "flag"; } const char* CExpression::getTmpFlag () { return myTmpFlag = true, "flag2"; } char* CExpression::getLabel () { char* label = new char[22]; snprintf (label, 22, "l%u", ++myNumLabels); return label; } void CExpression::generate () { unsigned i; for (i = 0; i < myNumVariables; i++) { if (myFlags[i] & FLAG_CONVERTED) { myDecl.indent (2); myDecl.append ("card_t n"); myDecl.append (i); myDecl.append (";\n"); } switch (myVariables[i]->getKind ()) { case Expression::eVariable: case Expression::eEmptySet: continue; default: break; } myDecl.indent (2); if (myFlags[i] & FLAG_MULTISET) { myVariables[i]->getType ()->appendMSetName (myDecl); myDecl.append ("* m"); } else { myVariables[i]->getType ()->appendName (myDecl); myDecl.append (" x"); } myDecl.append (i); if (myFlags[i] & FLAG_MULTISET) myDecl.append (" = 0"); myDecl.append (";\n"); } if (myVarCount || myVarTmpCount) { myDecl.indent (2); myDecl.append ("card_t "); if (myVarCount) { myDecl.append (getVarCount ()); if (myVarTmpCount) { myDecl.append (", "); myDecl.append (getVarTmpCount ()); } } else myDecl.append (getVarTmpCount ()); myDecl.append (";\n"); } if (myFlag || myTmpFlag) { myDecl.indent (2); myDecl.append ("bool_t "); if (myFlag) { myDecl.append (getFlag ()); if (myTmpFlag) { myDecl.append (", "); myDecl.append (getTmpFlag ()); } } else myDecl.append (getTmpFlag ()); myDecl.append (";\n"); } myDecl.append (myOut); delete[] myVariables; delete[] myFlags; delete[] myIterators; myNumVariables = 0, myVariables = 0, myFlags = 0; myNumIterators = 0, myIterators = 0; myVarCount = myVarTmpCount = myFlag = myTmpFlag = false; myNumLabels = 0; myOut.create (0); } maria-1.3.5/Compilation/base/CExpression.h0000644000175000017500000001452007643253065020576 0ustar msmakelamsmakela// Auxiliary structure for compiling an expression -*- c++ -*- #ifndef CEXPRESSION_H_ # define CEXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ /** @file CExpression.h * Auxiliary structure for compiling expressions */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ # include "StringBuffer.h" # include "Error.h" /** Auxiliary structure for compiling an expression */ class CExpression { public: /** Constructor * @param decl output stream * @param net the net the expression belongs to * @param transition the transition the expression belongs to (optional) */ CExpression (class StringBuffer& decl, const class Net& net, const class Transition* transition); private: /** Copy constructor */ CExpression (const class CExpression& old); /** Assignment operator */ class CExpression& operator= (const class CExpression& old); public: /** Destructor */ ~CExpression (); /** Determine the valuation */ const char* getValuation () const { return myValuation; } /** Set the valuation */ void setValuation (const char* valuation) { myValuation = valuation; } /** Set the fatal error handler */ void setFatalError (const char* fatalError) { myFatalError = fatalError; } /** Determine the multi-set */ const char* getMultiset () const { return myMultiset; } /** Set the multi-set */ void setMultiset (const char* mset) { myMultiset = mset; } /** Declare an auxiliary variable for evaluating an expression * @param expr expression for the variable * @param name (output) name of the variable * @return whether this is a new declaration */ bool getVariable (const class Expression& expr, char*& name); /** Declare an auxiliary variable for a constant * @param c the constant * @param name (output) name of the variable * @return whether this is a new declaration */ bool getVariable (const class Constant& c, char*& name); /** Declare an auxiliary variable for converting an evaluated expression * @param expr expression for the variable * @param name (output) name of the variable * @return whether this is a new declaration */ bool getConverted (const class Expression& expr, char*& name); /** Declare an iterator variable * @param var the variable definition * @return name of the iterator variable */ char* getIterator (const class VariableDefinition& var); /** Determine whether an iterator variable exists * @param var the variable definition * @return name of the iterator variable, or NULL */ char* isIterator (const class VariableDefinition& var) const; /** Change the association of a variable from one expression to another * @param expr1 the old expression * @param expr2 the new expression */ void recycle (const class Expression& expr1, const class Expression& expr2); /** Determine which variables have been computed * @param variables placeholder for the table * @return number of elements in the table */ unsigned getCheckpoint (bool*& variables) const; /** Set the variables that have been computed * @param indent indentation level (for multi-set clean-up code) * @param variables truth table for variables that have been computed * @param number number of elements in the truth table * @param clear flag: clear the "computed" flags accordingly */ void setCheckpoint (unsigned indent, const bool* variables, unsigned number, bool clear = true); /** Emit code for reporting an error * @param indent indentation level * @param error the error code */ void compileError (unsigned indent, enum Error error); /** Emit code for cleaning up multi-set structures * @param indent indentation level */ void compileCleanup (unsigned indent); /** Get a multiplicity counter variable */ const char* getVarCount (); /** Get a temporary counter variable */ const char* getVarTmpCount (); /** Get a flag variable */ const char* getFlag (); /** Get a temporary flag variable */ const char* getTmpFlag (); /** Get a new label */ char* getLabel (); /** Get access to the output buffer */ class StringBuffer& getOut () { return myOut; } /** Emit the variable declarations and the code, and clear them */ void generate (); private: /** Number of generated variable declarations */ unsigned myNumVariables; /** Expressions for the generated variable declarations */ const class Expression** myVariables; /** Flags for the variables: 1=computed, 2=value-to-number, 4=multi-set */ unsigned* myFlags; /** Number of iterator variable declarations */ unsigned myNumIterators; /** Iterator variables */ const class VariableDefinition** myIterators; /** Flag: has a multiplicity counter been generated? */ bool myVarCount; /** Flag: has a temporary counter been generated? */ bool myVarTmpCount; /** Flag: has a flag variable been generated? */ bool myFlag; /** Flag: has a temporary flag variable been generated? */ bool myTmpFlag; /** Number of generated labels */ unsigned myNumLabels; /** The valuation */ const char* myValuation; /** The multi-set */ const char* myMultiset; /** Actions to perform on a fatal error */ const char* myFatalError; /** The generated statements */ class StringBuffer myOut; /** Additional declarations */ class StringBuffer& myDecl; /** The net the code belongs to */ const class Net& myNet; /** The transition the code belongs to */ const class Transition* myTransition; }; #endif // CEXPRESSION_H_ maria-1.3.5/Compilation/base/Compilation.C0000644000175000017500000006067407762612351020557 0ustar msmakelamsmakela// Compilation of types and expressions -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation # ifdef __sgi # define _POSIX_C_SOURCE 199309L # endif #endif // __GNUC__ #include "Compilation.h" #include "Net.h" #include "Place.h" #include "Transition.h" #include "Type.h" #include "CExpression.h" #include "Marking.h" #include "BitBuffer.h" #include "Property.h" #include "util.h" #include #include #include #include #include #include #include #include #include #include #include #include #if defined __APPLE__ /** External symbol */ # define E(s) "_" s #else /** External symbol */ # define E(s) s #endif #ifdef __OpenBSD__ # ifndef RTLD_NOW # define RTLD_NOW 0 # endif #endif /** Handle a child termination * @param pid process number of the terminated child */ extern "C" void childterm (pid_t pid); /** Handle a signal * @param num number of the signal */ extern "C" void sig (int num); /** @file Compilation.C * Interface to compiled code */ /* Copyright © 2000-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Compilation::Compilation (const class Net& net, const char* directory, const char* prefix) : myNet (net), myDirectory (directory), myPrefix (prefix), myHandle (0), myMsetClean (0), myEventClean (0), myEventClear (0), myEventAnalyzers (0), myEventInflater (0), myEventDeflater (0), myEventDecoder (0), myStateClean (0), myStateProject (0), myStateDecoder (0), myFatal (0), myFlattened (0), myAddState (0), mySyncState (0), myAddArcs (0), myFlat (0), myStateDeadlock (0), myWeaklyFair (0), myStronglyFair (0), myPropBits (0), myPropSucc (0), myPropHandle (0), myPropEval (0), myStateProps (0) { } Compilation::~Compilation () { unlink (); delete[] myEventAnalyzers; } /** Ensure that a directory exists * @param directory name of the directory * @return true if the directory exists or could be created */ bool dirExists (const char* directory) { if (!mkdir (directory, 0777)) return true; if (errno == EEXIST) { struct stat buf; if (!stat (directory, &buf) && S_ISDIR (buf.st_mode)) return true; errno = ENOTDIR; } perror ("mkdir"); return false; } /** Create a file name * @param directoryname name of the directory * @param basefilename (output) pointer to the full file name * @param maxnamelength maximum number of characters in the file name part * @return pointer to the file name part */ inline static char* mkfilename (const char* directoryname, char*& basefilename, unsigned maxnamelength) { size_t directorylength = strlen (directoryname); if (directoryname[directorylength - 1] != '/') directorylength++; basefilename = new char[directorylength + maxnamelength]; memcpy (basefilename, directoryname, directorylength); basefilename[directorylength - 1] = '/'; return basefilename + directorylength; } /** type definitions */ static const char typedefs[] = "mset.h"; /** type comparisons */ static const char typecomp[] = "mset.c"; /** event decoding dispatcher */ static const char events[] = "event.c"; /** state encoding and decoding */ static const char states[] = "state.c"; /** Initialize the index numbers for data type definitions * @param net the net to be initialized */ static void uncompileTypes (const class Net& net) { for (unsigned i = net.getNumChildren (); i--; ) uncompileTypes (net.getChild (i)); for (Net::TypeList::const_iterator t = net.begin (); t != net.end (); t++) (*t)->uncompile (); } /** Generate code for data type definitions * @param net the net for which to generate * @param out the output buffer * @param file the output file */ static void generateTypes (const class Net& net, class StringBuffer& out, FILE* file) { for (unsigned i = 0; i < net.getNumChildren (); i++) generateTypes (net.getChild (i), out, file); for (Net::TypeList::const_iterator t = net.begin (); t != net.end (); t++) { (*t)->compile (out); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); } } /** Generate code for data item comparisons * @param net the net for which to generate * @param out the output buffer * @param file the output file */ static void generateComparisons (const class Net& net, class StringBuffer& out, FILE* file) { for (unsigned i = 0; i < net.getNumChildren (); i++) generateComparisons (net.getChild (i), out, file); for (Net::TypeList::const_iterator t = net.begin (); t != net.end (); t++) { if ((*t)->isGenerated ()) continue; out.append ("#define ID(id) id##"); (*t)->appendIndex (out); out.append ("\n"); (*t)->compileExtraDefinitions (out, 0, false); out.append ("#include\"bushfcn.h\"\n"); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); } } /** Generate code for synchronising transitions * @param net the net for which to generate * @param basefilename full path name to the generated files * @param filename the changing part of the generated file names * @param decl buffer for declarations * @param numcompiled (in/out) number of transitions compiled * @return true on success, false on failure */ static bool generateSync (const class Net& net, const char* basefilename, char* filename, class StringBuffer& decl, unsigned& numcompiled) { unsigned i; // transition files (synchronising transitions) for (i = net.getNumCallees (); i--; ) { /** the callee transition (synchronisation label) */ const class Transition& t = net.getCallee (i); for (unsigned k = 0; k < t.getNumChildren (); k++) { class Transition& u = const_cast(t.getChild (k)); if (u.getLocalIndex () >= u.getNet ()->getNumCallees () || &u.getNet ()->getCallee (u.getLocalIndex ()) != &u) { // u is an ordinary transition that synchronises on t u.setRootIndex (numcompiled); snprintf (filename, 24, "t%u.c", numcompiled); if (FILE* file = fopen (basefilename, "w")) { u.compile (decl); fwrite (decl.getString (), 1, decl.getLength (), file); decl.create (0); fclose (file); } else return false; numcompiled++; } } } for (i = net.getNumChildren (); i--; ) if (!generateSync (net.getChild (i), basefilename, filename, decl, numcompiled)) return false; return true; } /** Generate code * @param net the net for which to generate * @param directory name of the directory containing the generated code * @return true on success, false on failure */ inline static bool generate (const class Net& net, const char* directory) { if (!dirExists (directory)) return false; char* basefilename; char* filename = mkfilename (directory, basefilename, 24); /** output file */ FILE* file; /** buffer for declarations */ class StringBuffer decl; // type definitions memcpy (filename, typedefs, sizeof typedefs); if (!(file = fopen (basefilename, "w"))) { fopenError: perror ("fopen"); delete[] basefilename; return false; } decl.append ("#include\"bush.h\"\n"); uncompileTypes (net); generateTypes (net, decl, file); unsigned i; decl.append ("extern struct marking {\n"); for (i = 0; i < net.getNumPlaces (); i++) { const class Place& place = *net.getPlace (i); decl.indent (2); if (place.getMaxNumTokens () == 1) place.getType ().appendName (decl); else place.getType ().appendMSetName (decl); decl.append ("* p"); decl.append (i); decl.append (";\n"); } decl.append ("} mSrc, mIn, mDest;\n" "extern card_t numTokens["); decl.append (net.getNumPlaces ()); decl.append ("];\n" "void\n" "initm (void);\n" "void\n" "freem (struct marking* m);\n" "void\n" "mset_clean (void);\n"); net.compileConstantDecl (decl, "extern "); fwrite (decl.getString (), 1, decl.getLength (), file); decl.create (0); fclose (file); // type comparisons memcpy (filename, typecomp, sizeof typecomp); if (!(file = fopen (basefilename, "w"))) goto fopenError; decl.append ("#include\"bushpriv.h\"\n"); generateComparisons (net, decl, file); net.compileConstantDecl (decl, 0); for (i = 0; i < net.getNumAllTransitions (); i++) { decl.append ("void i"); decl.append (i); decl.append (" (void);\n"); } decl.append ("extern void\n" "init (void)\n" "{\n"); net.compileConstantInit (decl); for (i = 0; i < net.getNumAllTransitions (); i++) { decl.append (" i"); decl.append (i); decl.append (" ();\n"); } decl.append ("}\n"); fwrite (decl.getString (), 1, decl.getLength (), file); decl.create (0); decl.append ("void\n" "initm (void)\n" "{\n" " freem (&mDest);\n"); for (i = 0; i < net.getNumPlaces (); i++) { const class Type& type = net.getPlace (i)->getType (); if (net.getPlace (i)->getMaxNumTokens () == 1) { decl.append (" if (mSrc.p"); decl.append (i); decl.append (") *(mDest.p"); decl.append (i); decl.append (" = malloc (sizeof ("); type.appendName (decl); decl.append ("))) = *mSrc.p"); decl.append (i); decl.append (";\n"); } else { decl.append (" mDest.p"); decl.append (i); decl.append (" = copy"); type.appendIndex (decl); decl.append (" (0, mSrc.p"); decl.append (i); decl.append (");\n"); } } decl.append ("}\n" "void\n" "freem (struct marking* m)\n" "{\n"); for (i = 0; i < net.getNumPlaces (); i++) { if (net.getPlace (i)->getMaxNumTokens () == 1) { decl.append (" free (m->p"); decl.append (i); decl.append ("), m->p"); decl.append (i); decl.append (" = 0;\n"); } else { decl.append (" FREE (m->p"); decl.append (i); decl.append (");\n"); } } decl.append ("}\n" "void\n" "mset_clean (void)\n" "{\n" " freem (&mSrc); freem (&mIn); freem (&mDest);\n" "}\n"); fwrite (decl.getString (), 1, decl.getLength (), file); decl.create (0); fclose (file); // event decoding dispatcher memcpy (filename, events, sizeof events); if (!(file = fopen (basefilename, "w"))) goto fopenError; decl.append ("#include\"Error.h\"\n" "#include\"eventpriv.h\"\n" "unsigned wfair["); decl.append (1 + net.getNumWeaklyFair ()); decl.append ("], sfair["); decl.append (1 + net.getNumStronglyFair ()); decl.append ("];\n"); for (i = 0; i < net.getNumAllTransitions (); i++) { decl.append ("enum Error d"); decl.append (i); decl.append (" (unsigned sf);\n"); } decl.append ("extern enum Error\n" "event_decode (unsigned sf)\n" "{\n"); switch (net.getNumAllTransitions ()) { case 1: decl.append (" return d0 (sf);\n"); break; case 0: decl.append (" return errNone;\n"); break; default: decl.append (" unsigned tr = FCN (dec) (flat ? "); decl.append (log2 (net.getNumAllTransitions ())); decl.append (" : "); decl.append (log2 (net.getNumTransitions ())); decl.append (");\n" " switch (tr) {\n"); for (i = 0; i < net.getNumAllTransitions (); i++) { decl.append (" case "); decl.append (i); decl.append (": return d"); decl.append (i); decl.append (" (sf);\n"); } decl.append (" }\n" " return errFatal;\n"); } decl.append ("}\n"); fwrite (decl.getString (), 1, decl.getLength (), file); decl.create (0); fclose (file); // state encoding and decoding memcpy (filename, states, sizeof states); if (!(file = fopen (basefilename, "w"))) goto fopenError; class CExpression cexpr (decl, net, 0); decl.append ("#include\"statefcn.h\"\n" "card_t numTokens["); decl.append (net.getNumPlaces ()); decl.append ("];\n"); cexpr.setMultiset ("mSrc"); net.compileDeadlock (cexpr); decl.append ("extern enum Error\n" "deadlock (unsigned net)\n" "{\n"); cexpr.generate (); cexpr.setMultiset ("mDest"); net.compileReject (cexpr); decl.append ("}\n" "static enum Error\n" "reject (unsigned net)\n" "{\n"); cexpr.generate (); net.compileProps (cexpr, "op", "data"); decl.append ("}\n" "extern int\n" "stateprop (int (*op) (unsigned, void*), void* data)\n" "{\n"); cexpr.generate (); net.compileEncoder (cexpr); decl.append ("}\n" "enum Error\n" "encode (unsigned net, unsigned tr, unsigned ftr," " int hide, void* ctx)\n" "{\n"); cexpr.generate (); cexpr.setMultiset ("mSrc"); net.compileDecoder (cexpr); decl.append ("}\n" "extern void\n" "decode (unsigned net, void* buf, unsigned size)\n" "{\n"); cexpr.generate (); net.compileProjection (cexpr); decl.append ("}\n" "extern const void*\n" "project (unsigned net, unsigned d, unsigned dbits," " unsigned* size)\n" "{\n"); cexpr.generate (); decl.append ("}\n"); fwrite (decl.getString (), 1, decl.getLength (), file); decl.create (0); fclose (file); // transition files (original and fused transitions in root net) assert (!net.getIndex ()); for (i = 0; i < net.getNumAllTransitions (); i++) { snprintf (filename, 24, "t%u.c", i); if (!(file = fopen (basefilename, "w"))) goto fopenError; net.getTransition (i).compile (decl); fwrite (decl.getString (), 1, decl.getLength (), file); decl.create (0); fclose (file); } unsigned numcompiled = i; if (!generateSync (net, basefilename, filename, decl, numcompiled)) goto fopenError; net.setNumCompiled (numcompiled); delete[] basefilename; return true; } bool Compilation::compile () const { return ::generate (myNet, myDirectory); } /** Execute an external program * @param progname name of the program * @param argv arguments of the program * @return true if everything succeeded */ inline static bool execute (const char* progname, char*const* argv) { signal (SIGCHLD, SIG_DFL); if (pid_t pid = fork ()) { if (pid < 0) perror ("fork"); else { for (;;) { int status = 0; pid_t child = wait (&status); if (child == pid) { if (!status) { signal (SIGCHLD, sig); return true; } fprintf (stderr, "%s returned %d\n", progname, status); break; } else if (child < 0) { perror ("wait"); break; } else childterm (pid); } } } else { execvp (progname, argv); perror (progname); exit (127); } signal (SIGCHLD, sig); return false; } /** Compile the files * @param prefix prefix for invoking the compiler * @param directory name of the directory containing the generated code * @param object name of the object file * @param numTrans number of transition files * @param ... names of modules to compile, terminated by NULL */ inline static bool compile (const char* prefix, const char* directory, const char* object, unsigned numTrans, ...) { size_t prefixlength = strlen (prefix); char* progname = new char[prefixlength + 5]; if (!progname) return false; memcpy (progname, prefix, prefixlength); memcpy (progname + prefixlength, "-cso", 5); char** argv = new char*[numTrans + 7]; if (!argv) return false; argv[0] = progname; argv[1] = newString (directory); argv[2] = newString (object); /** number of extra modules */ unsigned numModules = 0; /** the extra modules */ va_list modules; va_start (modules, numTrans); while (const char* mod = va_arg (modules, const char*)) argv[3 + numModules++] = newString (mod); va_end (modules); argv[3 + numTrans + numModules] = 0; char tname[24]; unsigned i; bool status = false; for (i = 0; i < numTrans; i++) { snprintf (tname, sizeof tname, "t%u.c", i); if (!(argv[3 + numModules + i] = newString (tname))) goto cleanup; } status = execute (progname, argv); cleanup: for (i += 3 + numModules; i--; ) delete[] argv[i]; delete[] argv; return status; } /** property automaton */ static const char props[] = "p.c"; /** property library */ static const char prop_so[] = "p.so"; bool Compilation::compile (const class Property& property) { *myPropBits = property.isFinite () ? log2 (property.getNumStates ()) : 0; /** a state of the property automaton */ unsigned state; /** file name including the directory name */ char* basefilename; /** file name excluding the directory name */ char* filename = mkfilename (myDirectory, basefilename, sizeof prop_so); memcpy (filename, props, sizeof props); if (FILE* file = fopen (basefilename, "w")) { /** buffer for declarations */ class StringBuffer decl; /** the compilation */ class CExpression cexpr (decl, myNet, 0); /** accepting state of the property automaton */ const unsigned final = property.getFinalState (); cexpr.setMultiset ("mSrc"); decl.append ("#include \"mset.h\"\n" "#define ERROR(err) return err\n" "unsigned succ["); decl.append (1 + property.getNumStates ()); decl.append ("];\n"); for (state = 0; state < property.getNumStates (); state++) { property[state].compileGates (cexpr, 2, "succ", final); decl.append ("static enum Error\nprop"), decl.append (state); decl.append (" (void)\n{\n"); cexpr.generate (); decl.append ("}\n"); fwrite (decl.getString (), 1, decl.getLength (), file); decl.create (0); } fputs ("enum Error (*prop[]) (void) = {", file); /** line wrap thresold */ const unsigned wrap = 75; /** column counter */ register unsigned column = wrap; for (state = 0; state < property.getNumStates (); state++) { if (column >= wrap) column = fprintf (file, "\n prop%u,", state) - 1; else column += fprintf (file, " prop%u,", state); } fputs ("\n};\n", file); fclose (file); memcpy (filename, prop_so, sizeof prop_so); if (::compile (myPrefix, myDirectory, basefilename, 0, props, 0)) { if (myPropHandle) dlclose (myPropHandle); myPropHandle = dlopen (basefilename, RTLD_NOW); delete[] basefilename; const char* err = dlerror (); if (err) fputs (err, stderr), putc ('\n', stderr); else if (!myPropHandle) fputs ("could not open shared library\n", stderr); else { const unsigned* succ = reinterpret_cast(dlsym (myPropHandle, E ("succ"))); if ((err = dlerror ())) { fputs (err, stderr), putc ('\n', stderr); return false; } else if (!succ) { fputs ("could not bind symbol `succ'\n", stderr); return false; } myPropEval = reinterpret_cast(dlsym (myPropHandle, E ("prop"))); if ((err = dlerror ())) { fputs (err, stderr), putc ('\n', stderr); return false; } else if (!myPropEval) { fputs ("could not bind symbol `prop'\n", stderr); return false; } *myPropSucc = succ; return true; } return false; } } else perror ("fopen"); delete[] basefilename; return false; } /** close the shared library at exit */ #define DLRET (dlclose (myHandle), myHandle = 0) /** check for an error message */ #define DLERR if ((er0 = dlerror ())) return err = newString (er0), DLRET, err /** Bind a symbol of the specified type from a shared object * @param sym_t type of the symbol to be bound * @param sym name of the symbol to be bound * @param var name of the variable to be bound */ #define DLBIND(sym_t, sym, var) \ var = *reinterpret_cast(&(f = dlsym (myHandle, E (#sym)))); \ DLERR; \ if (!var) return DLRET, newString ("cannot bind symbol " E (#sym)) /** Bind a symbol of the specified type from a shared object to a table * @param sym_t type of the symbol to be bound * @param symfmt format string for the symbol name * @param var name of the table */ #define DLBINDT(sym_t, symfmt, var) \ snprintf (snam, sizeof snam, E (symfmt), i); \ var[i] = *reinterpret_cast(&(f = dlsym (myHandle, snam))); \ DLERR; \ if (!var) return DLRET, newString ("cannot bind symbol " symfmt) /** Bind a symbol of the specified type backwards to a shared object * @param sym_t type of the symbol to be bound * @param sym name of the symbol to be bound * @param var name of the variable to be bound */ #define DLBINDB(sym_t, sym, var) \ f = dlsym (myHandle, E (#sym)); DLERR; \ if (!f) return DLRET, newString ("cannot bind symbol " E (#sym)); \ *reinterpret_cast(f) = var /** Bind a symbol of the specified type to a pointer in the shared object * @param sym_t type of the symbol to be bound * @param sym name of the symbol to be bound * @param var name of the variable to be bound */ #define DLBINDP(sym_t, sym, var) \ f = dlsym (myHandle, E (#sym)); DLERR; \ if (!f) return DLRET, newString ("cannot bind symbol " E (#sym)); \ var = reinterpret_cast(f) char* Compilation::link () { unlink (); { size_t directorylength = strlen (myDirectory); char* so_name = new char[directorylength + 6]; memcpy (so_name, myDirectory, directorylength); memcpy (so_name + directorylength, "/a.so", 6); if (::compile (myPrefix, myDirectory, so_name, myNet.getNumCompiled (), events, states, typecomp, 0)) myHandle = dlopen (so_name, RTLD_NOW #ifdef RTLD_GLOBAL | RTLD_GLOBAL #endif // RTLD_GLOBAL ); else { delete[] so_name; return newString ("could not create shared library"); } delete[] so_name; } /** error message */ const char* er0; /** copied error message */ char* err; if ((er0 = dlerror ())) { if (myHandle) dlclose (myHandle), myHandle = 0; return err = newString (er0); } if (!myHandle) return newString ("could not open shared library"); /** auxiliary variable for type conversions */ void* f; DLBIND (vf_t, mset_clean, myMsetClean); DLBIND (vf_t, event_cleanup, myEventClean); DLBIND (vf_t, event_clear, myEventClear); DLBIND (inf_t, inflate, myEventInflater); DLBIND (def_t, deflate, myEventDeflater); DLBIND (fair_t, event_decode, myEventDecoder); DLBIND (vf_t, cleanup, myStateClean); DLBIND (sproj_t, project, myStateProject); DLBIND (sdec_t, decode, myStateDecoder); DLBIND (deval_t, deadlock, myStateDeadlock); DLBIND (prop_t, stateprop, myStateProps); myWeaklyFair = reinterpret_cast(dlsym (myHandle, E ("wfair"))); DLERR; if (!myWeaklyFair) return DLRET, newString ("cannot bind symbol " E ("wfair")); myStronglyFair = reinterpret_cast(dlsym (myHandle, E ("sfair"))); DLERR; if (!myStronglyFair) return DLRET, newString ("cannot bind symbol " E ("sfair")); myPropBits = reinterpret_cast(dlsym (myHandle, E ("propBits"))); DLERR; if (!myPropBits) return DLRET, newString ("cannot bind symbol " E ("propBits")); myPropSucc = reinterpret_cast(dlsym (myHandle, E ("propSucc"))); DLERR; if (!myPropSucc) return DLRET, newString ("cannot bind symbol " E ("propSucc")); unsigned i = myNet.getNumCompiled (); delete[] myEventAnalyzers; myEventAnalyzers = new uf_t[i]; for (unsigned i = myNet.getNumCompiled (); i--; ) { char snam[23]; DLBINDT (uf_t, "a%u", myEventAnalyzers); } *myPropBits = 0; extern volatile bool interrupted; DLBINDB (volatile bool*, intr, &interrupted); DLBINDP (bool*, fatal, myFatal); DLBINDP (bool, flattened, myFlattened); DLBINDP (sadd_t, addstate, myAddState); DLBINDP (ssync_t, syncstate, mySyncState); DLBINDP (char, arcs, myAddArcs); DLBINDP (char, flat, myFlat); vf_t init; DLBIND (vf_t, init, init); (*init) (); return 0; } void Compilation::unlink () { if (myPropHandle) { dlclose (myPropHandle); myPropHandle = 0, myPropEval = 0; } if (myHandle) { msetClean (); eventClean (); stateClean (); dlclose (myHandle); myHandle = 0; } } maria-1.3.5/Compilation/base/Compilation.h0000644000175000017500000002226407762612344020617 0ustar msmakelamsmakela// Compilation of types, variables and expressions -*- c++ -*- #ifndef COMPILATION_H_ # define COMPILATION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Error.h" # include /** @file Compilation.h * Interface to compiled code */ /* Copyright © 2000-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Compilation of types, variables and expressions */ class Compilation { /** Parameterless void function */ typedef void (*vf_t) (void); /** Transition instance analysis function */ typedef unsigned (*uf_t) (void*, char*); /** Event buffer inflater */ typedef unsigned (*inf_t) (void*, size_t); /** Event buffer deflater */ typedef void* (*def_t) (size_t*); /** State encoder */ typedef const void* (*sproj_t) (unsigned,unsigned,unsigned,unsigned*); /** State decoder */ typedef void (*sdec_t) (unsigned,void*,unsigned); /** Add encoded state */ typedef void (*sadd_t) (const void*,size_t,enum Error, unsigned,unsigned,int,void*); /** Report that a synchronising transition is enabled */ typedef void (*ssync_t) (unsigned,void*); /** Evaluate deadlock condition for a given net */ typedef enum Error (*deval_t) (unsigned); /** Evaluator function */ typedef enum Error (*eval_t) (void); /** Event decoder and fairness evaluator */ typedef enum Error (*fair_t) (unsigned); /** State property evaluator function */ typedef int (*prop_t) (bool (*) (unsigned, const void*), const void*); public: /** Constructor * @param net the net to be compiled * @param directory name of the directory for the files * @param prefix prefix for invoking external programs */ explicit Compilation (const class Net& net, const char* directory, const char* prefix); private: /** Copy constructor */ Compilation (const class Compilation& old); /** Assignment operator */ class Compilation& operator= (const class Compilation& old); public: /** Destructor */ ~Compilation (); /** Compile the type definitions and expressions of a net * @return true if everything succeeded */ bool compile () const; /** Link the compiled functions of a net * @return NULL on success; error message on failure */ char* link (); /** Link the state storage function * @param addstate function to be called when adding states */ void linkAddState (sadd_t addstate) const { *myAddState = addstate; } /** Link the state space reporting functions * @param syncstate function for reporting potential synchronisations * @param arcs flag: generate arcs * @param flat flag: generate a flattened state space */ void linkReporter (ssync_t syncstate, bool arcs, bool flat) const { *mySyncState = syncstate; *myAddArcs = arcs; *myFlat = flat; } /** Get a pointer to the flag for reporting fatal errors */ bool*& getFatal () const { return *myFatal; } /** Get a reference to the flag for indicating flattened analysis */ bool& getFlattened () const { return *myFlattened; } /** Unlink the compiled functions of a net */ void unlink (); /** Compile and link a property automaton * @param property the property automaton * @return true if everything succeeded */ bool compile (const class Property& property); /** Clear the finite property automaton */ void clearProp () { *myPropBits = 0; } /** Clean up (deallocate) the multi-sets */ void msetClean () const { (*myMsetClean) (); } /** Clean up (deallocate) the event encoding buffer */ void eventClean () const { (*myEventClean) (); } /** Clear (empty) the event encoding buffer */ void eventClear () const { (*myEventClear) (); } /** Initialize the event decoding buffer * @param buf the decoding buffer * @param size length of the decoding buffer */ void eventInflate (void*buf, size_t size) const { (*myEventInflater) (buf, size); } /** Get the event encoding buffer * @param size (output): length encoded data in bytes * @return the buffer */ const void* eventDeflate (size_t& size) const { return (*myEventDeflater) (&size); } /** Analyze and fire the enabled instances of a transition * @param tr number of the transition * @param ctx the call-back context * @param log log of enabled transition instance sets (optional) * @return number of errors occurred */ unsigned eventAnalyze (unsigned tr, void* ctx, char* log) const { return (*myEventAnalyzers[tr]) (ctx, log); } /** Decode a transition instance and compute fairness constraints * @param strong flag: compute also strong fairness constraints? * @return errNone or an error code */ enum Error eventDecode (bool strong) const { return (*myEventDecoder) (strong); } /** Get the active weak fairness sets after a call to eventDecode () */ unsigned* getWeaklyFair () const { return myWeaklyFair; } /** Get the active strong fairness sets after a call to eventDecode () */ unsigned* getStronglyFair () const { return myStronglyFair; } /** Clean up (deallocate) the state encoding buffer */ void stateClean () const { (*myStateClean) (); } /** Project the state on a module * @param net the module * @param d extra data to be appended to the state vector * @param dbits width of d in bits * @param size (output) length of the encoded state in bytes * @return the encoded data */ const void* stateProject (unsigned net, unsigned d, unsigned dbits, unsigned& size) const { return (*myStateProject) (net, d, dbits, &size); } /** Decode a state * @param net the number of the net (0=root) * @param buf the encoded data (deflated if size is nonzero) * @param size length of the encoded state in bytes (0=inflated data) */ void stateDecode (unsigned net, void* buf, unsigned size) const { (*myStateDecoder) (net, buf, size); } /** Evaluate the reject condition * @param net the number of the net (0=root) * @return errNone, errComp (condition holds) or an error code */ enum Error stateDeadlock (unsigned net) const { return (*myStateDeadlock) (net); } /** Evaluate state properties * @param operation operation to invoke on properties that hold * @param data context data to pass to the operation */ bool checkProps (bool (*operation) (unsigned, const void*), const void* data) const { return bool ((*myStateProps) (operation, data)); } /** Evaluate the successors of a property automaton * @param s the number of the state where to evaluate the gates * @return errNone, or an error code */ enum Error propEval (unsigned s) const { return (*myPropEval[s]) (); } /** Get the enabled successors after a call to propEval () */ const unsigned* getPropSucc () const { return *myPropSucc; } private: /** The net to be compiled */ const class Net& myNet; /** The directory name */ const char* myDirectory; /** Prefix for external program names */ const char* myPrefix; /** Handle to a dynamic library */ void* myHandle; /** Multi-set clean-up function */ vf_t myMsetClean; /** Event clean-up function */ vf_t myEventClean; /** Event clearing function */ vf_t myEventClear; /** Event analyzer functions */ uf_t* myEventAnalyzers; /** Event inflater function */ inf_t myEventInflater; /** Event deflater function */ def_t myEventDeflater; /** Event decoder function */ fair_t myEventDecoder; /** State clean-up function */ vf_t myStateClean; /** State projection function */ sproj_t myStateProject; /** State decoder function */ sdec_t myStateDecoder; /** Fatalness flag */ bool** myFatal; /** Flattenedness flag */ bool* myFlattened; /** Add encoded state (callback) */ sadd_t* myAddState; /** Report synchronisation (callback) */ ssync_t* mySyncState; /** Flag: generate arcs */ char* myAddArcs; /** Flag: generate flattened state space */ char* myFlat; /** State deadlock property evaluator function */ deval_t myStateDeadlock; /** Active weak fairness sets */ unsigned* myWeaklyFair; /** Active strong fairness sets */ unsigned* myStronglyFair; /** Bits per finite-word property automaton state */ unsigned* myPropBits; /** Enabled successors in the property automaton */ const unsigned** myPropSucc; /** Handle to a property automaton library */ void* myPropHandle; /** Property gate evaluators */ eval_t* myPropEval; /** State property evaluator */ prop_t myStateProps; }; #endif // COMPILATION_H_ maria-1.3.5/Compilation/runtime/0000755000175000017500000000000010272511377016725 5ustar msmakelamsmakelamaria-1.3.5/Compilation/runtime/bushfcn.h0000644000175000017500000001340007643253065020531 0ustar msmakelamsmakela/** @file runtime/bushfcn.h * Definitions of low-level tree operations for handling multi-sets */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #if !defined CMP3 || !defined EQ || !defined ID # error "you should not try to use this file directly" #endif /* !CMP3 || !EQ || !ID */ /** insert an item to the tree * @param t root of the tree * @param item item to be inserted * @param count number of items to insert * @return root of the new tree, or NULL in case of error */ struct TREE* ID(insert) (struct TREE* t, const TYPE* item, card_t count) { if (!t) { if (!(t = malloc (sizeof *t))) return 0; t->up = 0; init: t->left = t->right = 0; t->item = *item; t->count = count; #ifdef RED_BLACK balance (t); #endif /* RED_BLACK */ ROOT (t); return t; } for (;;) { CMP3 ((*item), (t->item), goto less, goto greater); /* found */ if (t->count > CARD_T_MAX - count) { /* cardinality overflow */ failure: ROOT (t); FREE (t); return 0; } t->count += count; ROOT (t); return t; less: if (t->left) t = t->left; else { if (!(t->left = malloc (sizeof *t))) goto failure; /* out of memory */ t->left->up = t, t = t->left; goto init; } continue; greater: if (t->right) t = t->right; else { if (!(t->right = malloc (sizeof *t))) goto failure; /* out of memory */ t->right->up = t, t = t->right; goto init; } continue; } } /** find an item * @param t root of the tree * @param item item to be sought * @return the corresponding node, or NULL if not found */ struct TREE* ID(find) (struct TREE* t, const TYPE* item) { while (t) { CMP3 ((*item), (t->item), goto less, goto greater); break; less: t = t->left; continue; greater: t = t->right; continue; } return t; } /** multi-set equality comparison * @param l left multi-set to compare * @param r right multi-set to compare * @return whether the two multi-sets are equal */ bool_t ID(equal) (const struct TREE* l, const struct TREE* r) { FIRST (l); FIRST (r); while (l && r) { while (l && !l->count) NEXT (l); while (r && !r->count) NEXT (r); if (!(l && r)) break; if (l->count != r->count || !(EQ ((l->item), (r->item)))) return 0; NEXT (l); NEXT (r); } while (l && !l->count) NEXT (l); while (r && !r->count) NEXT (r); return !l && !r; } /** multi-set containment comparison * @param l left multi-set to compare * @param r right multi-set to compare * @return whether the right multi-set contains the left multi-set */ bool_t ID(subset) (const struct TREE* l, const struct TREE* r) { FIRST (l); FIRST (r); while (l && r) { while (l && !l->count) NEXT (l); while (r && !r->count) NEXT (r); if (!(l && r)) break; CMP3 ((l->item), (r->item), return 0, goto next); if (l->count > r->count) return 0; NEXT (l); next: NEXT (r); } while (l && !l->count) NEXT (l); return !l; } /** multi-set intersection * @param l multi-set to be intersected * @param r multi-set of items to remove from the left multi-set */ void ID(intersect) (struct TREE* l, const struct TREE* r) { register struct TREE* i = (struct TREE*) r; FIRST (i); while (i) { if (i->count) { register struct TREE* t = ID(find) (l, &i->item); if (t && t->count > i->count) t->count = i->count; NEXT (i); } } i = l; FIRST (i); while (i) { if (i->count && !ID(find) ((struct TREE*) r, &i->item)) i->count = 0; NEXT (i); } } /** multi-set subtraction * @param l multi-set to be subtracted * @param r multi-set of items to remove from the left multi-set */ void ID(subtract) (struct TREE* l, const struct TREE* r) { register const struct TREE* i = r; FIRST (i); while (i) { if (i->count) { register struct TREE* t = ID(find) (l, &i->item); if (t) { if (t->count > i->count) t->count -= i->count; else t->count = 0; } } NEXT (i); } } /** copy constructor * @param u target multi-set * @param t multi-set to be copied to u * @return u augmented with t */ struct TREE* ID(copy) (struct TREE* u, const struct TREE* t) { FIRST (t); while (t) { if (t->count && !(u = ID(insert) (u, &t->item, t->count))) return 0; NEXT (t); } return u; } /** multi-copy constructor * @param u target multi-set * @param t multi-set to be copied * @param count number of copies to insert * @return u augmented with count copies of t */ struct TREE* ID(copyc) (struct TREE* u, const struct TREE* t, card_t count) { if (!count) return u; else if (count == 1) return ID(copy) (u, t); else { card_t maxcount = CARD_T_MAX / count; FIRST (t); while (t) { if (t->count >= maxcount) { FREE (u); return 0; } else if (t->count && !(u = ID(insert) (u, &t->item, t->count * count))) return 0; NEXT (t); } return u; } } #undef ID #undef CMP3 #undef EQ maria-1.3.5/Compilation/runtime/Error.h0000644000175000017500000000323707643253065020201 0ustar msmakelamsmakela/* Error codes -*- c -*- */ #ifndef ERROR_H_ # define ERROR_H_ /** @file runtime/Error.h * Evaluation error codes from the compiled code */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Error codes */ enum Error { errNone = 0, /* no error */ errConst, /* constraint violation */ errVar, /* undefined variable */ errUndef, /* undefined expression evaluated */ errFatal, /* fatal expression evaluated */ errDiv0, /* division by zero */ errOver, /* overflow */ errMod, /* modulus error */ errShift, /* shift error */ errUnion, /* attempt to reference a non-active union component */ errBuf, /* buffer boundary violation */ /* codes not used by the low-level expression evaluator */ errCard, /* cardinality overflow */ errComp /* incompatible values (no actual error) */ }; #endif /* ERROR_H_ */ maria-1.3.5/Compilation/runtime/bush.h0000644000175000017500000001050207643253065020042 0ustar msmakelamsmakela/** @file runtime/bush.h * Declarations of low-level tree operations for handling multi-sets */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include #include #include"Error.h" #include"types.h" #ifndef CONST # ifdef __GNUC__ # define CONST __attribute__ ((const)) # else # define CONST # endif #endif /* multi-set and type declaration stuff */ /** three-way conditional comparison for data items * @param f flag: perform the comparison? * @param l left-hand-side argument * @param r right-hand-side argument * @param c component to compare * @param s action to perform if l is smaller than right * @param g action to perform if l is greater than right */ #define CC3(f,l,r,c,s,g) if (f) {if (l cr c) {g;}} /** three-way comparison for data items * @param l left-hand-side argument * @param r right-hand-side argument * @param c component to compare * @param s action to perform if l is smaller than right * @param g action to perform if l is greater than right */ #define C3(l,r,c,s,g) if (l c < r c) { s; } else if (l c > r c) { g; } /** name of the current tree type */ #define TREE ID(tree) /** name of the current type */ #define TYPE ID(t) /** generic tree structure */ struct tree { struct tree *up, *left, *right; #ifdef RED_BLACK bool_t red; #endif /* RED_BLACK */ card_t count; }; /** declare a multi-set data structure */ #ifdef RED_BLACK # define DECLARE_MULTISET \ struct TREE \ { \ struct TREE *up, *left, *right; \ bool_t red; \ card_t count; \ TYPE item; \ } #else /* RED_BLACK */ # define DECLARE_MULTISET \ struct TREE \ { \ struct TREE *up, *left, *right; \ card_t count; \ TYPE item; \ } #endif /* RED_BLACK */ /** declare multi-set operations */ #define DECLARE_MULTISET_OPS \ DECLARE_MULTISET; \ struct TREE* ID(insert) (struct TREE*,const TYPE*,card_t); \ struct TREE* ID(find) (struct TREE*,const TYPE*) CONST; \ bool_t ID(equal) (const struct TREE*,const struct TREE*) CONST; \ bool_t ID(subset) (const struct TREE*,const struct TREE*) CONST;\ void ID(intersect) (struct TREE*,const struct TREE*); \ void ID(subtract) (struct TREE*,const struct TREE*); \ struct TREE* ID(copy) (struct TREE*,const struct TREE*); \ struct TREE* ID(copyc) (struct TREE*,const struct TREE*,card_t) /** climb to the root of a tree * @param t in: a tree node; out: the root of the tree */ #define ROOT(t) if (t) while (t->up) t = t->up /** get the minimum item in a tree * @param t in: root of the tree; out: minimum item in tree */ #define FIRST(t) if (t) while ((t)->left) (t) = (t)->left /** get the successor of a tree node * @param t in: the tree node; out: successor of the node */ #define NEXT(t) do { \ if ((t)->right) for ((t) = (t)->right; (t)->left; (t) = (t)->left); \ else { \ while ((t)->up && (t) == (t)->up->right) (t) = (t)->up; \ (t) = (t)->up; \ } \ } while (0) /** free a tree * @param t in: tree to be freed; out: NULL */ #define FREE(t) (t ? (freetree (t), t = 0) : 0) void freetree (void* node); /** determine whether the multi-set a tree represents is singleton * @param node the root of the tree * @return pointer to the item, or 0 if the tree is not singleton */ void* singleton (void* node) CONST; /** determine whether the multi-set a tree represents is empty * @param node the root of the tree * @return pointer to the first non-empty item, or 0 if the tree is empty */ const void* nonempty (const void* node) CONST; maria-1.3.5/Compilation/runtime/bushpriv.h0000644000175000017500000001022707643253065020747 0ustar msmakelamsmakela/** @file runtime/bushpriv.h * Definitions of generic tree operations */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include "mset.h" /** deallocate a tree * @param node the root of the tree */ void freetree (void* node) { register struct tree* t = node; if (t->left) freetree (t->left); if (t->right) freetree (t->right); free (t); } /** determine whether the multi-set a tree represents is singleton * @param node the root of the tree * @return the singleton node, or 0 if the tree is not singleton */ void* singleton (void* node) { struct tree* u = 0; register struct tree* t = node; FIRST (t); while (t) { if (!t->count); else if (t->count > 1 || u) return 0; else u = t; NEXT (t); } return u ? u + 1 : 0; } /** determine whether the multi-set a tree represents is empty * @param node the root of the tree * @return pointer to the first non-empty item, or 0 if the tree is empty */ const void* nonempty (const void* node) { register const struct tree* t = node; FIRST (t); while (t) { if (t->count) return t; NEXT (t); } return 0; } #ifdef DEBUG /** climb to the root of a tree * @param node a tree node * @return the root of the tree */ struct tree* root (void* node) { register struct tree* t = node; if (t) while (t->up) t = t->up; return t; } /** get the minimum item in a tree * @param node the root of the tree * @return minimum item in the tree */ struct tree* first (void* node) { register struct tree* t = node; if (t) while (t->left) t = t->left; return t; } /** get the successor of a tree node * @param node the tree node * @return the successor of the node */ struct tree* next (void* node) { register struct tree* t = node; if (t) { if (t->right) return first (t->right); while (t->up && t == t->up->right) t = t->up; t = t->up; } return t; } #endif /* DEBUG */ #ifdef RED_BLACK /** left rotate a tree * @param node tree node to be rotated */ static void left_rotate (void* node) { register struct tree *t = node, *u = t->right; if ((t->right = u->left)) u->left->up = t; if ((u->up = t->up)) { if (t == t->up->left) t->up->left = u; else t->up->right = u; } u->left = t, t->up = u; } /** right rotate a tree * @param node tree node to be rotated */ static void right_rotate (void* node) { register struct tree *t = node, *u = t->left; if ((t->left = u->right)) u->right->up = t; if ((u->up = t->up)) { if (t == t->up->right) t->up->right = u; else t->up->left = u; } u->right = t, t->up = u; } /** balance a tree * @param node a newly inserted node */ static void balance (void* node) { register struct tree* t = node; t->red = 1; while (t->up && t->up->red) { register struct tree* u = t->up->up; if (!u) break; if (t->up == u->left) { if (u->right && u->right->red) u->left->red = u->right->red = 0, u->red = 1, t = u; else { if (t == t->up->right) left_rotate (t = t->up); if (t->up) t->up->red = 0; u->red = 1; right_rotate (u); } } else { if (u->left && u->left->red) { if (u->right) u->right->red = 0; u->left->red = 0, u->red = 1, t = u; } else { if (t == t->up->left) right_rotate (t = t->up); if (t->up) t->up->red = 0; u->red = 1; left_rotate (u); } } } } #endif /* RED_BLACK */ maria-1.3.5/Compilation/runtime/codec.h0000644000175000017500000000715507643253065020170 0ustar msmakelamsmakela/* coding/decoding base definitions */ #include #include /* determine the endianness */ #if defined __linux # include # if !defined BYTE_ORDER # define BYTE_ORDER __BYTE_ORDER # define LITTLE_ENDIAN __LITTLE_ENDIAN # define BIG_ENDIAN __BIG_ENDIAN # endif /* !defined BYTE_ORDER */ #elif defined _AIX # include #elif defined __alpha # include #elif defined __sun || defined __hpux # include # if !defined BYTE_ORDER # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # if !defined _LITTLE_ENDIAN && !defined _BIG_ENDIAN # ifdef ntohl # define _LITTLE_ENDIAN # else /* !defined ntohl */ # define _BIG_ENDIAN # endif /* !defined ntohl */ # endif /* !defined _LITTLE_ENDIAN && !defined _BIG_ENDIAN */ # if defined _LITTLE_ENDIAN # define BYTE_ORDER LITTLE_ENDIAN # elif defined _BIG_ENDIAN # define BYTE_ORDER BIG_ENDIAN # endif /* little/big endian */ # endif /* !defined BYTE_ORDER */ #elif defined __sgi # include # include #elif !defined BYTE_ORDER # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # if defined __i386 # define BYTE_ORDER LITTLE_ENDIAN # else # error "cannot determine the byte order" # endif #endif /** @file runtime/codec.h * Definitions for encoding and decoding values */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /* Machine word */ #if (BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN) /** Machine word */ typedef unsigned long word_t; #else /* mixed-endian */ /** Machine word */ typedef unsigned char word_t; #endif /* BYTE_ORDER */ #define WORD_T_BIT (CHAR_BIT * sizeof (word_t)) /** number of words a specified amount of bits takes */ #define NUM_WORDS(bits) (((bits) + (WORD_T_BIT - 1)) / WORD_T_BIT) /** number of bytes a specified amount of bits takes */ #define NUM_BYTES(bits) (((bits) + (CHAR_BIT - 1)) / CHAR_BIT) /** number of words a specified amount of bytes takes */ #define NUM_WORD_B(bytes) (((bytes) + (sizeof (word_t) - 1)) / sizeof (word_t)) /* determine whether CHAR_BIT is a power of 2 */ #if (CHAR_BIT - 1) & CHAR_BIT /** Round up a bit amount to the nearest multiple of the machine word length */ # define ROUNDUP_WORDS(bits) (NUM_WORDS(bits) * WORD_T_BIT) /** Round up a bit amount to the nearest multiple of byte length */ # define ROUNDUP_BYTES(bits) (NUM_BYTES(bits) * CHAR_BIT) #else /** Round up a bit amount to the nearest multiple of the machine word length */ # define ROUNDUP_WORDS(bits) (((bits) + (WORD_T_BIT - 1)) & ~(WORD_T_BIT - 1)) /** Round up a bit amount to the nearest multiple of byte length */ # define ROUNDUP_BYTES(bits) (((bits) + (CHAR_BIT - 1)) & ~(CHAR_BIT - 1)) #endif /** encoding variable */ #define ENCVAR(x) FCN(enc##_##x) /** decoding variable */ #define DECVAR(x) FCN(dec##_##x) maria-1.3.5/Compilation/runtime/codecfcn.h0000644000175000017500000001160607643253065020653 0ustar msmakelamsmakela/** @file runtime/codecfcn.h * Definitions of encoding and decoding functions and data structures */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifndef FCN # error "FCN not defined!" #endif /* FCN */ /** encoding buffer */ static word_t* ENCVAR (buf) = 0; /** current length of the buffer, in bits */ static unsigned ENCVAR (bits) = 0; /** allocated length of the buffer, in words */ static unsigned ENCVAR (length) = 0; /** Append data to the buffer * @param data Data to be appended * @param bits Length of data in bits */ static void FCN (enc) (card_t data, unsigned bits) { unsigned wordpos, bitpos; if (ENCVAR (bits) + bits > ENCVAR (length) * WORD_T_BIT) { /* enlarge the buffer */ wordpos = NUM_WORDS (ENCVAR (bits)); ENCVAR (length) = NUM_WORDS (ENCVAR (bits) + bits); if (ENCVAR (buf)) ENCVAR (buf) = realloc (ENCVAR (buf), ENCVAR (length) * sizeof (word_t)); else ENCVAR (buf) = malloc (ENCVAR (length) * sizeof (word_t)); /* clear the new words */ memset (ENCVAR (buf) + wordpos, 0, (ENCVAR (length) - wordpos) * sizeof (word_t)); } wordpos = ENCVAR (bits) / WORD_T_BIT, bitpos = ENCVAR (bits) % WORD_T_BIT; ENCVAR (bits) += bits; ENCVAR (buf) [wordpos] |= ((word_t) data) << bitpos; if (bitpos + bits > WORD_T_BIT) { bitpos = WORD_T_BIT - bitpos; ENCVAR (buf) [++wordpos] = data >>= bitpos; # if !(BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN) for (bits -= bitpos; bits > WORD_T_BIT; bits -= WORD_T_BIT) ENCVAR (buf) [++wordpos] = data >>= WORD_T_BIT; # endif } } /** Remove data from the buffer * @param bits Number of bits to remove */ static void FCN (del) (unsigned bits) { unsigned wordpos, bitpos; ENCVAR (bits) -= bits; wordpos = ENCVAR (bits) / WORD_T_BIT, bitpos = ENCVAR (bits) % WORD_T_BIT; if (bitpos) ENCVAR (buf) [wordpos] &= (((word_t) 1) << bitpos) - 1; memset (ENCVAR (buf) + wordpos, 0, ((ENCVAR (bits) + bits) / WORD_T_BIT - wordpos) * sizeof (word_t)); } /** clear the encoding buffer */ static void FCN (clear) (void) { memset (ENCVAR (buf), 0, NUM_WORDS (ENCVAR (bits)) * sizeof (word_t)); ENCVAR (bits) = ENCVAR (length) = 0; } /** clean up the encoding buffer */ static void FCN (cleanup) (void) { free (ENCVAR (buf)), ENCVAR (buf) = 0; ENCVAR (bits) = ENCVAR (length) = 0; } /** deflate the encoding buffer */ static void FCN (deflate) (void) { #if BYTE_ORDER == BIG_ENDIAN if (ENCVAR (bits) % WORD_T_BIT) ENCVAR (buf) [ENCVAR (bits) / WORD_T_BIT] <<= CHAR_BIT * (((word_t) -NUM_BYTES (ENCVAR (bits))) % sizeof (word_t)); #endif } /** decoding buffer */ static word_t* DECVAR (buf) = 0; /** bit offset to the buffer */ static unsigned DECVAR (bits) = 0; /** Extract data from the buffer * @param bits number of bits to extract * @return the data */ static card_t FCN (dec) (unsigned bits) { unsigned wordpos, bitpos; card_t mask, data; wordpos = DECVAR (bits) / WORD_T_BIT, bitpos = DECVAR (bits) % WORD_T_BIT; DECVAR (bits) += bits; mask = bits < CARD_T_BIT ? (((card_t) 1) << bits) - 1 : ~0; data = (DECVAR (buf) [wordpos] >> bitpos) & mask; if (bitpos + bits > WORD_T_BIT) { bitpos = WORD_T_BIT - bitpos; data |= (((card_t) DECVAR (buf) [++wordpos]) << bitpos) & mask; # if !(BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN) for (bits -= bitpos, bitpos = WORD_T_BIT; bits > WORD_T_BIT; bits -= WORD_T_BIT, bitpos += WORD_T_BIT) data |= (((card_t) DECVAR (buf) [++wordpos]) << bitpos) & mask; # endif } return data; } /** inflate the decoding buffer * @param buf the buffer * @param bytes length of the buffer */ static void FCN (inflate) (word_t* buf, size_t bytes) { DECVAR (buf) = buf; DECVAR (bits) = 0; #if BYTE_ORDER == BIG_ENDIAN if (bytes % sizeof (word_t)) DECVAR (buf) [NUM_WORD_B (bytes) - 1] >>= CHAR_BIT * (((word_t) -bytes) % sizeof (word_t)); #elif BYTE_ORDER == LITTLE_ENDIAN if (bytes % sizeof (word_t)) DECVAR (buf) [NUM_WORD_B (bytes) - 1] &= (((word_t) 1) << (WORD_T_BIT - CHAR_BIT * (((word_t) -bytes) % sizeof (word_t)))) - 1; #endif } maria-1.3.5/Compilation/runtime/event.h0000644000175000017500000000724407762612411020227 0ustar msmakelamsmakela/** @file runtime/event.h * Common definitions for code generated for transitions */ /* Copyright © 2000-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** flag: has the analysis been interrupted? */ extern volatile char* intr; /** flag: has a fatal error occurred? */ extern char* fatal; /** flag: generate arcs? */ extern char arcs; /** flag: generate a flat state space? */ extern char flat; /** weak fairness sets */ extern unsigned wfair[]; /** strong fairness sets */ extern unsigned sfair[]; /** encode the marking and add an event from the current state to it * @param net the net the transition belongs to (0=root) * @param tr the index number of the transition that fired * @param ftr the number of the transition in the flattened net * @param hide flag: is the transition to the state hidden? * @param ctx the call-back context */ enum Error encode (unsigned net, unsigned tr, unsigned ftr, int hide, void* ctx); /** call-back for reporting an enabled synchronising transition * @param tr the index number of the transition * @param ctx the call-back context */ extern void (*syncstate) (unsigned tr, void* ctx); /** append data to the event encoding buffer * @param data data to append * @param bits number of bits (data < 1 << bits) */ extern void enc (card_t data, unsigned bits); /** extract data from the event encoding buffer * @param bits number of bits to extract * @return the extracted data (< 1 << bits) */ extern card_t dec (unsigned bits); /** clear the event encoding buffer */ extern void event_clear (void); /** clean up the event encoding buffer */ extern void event_cleanup (void); /** set up and inflate the event decoding buffer * @param buf the decoding buffer * @param bytes length of the decoding buffer */ extern void inflate (void* buf, size_t bytes); /** deflate the event encoding buffer * @param size (output) number of bytes in the encoded buffer * @return the start address of the encoding buffer */ extern void* deflate (size_t *size); /** decode an event and compute the fairness sets * @param sf flag: compute strong fairness constraints * @return number of the transition */ extern enum Error event_decode (unsigned sf); /** See if an optional variable has been assigned a value * @param i the bit vector holding the "assigned" statuses * @param v index number of the variable */ #define ASSIGNED(i,v) (i.y[v / sizeof *i.y] & (1 << (v % sizeof *i.y))) /** Flag that an optional variable has been assigned a value * @param i the bit vector holding the "assigned" statuses * @param v index number of the variable */ #define ASSIGN(i,v) (i.y[v / sizeof *i.y] |= (1 << (v % sizeof *i.y))) /** Flag that an optional variable has no assigned value * @param i the bit vector holding the "assigned" statuses * @param v index number of the variable */ #define DEASSIGN(i,v) (i.y[v / sizeof *i.y] &= ~(1 << (v % sizeof *i.y))) maria-1.3.5/Compilation/runtime/eventpriv.h0000644000175000017500000000313207762612402021120 0ustar msmakelamsmakela/** @file runtime/eventpriv.h * Definitions for encoding and decoding events */ /* Copyright © 2000-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include "types.h" #include "event.h" #include "codec.h" #define FCN(f) f##_##event #include "codecfcn.h" volatile char* intr; char* fatal; char arcs; char flat; void (*syncstate) (unsigned tr, void* ctx); void enc (card_t data, unsigned bits) { FCN (enc) (data, bits); } card_t dec (unsigned bits) { return FCN (dec) (bits); } void event_clear (void) { FCN (clear) (); } void event_cleanup (void) { FCN (cleanup) (); } void inflate (void* buf, size_t bytes) { FCN (inflate) ((word_t*) buf, bytes); } void* deflate (size_t* size) { FCN (deflate) (); *size = NUM_BYTES (ENCVAR (bits)); return ENCVAR (buf); } maria-1.3.5/Compilation/runtime/statefcn.h0000644000175000017500000001404110232531306020673 0ustar msmakelamsmakela/** @file runtime/statefcn.h * Definitions for encoding and decoding states */ /* Copyright © 2000-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include "mset.h" #include "codec.h" #define FCN(f) f##_##state #include "codecfcn.h" /** flag: has the analysis been interrupted? (defined in eventpriv.h) */ extern volatile char* intr; /** flag: has a fatal error occurred? (defined in eventpriv.h) */ extern char* fatal; /** flag: has modular analysis been disabled? */ char flattened; /** call-back for adding an encoded state and arcs * @param buf the encoded state * @param length length of the encoded state, in bytes * @param err status of evaluating the reject property * @param tr the index number of the transition that fired * @param ftr the number of the transition in the flattened net * @param hide flag: is the transition hidden? * @param ctx the call-back context */ void (*addstate) (void* buf, size_t length, enum Error err, unsigned tr, unsigned ftr, int hide, void* ctx); /** number of bits needed for representing * the state of the property automaton * (0=no property specified) */ unsigned propBits; /** amount and numbers of successor states of the property automaton */ unsigned* propSucc; /** current state, tokens bound from input arcs, successor state */ struct marking mSrc, mIn, mDest; /** array of pointers to multi-set items sorted by multiplicty */ static struct tree** histogram = 0; /** number of distinct items in the current multi-set (length of histogram) */ static card_t distinct = 0; /** maximum number of distinct items so far (capacity of the buffer) */ static card_t maxdistinct = 0; /** sort the multiplicities of a multi-set * @param mset the multi-set to sort * @return total number of items (CARD_T_MAX on error) */ static card_t msort (void* mset) { card_t total = 0; unsigned pos = 0, low, high; register struct tree* t = mset; FIRST (t); distinct = 0; while (t) { register card_t count = t->count; if (!count) { NEXT (t); continue; } if (count > CARD_T_MAX - total) return CARD_T_MAX; total += count; if (distinct) { for (low = 0, high = distinct; low != high; ) { pos = (low + high) >> 1; if (histogram[pos]->count > count) high = pos; else if (++pos == high) break; else low = pos; } memmove (histogram + pos + 1, histogram + pos, (distinct - pos) * sizeof *histogram); } if (++distinct > maxdistinct) { maxdistinct = distinct; if (!histogram) histogram = malloc ((maxdistinct + 1) * sizeof *histogram); else histogram = realloc (histogram, (maxdistinct + 1) * sizeof *histogram); } histogram[pos] = t; NEXT (t); } return total; } /** logarithm of base 2 * @param num number whose logarithm is to be computed * @return number of bits required to represent 0..num */ static unsigned log2 (card_t num) { #if CARD_T_MAX == 4294967295U if (num <= 0x2) return num - 1; if (num <= 0x4) return 2; if (num <= 0x8) return 3; if (num <= 0x10) return 4; if (num <= 0x20) return 5; if (num <= 0x40) return 6; if (num <= 0x80) return 7; if (num <= 0x100) return 8; if (num <= 0x200) return 9; if (num <= 0x400) return 10; if (num <= 0x800) return 11; if (num <= 0x1000) return 12; if (num <= 0x2000) return 13; if (num <= 0x4000) return 14; if (num <= 0x8000) return 15; if (num <= 0x10000) return 16; if (num <= 0x20000) return 17; if (num <= 0x40000) return 18; if (num <= 0x80000) return 19; if (num <= 0x100000) return 20; if (num <= 0x200000) return 21; if (num <= 0x400000) return 22; if (num <= 0x800000) return 23; if (num <= 0x1000000) return 24; if (num <= 0x2000000) return 25; if (num <= 0x4000000) return 26; if (num <= 0x8000000) return 27; if (num <= 0x10000000) return 28; if (num <= 0x20000000) return 29; if (num <= 0x40000000) return 30; if (num <= 0x80000000) return 31; return 32; #else unsigned low = 0, high = CARD_T_BIT; for (;;) { unsigned log = (low + high) >> 1; card_t exp = 1u << log; if (exp < num) { if (low == high) return log; low = log + 1; } else if ((exp >> 1) >= num) high = log - 1; else return log; } #endif } /** Encode an unconstrained cardinality * @param c the cardinality */ static void encc (card_t c) { if (!c) FCN (enc) (0, 1); else { FCN (enc) (1, 1); if (c <= 8) FCN (enc) (0, 1), FCN (enc) (c - 1, 3); else { FCN (enc) (1, 1); if (c <= 0x108) FCN (enc) (0, 1), FCN (enc) (c - 9, 8); else { FCN (enc) (1, 1); if (c <= 0x10108) FCN (enc) (0, 1), FCN (enc) (c - 0x109, 16); else FCN (enc) (1, 1), FCN (enc) (c, CARD_T_BIT); } } } } /** Decode an unconstrained cardinality * @return the cardinality */ static card_t decc (void) { if (!FCN (dec) (1)) return 0; else if (!FCN (dec) (1)) return 1 + FCN (dec) (3); else if (!FCN (dec) (1)) return 9 + FCN (dec) (8); else if (!FCN (dec) (1)) return 0x109 + FCN (dec) (16); else return FCN (dec) (CARD_T_BIT); } /** Clean up all dynamically allocated data structures for the encoder */ void cleanup (void) { FCN (cleanup) (); free (histogram), histogram = 0, maxdistinct = 0; } maria-1.3.5/Compilation/runtime/token.h0000644000175000017500000001035607643253065020230 0ustar msmakelamsmakela/** @file runtime/token.h * Definitions for managing tokens in the unification process */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** declare a token with bindable variables * @param type type of the associated input place * @param num number of the token */ #define TOKEN(type,num) \ static struct { \ card_t count; \ card_t reserved; \ struct tree##type* m; \ struct tree##type* i; \ } token##num /** declare a scalar-valued concrete token * @param type type of the associated input place * @param num number of the token */ #define TOKENC(type,num) \ static struct { \ card_t count; \ card_t reserved; \ struct tree##type* m; \ struct tree##type* i; \ t##type item; \ } token##num /** declare a multiset-valued concrete token * @param type type of the associated input place * @param num number of the token */ #define TOKENM(type,num) \ static struct { \ struct tree##type* m; \ struct tree##type* v; \ } token##num /** declare the only token contained in a place * @param type type of the associated input place * @param num number of the token */ #define TOKEN1(type,num) \ static struct { \ card_t count; \ t##type* item; \ } token##num /** initialize a token with bindable variables * @param num number of the token * @param place the associated input place */ #define INIT_TOKEN(num,place) \ do { \ token##num.reserved = 0; \ token##num.m = place; FIRST (token##num.m); \ while (token##num.m && !token##num.m->count) \ NEXT (token##num.m); \ token##num.i = token##num.m; \ } while (0) /** initialize a scalar-valued concrete token * @param num number of the token * @param place the associated input place */ #define INIT_TOKENC(num,place) (token##num.reserved = 0, token##num.m = place) /** initialize a multiset-valued concrete token * @param num number of the token * @param place the associated input place */ #define INIT_TOKENM(num,place) (token##num.m = place) /** reserve a scalar-valued token * @param num number of the token */ #define RESERVE_TOKEN(num) \ (token##num.i->count -= (token##num.reserved = token##num.count)) \ /** release a scalar-valued token * @param num number of the token */ #define RELEASE_TOKEN(num) \ ((token##num.i->count += token##num.reserved), token##num.reserved = 0) /** determine whether there are scalar-valued enough tokens in a place * @param num number of the token */ #define ENOUGH_TOKEN(num) (token##num.count <= token##num.i->count) /** reserve a multiset-valued token * @param num number of the token * @param t type of the token */ #define RESERVE_TOKENM(num,t) subtract##t (token##num.m, token##num.v) /** release a multiset-valued token * @param num number of the token * @param t type of the token */ #define RELEASE_TOKENM(num,t) \ (token##num.m = copy##t (token##num.m, token##num.v), FREE (token##num.v)) /** step to the next token * @param num number of the token */ #define NEXT_TOKEN(num) NEXT(token##num.i) /** find a token * @param num number of the token * @param t type of the token */ #define FIND_TOKEN(num,t) \ ((token##num.i=find##t (token##num.m, &token##num.item)) && ENOUGH_TOKEN (num)) /** find a sub-multiset * @param num number of the token * @param t type of the token * @return true if the token is contained in the input place */ #define FIND_TOKENM(num,t) subset##t (token##num.v, token##num.m) maria-1.3.5/Compilation/runtime/types.h0000644000175000017500000000230107643253065020243 0ustar msmakelamsmakela/** @file runtime/types.h * Data types used by the generated code */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include #include /** Boolean type (0=false, nonzero=true) */ typedef int bool_t; /** Cardinality type */ typedef unsigned int card_t; #define CARD_T_MAX UINT_MAX #define CARD_T_BIT (CHAR_BIT * sizeof (card_t)) maria-1.3.5/Expression/0000755000175000017500000000000010272511401015107 5ustar msmakelamsmakelamaria-1.3.5/Expression/BinopExpression.C0000644000175000017500000004716707722340367020402 0ustar msmakelamsmakela// binary operator class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BinopExpression.h" #include "IntType.h" #include "CardType.h" #include "LeafValue.h" #include "Net.h" #include "Valuation.h" #include "Printer.h" /** @file BinopExpression.C * Binary operators in integer arithmetic */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ BinopExpression::BinopExpression (enum Op op, class Expression& left, class Expression& right) : Expression (), myOp (op), myLeft (&left), myRight (&right) { assert ((myLeft->getType ()->getKind () == Type::tInt && myRight->getType ()->getKind () == Type::tInt) || (myLeft->getType ()->getKind () == Type::tCard && myRight->getType ()->getKind () == Type::tCard)); assert (myLeft->isBasic () && myRight->isBasic ()); if (myLeft->getType ()->getKind () == Type::tInt) setType (Net::getIntType ()); else setType (Net::getCardType ()); } BinopExpression::~BinopExpression () { myLeft->destroy (); myRight->destroy (); } /** Evaluate a binary operator using signed arithmetics * @param op the operator * @param left the left-hand-side value * @param right the right-hand-side value * @param valuation structure for diagnostic output * @param type type of the value to be returned * @param expr expression to report as the cause of errors * @return the value, or NULL */ inline static class LeafValue* eval (enum BinopExpression::Op op, int_t left, int_t right, const class Valuation& valuation, const class Type& type, const class Expression& expr) { assert (type.getKind () == Type::tInt); switch (op) { case BinopExpression::bPlus: if ((left > 0 && right > 0 && INT_T_MAX - left < right) || (left < 0 && right < 0 && INT_T_MIN - left > right)) { valuation.flag (errOver, expr); return NULL; } return new class LeafValue (type, left + right); case BinopExpression::bMinus: if ((left > 0 && right < 0 && INT_T_MAX + right < left) || (left < 0 && right > 0 && INT_T_MAX + left < right)) { valuation.flag (errOver, expr); return NULL; } return new class LeafValue (type, left - right); case BinopExpression::bDiv: if (left == INT_T_MIN && right == -1) valuation.flag (errOver, expr); else if (right) return new class LeafValue (type, left / right); else valuation.flag (errDiv0, expr); return NULL; case BinopExpression::bMul: if (left > 0) { if (right > 0) { if (INT_T_MAX / left < right) { valuation.flag (errOver, expr); return NULL; } } else if (INT_T_MIN / left > right) { valuation.flag (errOver, expr); return NULL; } } else if (right > 0) { if (INT_T_MIN / left < right) { valuation.flag (errOver, expr); return NULL; } } else if (INT_T_MAX / left > right) { valuation.flag (errOver, expr); return NULL; } return new class LeafValue (type, left * right); case BinopExpression::bMod: if (right > 0 && left >= 0) return new class LeafValue (type, left % right); else { valuation.flag (errMod, expr); return NULL; } case BinopExpression::bAnd: return new class LeafValue (type, left & right); case BinopExpression::bOr: return new class LeafValue (type, left | right); case BinopExpression::bXor: return new class LeafValue (type, left ^ right); case BinopExpression::bRol: if (right < 0 || right >= int_t (INT_T_BIT)) { shiftError: valuation.flag (errShift, expr); return NULL; } return new class LeafValue (type, left << right); case BinopExpression::bRor: if (right < 0 || right >= int_t (INT_T_BIT)) goto shiftError; return new class LeafValue (type, left >> right); } assert (false); return NULL; } /** Evaluate a binary operator using unsigned arithmetics * @param op the operator * @param left the left-hand-side value * @param right the right-hand-side value * @param valuation structure for diagnostic output * @param type type of the value to be returned * @param expr expression to report as the cause of errors * @return the value, or NULL */ inline static class LeafValue* eval (enum BinopExpression::Op op, card_t left, card_t right, const class Valuation& valuation, const class Type& type, const class Expression& expr) { switch (op) { case BinopExpression::bPlus: if (CARD_T_MAX - left < right) { valuation.flag (errOver, expr); return NULL; } return new class LeafValue (type, left + right); case BinopExpression::bMinus: if (left < right) { valuation.flag (errOver, expr); return NULL; } return new class LeafValue (type, left - right); case BinopExpression::bDiv: if (right) return new class LeafValue (type, left / right); else { valuation.flag (errDiv0, expr); return NULL; } case BinopExpression::bMul: if (left && CARD_T_MAX / left < right) { valuation.flag (errOver, expr); return NULL; } return new class LeafValue (type, left * right); case BinopExpression::bMod: if (!right) { valuation.flag (errMod, expr); return NULL; } return new class LeafValue (type, left % right); case BinopExpression::bAnd: return new class LeafValue (type, left & right); case BinopExpression::bOr: return new class LeafValue (type, left | right); case BinopExpression::bXor: return new class LeafValue (type, left ^ right); case BinopExpression::bRol: if (right >= CARD_T_BIT) { shiftError: valuation.flag (errShift, expr); return NULL; } return new class LeafValue (type, left << right); case BinopExpression::bRor: if (right >= CARD_T_BIT) goto shiftError; return new class LeafValue (type, left >> right); } assert (false); return NULL; } class Value* BinopExpression::do_eval (const class Valuation& valuation) const { class Value* left = myLeft->eval (valuation); if (!left) return NULL; assert (left->getKind () == Value::vLeaf); class Value* right = myRight->eval (valuation); if (!right) { delete left; return NULL; } assert (right->getKind () == Value::vLeaf); if (getType ()->getKind () == Type::tInt) { assert (left->getType ().getKind () == Type::tInt); assert (right->getType ().getKind () == Type::tInt); if (class Value* result = ::eval (myOp, int_t (static_cast(*left)), int_t (static_cast(*right)), valuation, *getType (), *this)) { delete left; delete right; return constrain (valuation, result); } } else { assert (left->getType ().getKind () == Type::tCard); assert (right->getType ().getKind () == Type::tCard); if (class Value* result = ::eval (myOp, card_t (static_cast(*left)), card_t (static_cast(*right)), valuation, *getType (), *this)) { delete left; delete right; return constrain (valuation, result); } } delete left; delete right; return NULL; } class Expression* BinopExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* left = myLeft->ground (valuation, transition, declare); if (!left) return NULL; class Expression* right = myRight->ground (valuation, transition, declare); if (!right) { left->destroy (); return NULL; } assert (valuation.isOK ()); if (left == myLeft && right == myRight) { left->destroy (); right->destroy (); return copy (); } else { class Expression* expr = new class BinopExpression (myOp, *left, *right); expr->setType (*getType ()); return expr->ground (valuation); } } class Expression* BinopExpression::substitute (class Substitution& substitution) { class Expression* left = myLeft->substitute (substitution); class Expression* right = myRight->substitute (substitution); if (left == myLeft && right == myRight) { left->destroy (); right->destroy (); return copy (); } else { class Expression* expr = new class BinopExpression (myOp, *left, *right); expr->setType (*getType ()); return expr->cse (); } } bool BinopExpression::depends (const class VariableSet& vars, bool complement) const { return myLeft->depends (vars, complement) || myRight->depends (vars, complement); } bool BinopExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myLeft->forExpressions (operation, data) && myRight->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" # include "Constant.h" void BinopExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { assert (myLeft->getType () && myRight->getType ()); assert (myLeft->getType ()->getKind () == myRight->getType ()->getKind ()); class StringBuffer& out = cexpr.getOut (); const bool sign = myLeft->getType ()->getKind () == Type::tInt; char* left; char* right; if (cexpr.getVariable (*myLeft, left)) myLeft->compile (cexpr, indent, left, vars); if (cexpr.getVariable (*myRight, right)) myRight->compile (cexpr, indent, right, vars); const class LeafValue* vleft = 0; const class LeafValue* vright = 0; if (myLeft->getKind () == Expression::eConstant) { const class Value& v = static_cast(myLeft)->getValue (); assert (v.getKind () == Value::vLeaf); vleft = &static_cast(v); } if (myRight->getKind () == Expression::eConstant) { const class Value& v = static_cast(myRight)->getValue (); assert (v.getKind () == Value::vLeaf); vright = &static_cast(v); } switch (myOp) { case bPlus: out.indent (indent); out.append ("if ("); if (sign) { if (!vleft && !vright) out.append ("("); if ((!vleft || int_t (*vleft) > 0) && (!vright || int_t (*vright) > 0)) { if (!vleft) out.append (left), out.append (">0 && "); if (!vright) out.append (right), out.append (">0 && "); out.append ("INT_MAX-"); out.append (left), out.append ("<"), out.append (right); } if (!vleft && !vright) { out.append (") ||\n"); out.indent (indent + 4); out.append ("("); } if ((!vleft || int_t (*vleft) < 0) && (!vright || int_t (*vright) < 0)) { if (!vleft) out.append (left), out.append ("<0 && "); if (!vright) out.append (right), out.append ("<0 && "); out.append ("INT_MIN-"); out.append (left), out.append (">"), out.append (right); } if (!vleft && !vright) out.append (")"); } else { out.append ("UINT_MAX-"); out.append (left); out.append ("<"); out.append (right); } out.append (")\n"); cexpr.compileError (indent + 2, errOver); out.indent (indent); out.append (lvalue); out.append ("="); out.append (left); out.append ("+"); out.append (right); out.append (";\n"); break; case bMinus: out.indent (indent); out.append ("if ("); if (sign) { if (!vleft && !vright) out.append ("("); if ((!vleft || int_t (*vleft) > 0) && (!vright || int_t (*vright) < 0)) { if (!vleft) out.append (left), out.append (">0 && "); if (!vright) out.append (right), out.append ("<0 && "); out.append ("INT_MAX+"); out.append (right), out.append ("<"), out.append (left); } if (!vleft && !vright) { out.append (") ||\n"); out.indent (indent + 4); out.append ("("); } if ((!vleft || int_t (*vleft) < 0) && (!vright || int_t (*vright) > 0)) { if (!vleft) out.append (left), out.append ("<0 && "); if (!vright) out.append (right), out.append (">0 && "); out.append ("INT_MAX+"); out.append (left), out.append ("<"), out.append (right); } if (!vleft && !vright) out.append (")"); } else { out.append (left); out.append ("<"); out.append (right); } out.append (")\n"); cexpr.compileError (indent + 2, errOver); out.indent (indent); out.append (lvalue); out.append ("="); out.append (left); out.append ("-"); out.append (right); out.append (";\n"); break; case bDiv: out.indent (indent); out.append ("if (!"); out.append (right); out.append (")\n"); cexpr.compileError (indent + 2, errDiv0); if (sign) { out.indent (indent); out.append ("if ("); out.append (right); out.append ("==-1 && "); out.append (left); out.append ("==INT_MIN)\n"); cexpr.compileError (indent + 2, errOver); } out.indent (indent); out.append (lvalue); out.append ("="); out.append (left); out.append ("/"); out.append (right); out.append (";\n"); break; case bMul: out.indent (indent); out.append ("if ("); out.append (left); out.append ("&&\n"); out.indent (indent + 4); out.append ("("); if (sign) { if (!vleft) { out.append (left), out.append (">0\n"); out.indent (indent + 5); out.append ("? ("); } if (!vleft || int_t (*vleft) > 0) { if (!vright) { out.append (right); out.append (">0\n"); out.indent (indent + 8); out.append ("? "); } if (!vright || int_t (*vright) > 0) { out.append ("INT_MAX/"); out.append (left); out.append ("<"); out.append (right); } if (!vright) { out.append ("\n"); out.indent (indent + 8); out.append (": "); } if (!vright || int_t (*vright) <= 0) { out.append ("INT_MIN/"); out.append (left); out.append (">"); out.append (right); } } if (!vleft) { out.append (")\n"); out.indent (indent + 5); out.append (": ("); } if (!vleft || int_t (*vleft) <= 0) { if (!vright) { out.append (right); out.append (">0\n"); out.indent (indent + 8); out.append ("? "); } if (!vright || int_t (*vright) > 0) { out.append ("INT_MIN/"); out.append (left); out.append ("<"); out.append (right); } if (!vright) { out.append ("\n"); out.indent (indent + 8); out.append (": "); } if (!vright || int_t (*vright) <= 0) { out.append ("INT_MAX/"); out.append (left); out.append (">"); out.append (right); } } if (!vleft) out.append (")"); } else { out.append ("UINT_MAX/"); out.append (left); out.append ("<"); out.append (right); } out.append ("))\n"); cexpr.compileError (indent + 2, errOver); out.indent (indent); out.append (lvalue); out.append ("="); out.append (left); out.append ("*"); out.append (right); out.append (";\n"); break; case bMod: out.indent (indent); out.append ("if ("); if (sign) { out.append (left), out.append ("<0 || "); out.append (right), out.append ("<=0"); } else { out.append ("!"); out.append (right); } out.append (")\n"); cexpr.compileError (indent + 2, errMod); out.indent (indent); out.append (lvalue); out.append ("="); out.append (left); out.append ("%"); out.append (right); out.append (";\n"); break; case bAnd: out.indent (indent); out.append (lvalue); out.append ("="); out.append (left); out.append ("&"); out.append (right); out.append (";\n"); break; case bOr: out.indent (indent); out.append (lvalue); out.append ("="); out.append (left); out.append ("|"); out.append (right); out.append (";\n"); break; case bXor: out.indent (indent); out.append (lvalue); out.append ("="); out.append (left); out.append ("^"); out.append (right); out.append (";\n"); break; case bRol: case bRor: out.indent (indent); out.append ("if ("); if (sign) { out.append (right); out.append ("<0 || "); } out.append (right); out.append (">= CHAR_BIT * sizeof "); out.append (left); out.append (")\n"); cexpr.compileError (indent + 2, errShift); out.indent (indent); out.append (lvalue); out.append ("="); out.append (left); out.append (myOp == bRol ? "<<" : ">>"); out.append (right); out.append (";\n"); break; } delete[] left; delete[] right; compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE /** Convert an operator to a string * @param op the operator to convert * @return a string corresponding to the operator */ inline static const char* getOpString (enum BinopExpression::Op op) { switch (op) { case BinopExpression::bPlus: return "+"; case BinopExpression::bMinus: return "-"; case BinopExpression::bDiv: return "/"; case BinopExpression::bMul: return "*"; case BinopExpression::bMod: return "%"; case BinopExpression::bAnd: return "&"; case BinopExpression::bOr: return "|"; case BinopExpression::bXor: return "^"; case BinopExpression::bRol: return "<<"; case BinopExpression::bRor: return ">>"; } return "???"; } /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eUnionType: case Expression::eVectorIndex: case Expression::eUnop: case Expression::eBufferUnop: case Expression::eTypecast: case Expression::eCardinality: return false; case Expression::eStruct: case Expression::eUnion: case Expression::eVector: case Expression::eBooleanBinop: case Expression::eNot: case Expression::eRelop: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: assert (false); case Expression::eBinop: case Expression::eIfThenElse: break; } return true; } void BinopExpression::display (const class Printer& printer) const { if (::needParentheses (myLeft->getKind ())) { printer.delimiter ('(')++; myLeft->display (printer); --printer.delimiter (')'); } else myLeft->display (printer); printer.printRaw (::getOpString (myOp)); if (::needParentheses (myRight->getKind ())) { printer.delimiter ('(')++; myRight->display (printer); --printer.delimiter (')'); } else myRight->display (printer); } maria-1.3.5/Expression/BinopExpression.h0000644000175000017500000001140707722340367020433 0ustar msmakelamsmakela// binary operator class -*- c++ -*- #ifndef BINOPEXPRESSION_H_ # define BINOPEXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file BinopExpression.h * Binary operators in integer arithmetic */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Binary operator */ class BinopExpression : public Expression { public: /** Binary operators */ enum Op { bPlus, bMinus, bDiv, bMul, bMod, bAnd, bOr, bXor, bRol, bRor }; /** Constructor * @param op Operator * @param left Left-hand expression of the operator * @param right Right-hand expression of the operator */ BinopExpression (enum Op op, class Expression& left, class Expression& right); private: /** Copy constructor */ BinopExpression (const BinopExpression& old); /** Assignment operator */ BinopExpression& operator= (const BinopExpression& old); protected: /** Destructor */ ~BinopExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eBinop; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class BinopExpression& other) const { return myOp == other.myOp && *myLeft == *other.myLeft && *myRight == *other.myRight; } /** Ordering comparison operator */ bool operator< (const class BinopExpression& other) const { if (myOp < other.myOp) return true; if (other.myOp < myOp) return false; if (*myLeft < *other.myLeft) return true; if (*other.myLeft < *myLeft) return false; return *myRight < *other.myRight; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The operator */ enum Op myOp; /** Left-hand expression */ class Expression* myLeft; /** Right-hand expression */ class Expression* myRight; }; #endif // BINOPEXPRESSION_H_ maria-1.3.5/Expression/BooleanBinop.C0000644000175000017500000002541207722340367017607 0ustar msmakelamsmakela// Maria boolean binary operator expression class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BooleanBinop.h" #include "BoolType.h" #include "LeafValue.h" #include "Net.h" #include "Constant.h" #include "NotExpression.h" #include "VariableDefinition.h" #include "Property.h" #include "Printer.h" /** @file BooleanBinop.C * Binary operators in Boolean arithmetic */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ BooleanBinop::BooleanBinop (bool conj, class Expression& left, class Expression& right) : Expression (), myConj (conj), myLeft (&left), myRight (&right) { assert (myLeft->getKind () == Expression::eUndefined || myLeft->getType ()->getKind () == Type::tBool); assert (myRight->getKind () == Expression::eUndefined || myRight->getType ()->getKind () == Type::tBool); setType (Net::getBoolType ()); } BooleanBinop::~BooleanBinop () { myLeft->destroy (); myRight->destroy (); } bool BooleanBinop::isBasic () const { return (!myLeft || myLeft->isBasic ()) && (!myRight || myRight->isBasic ()); } bool BooleanBinop::isTemporal () const { return (myLeft && myLeft->isTemporal ()) || (myRight && myRight->isTemporal ()); } class Expression* BooleanBinop::construct (bool conj, class Expression& left, class Expression& right) { if (left == right) { right.destroy (); return &left; } else if (left.getKind () == Expression::eNot && right.getKind () == Expression::eNot) return NotExpression::construct (*construct (!conj, *NotExpression::construct (left), *NotExpression::construct (right))); else if (left.getKind () == Expression::eConstant) { const class Value& v = static_cast(left).getValue (); assert (v.getKind () == Value::vLeaf); if (conj == bool (static_cast(v))) { left.destroy (); return &right; } else { right.destroy (); return &left; } } else if (right.getKind () == Expression::eConstant) { const class Value& v = static_cast(right).getValue (); assert (v.getKind () == Value::vLeaf); if (conj == bool (static_cast(v))) { right.destroy (); return &left; } // optimising "left" away could break short-circuit evaluation } return (new class BooleanBinop (conj, left, right))->cse (); } class Value* BooleanBinop::do_eval (const class Valuation& valuation) const { class Value* v = myLeft->eval (valuation); if (!v) return NULL; assert (v->getType ().getKind () == Type::tBool); assert (v->getKind () == Value::vLeaf); if (myConj == bool (static_cast(*v))) { delete v; if (!(v = myRight->eval (valuation))) return 0; assert (v->getType ().getKind () == Type::tBool); assert (v->getKind () == Value::vLeaf); } return constrain (valuation, v); } class Expression* BooleanBinop::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* left = myLeft->ground (valuation, transition, declare); if (!left) return NULL; // short-circuit evaluation if (left->getKind () == Expression::eConstant) { const class Value& v = static_cast(left)->getValue (); assert (v.getKind () == Value::vLeaf); if (myConj != bool (static_cast(v))) return left; left->destroy (); return myRight->ground (valuation, transition, declare); } class Expression* right = myRight->ground (valuation, transition, declare); if (!right) { left->destroy (); return NULL; } assert (valuation.isOK ()); if (left == myLeft && right == myRight) { left->destroy (); right->destroy (); return copy (); } else return construct (myConj, *left, *right)->ground (valuation); } class Expression* BooleanBinop::substitute (class Substitution& substitution) { class Expression* left = myLeft->substitute (substitution); class Expression* right = myRight->substitute (substitution); if (left == myLeft && right == myRight) { left->destroy (); right->destroy (); return copy (); } else { class Expression* expr = construct (myConj, *left, *right); expr->setType (*getType ()); return expr; } } bool BooleanBinop::depends (const class VariableSet& vars, bool complement) const { return myLeft->depends (vars, complement) || myRight->depends (vars, complement); } bool BooleanBinop::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myLeft->forExpressions (operation, data) && myRight->forExpressions (operation, data); } class Expression* BooleanBinop::disqualify (const class Transition& transition) { class Expression* left = myLeft->disqualify (transition); class Expression* right = myRight->disqualify (transition); if (!left || !right) { if (!myConj) { if (left) return left; if (right) return right; } left->destroy (), right->destroy (); return 0; } if (left == myLeft && right == myRight) { left->destroy (), right->destroy (); return copy (); } class Expression* expr = construct (myConj, *left, *right); class Valuation valuation; if (class Value* v = expr->eval (valuation)) { expr->destroy (); return (new class Constant (*v))->cse (); } else return expr; } class Ltl* BooleanBinop::toFormula (class Property& property) { return (myLeft->isTemporal () || myRight->isTemporal ()) ? property.addBinop (myConj ? Property::opAnd : Property::opOr, *myLeft, *myRight) : Expression::toFormula (property); } class Expression* BooleanBinop::quantify (bool conj, class Expression& expr, class Valuation& valuation, class Transition* transition, class VariableDefinition& variable, class Expression* condition, bool declare) { assert (valuation.isOK ()); assert (expr.getType ()->getKind () == Type::tBool); assert (!condition || condition->getType ()->getKind () == Type::tBool); class Expression* q = expr.copy (); if (condition) q = conj ? construct (false, *NotExpression::construct (*condition), *q) : construct (true, *condition, *q); valuation.setValue (variable, variable.getType ().getFirstValue ()); class Expression* result = NULL; /** the outcome in case it is constant */ bool outcome = conj; do { if (class Expression* e = q->ground (valuation, transition, declare)) { assert (valuation.isOKorVar ()); valuation.clearErrors (); if (e->getKind () == Expression::eConstant) { const class Value& v = static_cast(e)->getValue (); assert (v.getKind () == Value::vLeaf); if (conj != bool (static_cast(v))) { result->destroy (), result = 0; outcome = !conj; break; } } else result = result ? construct (conj, *result, *e) : e; } else { result->destroy (), q->destroy (); return NULL; } } while (valuation.increment (variable)); q->destroy (); if (!result) result = (new class Constant (*new class LeafValue (Net::getBoolType (), outcome)))->cse (); return result; } #ifdef EXPR_COMPILE # include "CExpression.h" void BooleanBinop::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { class StringBuffer& out = cexpr.getOut (); myLeft->compile (cexpr, indent, lvalue, vars); out.indent (indent); out.append ("if ("); if (!myConj) out.append ("!"); out.append (lvalue); out.append (") {\n"); bool* checkpoint; unsigned checkpointSize = cexpr.getCheckpoint (checkpoint); myRight->compile (cexpr, indent + 2, lvalue, vars); cexpr.setCheckpoint (indent + 2, checkpoint, checkpointSize); delete[] checkpoint; out.indent (indent); out.append ("}\n"); compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eUnionType: case Expression::eVectorIndex: case Expression::eTypecast: case Expression::eCardinality: case Expression::eRelop: case Expression::eNot: case Expression::eSet: return false; case Expression::eBinop: case Expression::eStruct: case Expression::eUnion: case Expression::eVector: case Expression::eUnop: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferUnop: case Expression::eBufferWrite: case Expression::eBufferIndex: case Expression::eMarking: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: assert (false); case Expression::eTransitionQualifier: case Expression::eBooleanBinop: case Expression::eIfThenElse: case Expression::eTemporalBinop: case Expression::eTemporalUnop: break; } return true; } void BooleanBinop::display (const class Printer& printer) const { if (isAtomic ()) { printer.printRaw ("atom"); printer.delimiter ('(')++; } if (::needParentheses (myLeft->getKind ())) { printer.delimiter ('(')++; myLeft->display (printer); --printer.delimiter (')'); } else myLeft->display (printer); printer.printRaw (myConj ? "&&" : "||"); if (::needParentheses (myRight->getKind ())) { printer.delimiter ('(')++; myRight->display (printer); --printer.delimiter (')'); } else myRight->display (printer); if (isAtomic ()) --printer.delimiter (')'); } maria-1.3.5/Expression/BooleanBinop.h0000644000175000017500000001525207722340367017655 0ustar msmakelamsmakela// Maria boolean binary operator expression class -*- c++ -*- #ifndef BOOLEANBINOP_H_ # define BOOLEANBINOP_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file BooleanBinop.h * Binary operators in Boolean arithmetic */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Boolean binary operator expression */ class BooleanBinop : public Expression { protected: /** Constructor * @param conj flag: conjunction (instead of disjunction) * @param left left-hand-side expression * @param right right-hand-side expression */ BooleanBinop (bool conj, class Expression& left, class Expression& right); private: /** Copy constructor */ BooleanBinop (const class BooleanBinop& old); /** Assignment operator */ class BooleanBinop& operator= (const class BooleanBinop& old); protected: /** Destructor */ ~BooleanBinop (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eBooleanBinop; } /** Determine whether this is a basic expression */ bool isBasic () const; /** Determine whether this is a temporal logic expression */ bool isTemporal () const; /** Construct a BooleanBinop, reducing negations with De Morgan's rule * @param conj flag: conjunction (instead of disjunction) * @param left left-hand-side expression * @param right right-hand-side expression * @return a corresponding logic expression */ static class Expression* construct (bool conj, class Expression& left, class Expression& right); /** Determine if this is a conjunction (instead of disjunction) */ bool isConj () const { return myConj; } /** Determine the left-hand expression */ const class Expression& getLeft () const { return *myLeft; } /** Determine the right-hand expression */ const class Expression& getRight () const { return *myRight; } /** Equality comparison operator */ bool operator== (const class BooleanBinop& other) const { return myConj == other.myConj && *myLeft == *other.myLeft && *myRight == *other.myRight; } /** Ordering comparison operator */ bool operator< (const class BooleanBinop& other) const { if (myConj < other.myConj) return true; if (other.myConj < myConj) return false; if (*myLeft < *other.myLeft) return true; if (*other.myLeft < *myLeft) return false; return *myRight < *other.myRight; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Remove transition qualifiers from the expression * @param transition the transition for which the expression is qualified * @return the expession without qualifiers, or NULL */ class Expression* disqualify (const class Transition& transition); /** Translate the expression to a list of temporal logic connectives * and Boolean propositions * @param property the property automaton * @return the translated object */ class Ltl* toFormula (class Property& property); /** Quantify an expression * @param conj flag: connect with conjunction (instead of disjunction) * @param expr expression to quantify * @param valuation variable substitutions (mainly for error reporting) * @param transition transition for registering quantified variables * @param variable the quantifier variable * @param condition quantification condition (optional) * @param declare flag: declare new variables if required * @return a corresponding expression, or NULL */ static class Expression* quantify (bool conj, class Expression& expr, class Valuation& valuation, class Transition* transition, class VariableDefinition& variable, class Expression* condition, bool declare); # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** Flag: conjunction operation (instead of disjunction) */ bool myConj; /** Left-hand expression */ class Expression* myLeft; /** Right-hand expression */ class Expression* myRight; }; #endif // BOOLEANBINOP_H_ maria-1.3.5/Expression/BufferExpression.C0000644000175000017500000002150307722340367020526 0ustar msmakelamsmakela// Maria buffer expression class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BufferExpression.h" #include "BufferValue.h" #include "Printer.h" #include /** @file BufferExpression.C * Queue or stack constructor */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ BufferExpression::BufferExpression (const class BufferType& type) : Expression (), myComponents (NULL) { assert (type.getSize () > 0); myComponents = new class Expression*[type.getSize ()]; memset (myComponents, 0, type.getSize () * sizeof *myComponents); setType (type); } BufferExpression::~BufferExpression () { card_t size = static_cast(getType ())->getSize (); for (card_t i = 0; i < size && myComponents[i]; i++) myComponents[i]->destroy (); delete[] myComponents; } void BufferExpression::setType (const class Type& type) { assert (type.getKind () == Type::tBuffer); const class Type& itemType = static_cast(type).getItemType (); for (card_t size = static_cast(type).getSize (), i = 0; i < size && myComponents[i]; i++) myComponents[i]->setType (itemType); Expression::setType (type); } class Value* BufferExpression::do_eval (const class Valuation& valuation) const { class BufferValue* buffer = new class BufferValue (*getType ()); card_t size = static_cast(getType ())->getSize (); for (card_t i = 0; i < size && myComponents[i]; i++) { if (class Value* v = myComponents[i]->eval (valuation)) { assert (&v->getType () == &static_cast (getType ())->getItemType ()); (*buffer)[i] = v; } else { delete buffer; return NULL; } } return constrain (valuation, buffer); } class Expression* BufferExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { bool same = true; const class BufferType* const type = static_cast(getType ()); class BufferExpression* expr = new class BufferExpression (*type); card_t size = static_cast(getType ())->getSize (); for (card_t i = 0; i < size && myComponents[i]; i++) { class Expression* e = myComponents[i]->ground (valuation, transition, declare); if (!e) { expr->destroy (); return NULL; } if (e != myComponents[i]) same = false; expr->myComponents[i] = e; } assert (valuation.isOK ()); if (same) { expr->destroy (); return copy (); } return static_cast(expr)->ground (valuation); } class Expression* BufferExpression::substitute (class Substitution& substitution) { bool same = true; const class BufferType* const type = static_cast(getType ()); class BufferExpression* expr = new class BufferExpression (*type); card_t size = static_cast(getType ())->getSize (); for (card_t i = 0; i < size && myComponents[i]; i++) { class Expression* e = myComponents[i]->substitute (substitution); if (e != myComponents[i]) same = false; expr->myComponents[i] = e; } if (same) { expr->destroy (); return copy (); } else return expr->cse (); } bool BufferExpression::depends (const class VariableSet& vars, bool complement) const { card_t size = static_cast(getType ())->getSize (); for (card_t i = 0; i < size && myComponents[i]; i++) if (myComponents[i]->depends (vars, complement)) return true; return false; } bool BufferExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { card_t size = static_cast(getType ())->getSize (); if (!(*operation) (*this, data)) return false; for (card_t i = 0; i < size && myComponents[i]; i++) if (!myComponents[i]->forExpressions (operation, data)) return false; return true; } bool BufferExpression::isCompatible (const class Value& value, const class Valuation& valuation) const { assert (value.getKind () == Value::vBuffer && value.getType ().getKind () == Type::tBuffer); const class BufferValue& bv = static_cast(value); const class BufferType* bt = static_cast(getType ()); assert (bv.getSize () == static_cast(bv.getType ()).getSize ()); if (!bv.getType ().isAssignable (*getType ())) return false; for (card_t size = bt->getSize (), i = 0; i < size; i++) if (!myComponents[i]) return !bv[i]; else if (!bv[i]) return !myComponents[i]; else if (!myComponents[i]->isCompatible (*bv[i], valuation)) return false; return true; } void BufferExpression::getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const { assert (value.getKind () == Value::vBuffer); assert (&value.getType () == getType ()); const class BufferValue& bv = static_cast(value); card_t size = getSize (); if (bv.getCapacity () == size) for (card_t i = 0; i < size; i++) myComponents[i]->getLvalues (*bv[i], valuation, vars); } void BufferExpression::getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const { for (card_t size = getSize (), i = 0; i < size; i++) myComponents[i]->getLvalues (rvalues, lvalues); } #ifdef EXPR_COMPILE # include # include "CExpression.h" void BufferExpression::compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const { assert (!!lvalue); const size_t len = strlen (lvalue); char* const newlvalue = new char[len + 25]; char* const suffix = newlvalue + len; memcpy (newlvalue, lvalue, len); const card_t size = static_cast(getType ())->getSize (); for (card_t i = 0; i < size; i++) { snprintf (suffix, 25, ".a[%u]", i); myComponents[i]->compileLvalue (cexpr, indent, vars, newlvalue); } delete[] newlvalue; } void BufferExpression::compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const { const size_t len = strlen (value); char* const val = new char[len + 25]; char* const suffix = val + len; memcpy (val, value, len); class StringBuffer& out = cexpr.getOut (); out.indent (indent), out.append ("if ("); out.append (value), out.append (".s!="); out.append (getSize ()); out.append (")\n"); cexpr.compileError (indent + 2, errComp); const card_t size = static_cast(getType ())->getSize (); for (card_t i = 0; i < size; i++) { snprintf (suffix, 25, ".a[%u]", i); myComponents[i]->compileCompatible (cexpr, indent, vars, val); } delete[] val; } void BufferExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { size_t len = strlen (lvalue); char* const newlvalue = new char[len + 25]; char* const suffix = newlvalue + len; memcpy (newlvalue, lvalue, len); class StringBuffer& out = cexpr.getOut (); card_t size = getSize (); snprintf (suffix, 25, ".s=%u", size); out.indent (indent), out.append (newlvalue); out.append (";\n"); for (card_t i = 0; i < size; i++) { snprintf (suffix, 25, ".a[%u]", i); myComponents[i]->compile (cexpr, indent, newlvalue, vars); } delete[] newlvalue; compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE void BufferExpression::display (const class Printer& printer) const { const class BufferType* type = static_cast(getType ()); printer.delimiter ('{')++; for (card_t i = 0; myComponents[i]; ) { myComponents[i]->display (printer); if (++i == type->getSize () || !myComponents[i]) break; printer.delimiter (','); } --printer.delimiter ('}'); } maria-1.3.5/Expression/BufferExpression.h0000644000175000017500000002016407722340367020575 0ustar msmakelamsmakela// Maria buffer expression class -*- c++ -*- #ifndef BUFFEREXPRESSION_H_ # define BUFFEREXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include "BufferType.h" # include /** @file BufferExpression.h * Queue or stack constructor */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Buffer initialization expression */ class BufferExpression : public Expression { public: /** Constructor * @param type Type of the expression */ BufferExpression (const class BufferType& type); private: /** Copy constructor */ BufferExpression (const class BufferExpression& old); /** Assignment operator */ class BufferExpression& operator= (const class BufferExpression& old); protected: /** Destructor */ ~BufferExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eBuffer; } /** Set the type of the expression * @param type Type of the expression */ void setType (const class Type& type); /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Append a component * @param component The component expression to be appended */ void append (class Expression& component) { assert (hasCapacity ()); assert (component.isBasic ()); myComponents[getSize ()] = &component; } /** Determine whether there is capacity left */ bool hasCapacity () const { card_t size = static_cast(getType ())->getSize (); return size && !myComponents[size - 1]; } /** Determine the current size of the buffer expression */ card_t getSize () const { for (card_t i = static_cast(getType ())->getSize (); i--; ) { if (myComponents[i]) return i + 1; } return 0; } /** Equality comparison operator */ bool operator== (const class BufferExpression& other) const { const class BufferType* v = static_cast(getType ()); const class BufferType* u = static_cast(other.getType ()); if (v->isStack () != u->isStack () || v->getSize () != u->getSize ()) return false; for (card_t i = 0; i < v->getSize (); i++) if (!myComponents[i]) { if (other.myComponents[i]) return false; else continue; } else if (!other.myComponents[i] || !(*(myComponents[i]) == *(other.myComponents[i]))) return false; return true; } /** Ordering comparison operator */ bool operator< (const class BufferExpression& other) const { const class BufferType* v = static_cast(getType ()); const class BufferType* u = static_cast(other.getType ()); if (v->getSize () < u->getSize ()) return true; if (u->getSize () < v->getSize ()) return false; if (!v->isStack () && u->isStack ()) return true; if (!u->isStack () && v->isStack ()) return false; for (card_t i = v->getSize (); i--; ) if (!myComponents[i]) { if (other.myComponents[i]) return true; else continue; } else if (!other.myComponents[i]) return false; else if (*(myComponents[i]) < *(other.myComponents[i])) return true; else if (*(other.myComponents[i]) < *(myComponents[i])) return false; return false; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Determine whether the expression is compatible with the specified value, * neglecting subexpressions that cannot be evaluated * @param value value the expression will be compared to * @param valuation variable substitutions * @return true if the expression is compatible with the value */ bool isCompatible (const class Value& value, const class Valuation& valuation) const; /** Unify variables from this expression * @param value the value the expression should evaluate to * @param valuation variable substitutions * @param vars the variables to unify */ void getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const; /** Determine which variables could be unified from this expression * @param rvalues variables unified so far * @param lvalues (output) variables that could be unified * @return variables that could be unified */ void getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const; # ifdef EXPR_COMPILE /** Generate lvalue gathering code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables * @param lvalue C expression referring to the value */ void compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const; /** Generate compatibility check code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables that have been unified * @param value C expression referring to the desired value */ void compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const; /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The expressions for the buffer components */ class Expression** myComponents; }; #endif // BUFFEREXPRESSION_H_ maria-1.3.5/Expression/BufferIndex.C0000644000175000017500000000530607722340367017441 0ustar msmakelamsmakela// Buffer indexing expression (used only during parsing) -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BufferIndex.h" /** @file BufferIndex.C * Buffer indexing expression (transient storage used during parsing) */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ BufferIndex::BufferIndex (class Expression& buffer, class Expression& i) : myBuffer (&buffer), myIndex (&i) { assert (myBuffer && myIndex); assert (myBuffer->getType ()->getKind () == Type::tBuffer); assert (myIndex->getType ()->getKind () == Type::tCard); assert (myBuffer->isBasic () && myIndex->isBasic ()); setType (*myBuffer->getType ()); } BufferIndex::~BufferIndex () { myBuffer->destroy (); myIndex->destroy (); } class Value* BufferIndex::do_eval (const class Valuation& valuation) const { return myBuffer->eval (valuation); } class Expression* BufferIndex::ground (const class Valuation& valuation, class Transition* transition, bool declare) { return myBuffer->ground (valuation, transition, declare); } class Expression* BufferIndex::substitute (class Substitution& substitution) { return myBuffer->substitute (substitution); } bool BufferIndex::depends (const class VariableSet& vars, bool complement) const { return myBuffer->depends (vars, complement); } bool BufferIndex::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myBuffer->forExpressions (operation, data); } #ifdef EXPR_COMPILE void BufferIndex::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { myBuffer->compile (cexpr, indent, lvalue, vars); } #endif // EXPR_COMPILE void BufferIndex::display (const class Printer& printer) const { myBuffer->display (printer); } maria-1.3.5/Expression/BufferIndex.h0000644000175000017500000001132107722340367017500 0ustar msmakelamsmakela// Buffer indexing expression (used only during parsing) -*- c++ -*- #ifndef BUFFERINDEX_H_ # define BUFFERINDEX_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file BufferIndex.h * Buffer indexing expression (transient storage used during parsing) */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Buffer indexing expression (used only during parsing) */ class BufferIndex : public Expression { public: /** Constructor * @param buffer The buffer * @param i Indexing expression */ BufferIndex (class Expression& buffer, class Expression& i); private: /** Copy constructor */ BufferIndex (const class BufferIndex& old); /** Assignment operator */ class BufferIndex& operator= (const class BufferIndex& old); protected: /** Destructor */ ~BufferIndex (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eBufferIndex; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Get the buffer expression */ class Expression& getBuffer () { return *myBuffer->copy (); } /** Get the indexing expression */ class Expression& getIndex () { return *myIndex->copy (); } /** Equality comparison operator */ bool operator== (const class BufferIndex& other) const { return *myBuffer == *other.myBuffer && *myIndex == *other.myIndex; } /** Ordering comparison operator */ bool operator< (const class BufferIndex& other) const { if (*myIndex < *other.myIndex) return true; if (*other.myIndex < *myIndex) return false; return *myBuffer < *other.myBuffer; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The buffer expression */ class Expression* myBuffer; /** The indexing expression */ class Expression* myIndex; }; #endif // BUFFERINDEX_H_ maria-1.3.5/Expression/BufferRemove.C0000644000175000017500000003033707722340367017631 0ustar msmakelamsmakela// Buffer remove operator class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BufferRemove.h" #include "BufferType.h" #include "BufferValue.h" #include "Net.h" #include "CardType.h" #include "LeafValue.h" #include "Printer.h" /** @file BufferRemove.C * Operation for removing queue or stack items */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ BufferRemove::BufferRemove (class Expression& buffer, class Expression* amount, class Expression* i) : myBuffer (&buffer), myAmount (amount), myIndex (i) { assert (myBuffer && myBuffer->getType ()->getKind () == Type::tBuffer); assert (!myAmount || myAmount->getType ()->getKind () == Type::tCard); assert (!myIndex || myIndex->getType ()->getKind () == Type::tCard); assert (myBuffer->isBasic ()); assert (!myAmount || myAmount->isBasic ()); assert (!myIndex || myIndex->isBasic ()); setType (*myBuffer->getType ()); } BufferRemove::~BufferRemove () { myBuffer->destroy (); myAmount->destroy (); myIndex->destroy (); } /** Evaluate a cardinality-valued expression * @param expr the expression * @param valuation the variable substitutions * @param value (output) the result * @return true if the evaluation succeeded */ inline static bool eval (const class Expression& expr, const class Valuation& valuation, card_t& value) { if (class Value* v = expr.eval (valuation)) { assert (v->getType ().getKind () == Type::tCard); value = card_t (static_cast(*v)); delete v; return true; } else return false; } class Value* BufferRemove::do_eval (const class Valuation& valuation) const { class Value* buffer = myBuffer->eval (valuation); if (!buffer) return NULL; assert (buffer->getType ().getKind () == Type::tBuffer); class BufferValue* bv = static_cast(buffer); card_t idx = 0, amount = 1, capacity = bv->getCapacity (); if (myAmount && !::eval (*myAmount, valuation, amount)) { delete bv; return NULL; } if (myIndex && !::eval (*myIndex, valuation, idx)) { delete bv; return NULL; } if (amount + idx > capacity) { valuation.flag (errBuf, *this); delete bv; return NULL; } if (!amount) return bv; card_t i; for (i = amount; i--; ) delete (*bv)[idx + i]; for (i = idx + amount; i < capacity; i++) (*bv)[i - amount] = (*bv)[i]; for (i = capacity - amount; i < capacity; i++) (*bv)[i] = NULL; return bv; } class Expression* BufferRemove::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* buffer = myBuffer->ground (valuation, transition, declare); if (!buffer) return NULL; class Expression* amount = myAmount ? myAmount->ground (valuation, transition, declare) : NULL; if (myAmount && !amount) { buffer->destroy (); return NULL; } class Expression* i = myIndex ? myIndex->ground (valuation, transition, declare) : NULL; if (myIndex && !i) { buffer->destroy (); amount->destroy (); return NULL; } assert (valuation.isOK ()); if (buffer == myBuffer && amount == myAmount && i == myIndex) { buffer->destroy (); amount->destroy (); i->destroy (); return copy (); } else return static_cast (new class BufferRemove (*buffer, amount, i))->ground (valuation); } class Expression* BufferRemove::substitute (class Substitution& substitution) { class Expression* buffer = myBuffer->substitute (substitution); class Expression* amount = myAmount ? myAmount->substitute (substitution) : NULL; class Expression* i = myIndex ? myIndex->substitute (substitution) : NULL; if (buffer == myBuffer && amount == myAmount && i == myIndex) { buffer->destroy (); amount->destroy (); i->destroy (); return copy (); } return (new class BufferRemove (*buffer, amount, i))->cse (); } bool BufferRemove::depends (const class VariableSet& vars, bool complement) const { return myBuffer->depends (vars, complement) || (myAmount && myAmount->depends (vars, complement)) || (myIndex && myIndex->depends (vars, complement)); } bool BufferRemove::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myBuffer->forExpressions (operation, data) && (!myAmount || myAmount->forExpressions (operation, data)) && (!myIndex || myIndex->forExpressions (operation, data)); } #ifdef EXPR_COMPILE # include "CExpression.h" # include "Constant.h" void BufferRemove::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { char* buf; if (cexpr.getVariable (*myBuffer, buf)) myBuffer->compile (cexpr, indent, buf, vars); char* amvalue = 0; if (myAmount && myAmount->getKind () != Expression::eConstant && cexpr.getVariable (*myAmount, amvalue)) myAmount->compile (cexpr, indent, amvalue, vars); char* ixvalue = 0; if (myIndex && myIndex->getKind () != Expression::eConstant && cexpr.getVariable (*myIndex, ixvalue)) myIndex->compile (cexpr, indent, ixvalue, vars); class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append ("if ("); out.append (buf); out.append (".s<"); if (amvalue) out.append (amvalue), out.append ("+"); else if (myAmount) { assert (myAmount->getKind () == Expression::eConstant); static_cast(myAmount)->getValue ().compile (out); out.append ("+"); } else out.append ("="); if (ixvalue) out.append (ixvalue); else if (myIndex) { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } else out.append ("0"); out.append (")\n"); cexpr.compileError (indent + 2, errBuf); out.indent (indent); out.append (lvalue); out.append (".s="); out.append (buf); out.append (".s-"); if (amvalue) out.append (amvalue); else if (myAmount) static_cast(myAmount)->getValue ().compile (out); else out.append ("1"); out.append (";\n"); if (myIndex) { out.indent (indent); out.append ("memcpy ("); out.append (lvalue); out.append (".a"); out.append (", "); out.append (buf); out.append (".a"); out.append (", "); if (ixvalue) out.append (ixvalue); else static_cast(myIndex)->getValue ().compile (out); out.append (" * sizeof *"); out.append (buf); out.append (".a);\n"); } out.indent (indent); out.append ("memcpy ("); out.append (lvalue); out.append (".a"); if (myIndex) { out.append ("+"); if (ixvalue) out.append (ixvalue); else static_cast(myIndex)->getValue ().compile (out); } out.append (", "); out.append (buf); out.append (".a"); if (myIndex) { out.append ("+"); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } } if (amvalue) out.append ("+"), out.append (amvalue); else if (myAmount) { out.append ("+"); static_cast(myAmount)->getValue ().compile (out); } else out.append ("+1"); out.append (",\n"); out.indent (indent + 8); out.append ("("); out.append (lvalue); out.append (".s"); if (myIndex) { out.append ("-"); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } } out.append (") * sizeof *"); out.append (buf); out.append (".a);\n"); delete[] buf; delete[] amvalue; delete[] ixvalue; compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eVectorIndex: case Expression::eNot: case Expression::eTypecast: case Expression::eUnop: case Expression::eBufferUnop: case Expression::eCardinality: return false; case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: case Expression::eBooleanBinop: case Expression::eUnionType: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eStruct: case Expression::eUnion: case Expression::eVector: case Expression::eBinop: case Expression::eRelop: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: assert (false); case Expression::eIfThenElse: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: break; } return true; } /** Determine whether an amount expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses2 (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eVectorIndex: case Expression::eTypecast: return false; case Expression::eUndefined: case Expression::eNot: case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: case Expression::eBooleanBinop: case Expression::eUnionType: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eStruct: case Expression::eUnion: case Expression::eVector: case Expression::eRelop: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: assert (false); case Expression::eIfThenElse: case Expression::eUnop: case Expression::eBufferUnop: case Expression::eCardinality: case Expression::eBinop: break; } return true; } void BufferRemove::display (const class Printer& printer) const { if (!myAmount) printer.delimiter ('-'); if (myIndex) { printer.delimiter ('(')++; myBuffer->display (printer); printer.delimiter ('[')++; myIndex->display (printer); --printer.delimiter (']'); --printer.delimiter (')'); } else if (::needParentheses (myBuffer->getKind ())) { printer.delimiter ('(')++; myBuffer->display (printer); --printer.delimiter (')'); } else myBuffer->display (printer); if (myAmount) { printer.delimiter ('-'); if (::needParentheses2 (myAmount->getKind ())) { printer.delimiter ('(')++; myAmount->display (printer); --printer.delimiter (')'); } else myAmount->display (printer); } } maria-1.3.5/Expression/BufferRemove.h0000644000175000017500000001235307722340367017674 0ustar msmakelamsmakela// Buffer remove operator class -*- c++ -*- #ifndef BUFFERREMOVE_H_ # define BUFFERREMOVE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file BufferRemove.h * Operation for removing queue or stack items */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Buffer remove operator expression */ class BufferRemove : public Expression { public: /** Constructor * @param buffer Buffer whose items are being removed * @param amount Number of items to remove (NULL=1) * @param i Indexing expression (optional) */ BufferRemove (class Expression& buffer, class Expression* amount, class Expression* i); private: /** Copy constructor */ BufferRemove (const class BufferRemove& old); /** Assignment operator */ class BufferRemove& operator= (const class BufferRemove& old); protected: /** Destructor */ ~BufferRemove (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eBufferRemove; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class BufferRemove& other) const { return (myAmount || !other.myAmount) && (other.myAmount || !myAmount) && (myIndex || !other.myIndex) && (other.myIndex || !myIndex) && *myBuffer == *other.myBuffer && (!myAmount || *myAmount == *other.myAmount) && (!myIndex || *myIndex == *other.myIndex); } /** Ordering comparison operator */ bool operator< (const class BufferRemove& other) const { if (!myAmount && other.myAmount) return true; if (!other.myAmount && myAmount) return false; if (!myIndex && other.myIndex) return true; if (!other.myIndex && myIndex) return false; if (myAmount) { if (*myAmount < *other.myAmount) return true; if (*other.myAmount < *myAmount) return false; } if (myIndex) { if (*myIndex < *other.myIndex) return true; if (*other.myIndex < *myIndex) return false; } return *myBuffer < *other.myBuffer; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The buffer expression */ class Expression* myBuffer; /** The optional amount expression */ class Expression* myAmount; /** The optional index expression */ class Expression* myIndex; }; #endif // BUFFERREMOVE_H_ maria-1.3.5/Expression/BufferUnop.C0000644000175000017500000002076307722340367017317 0ustar msmakelamsmakela// Buffer unary operator class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BufferUnop.h" #include "BufferType.h" #include "BufferValue.h" #include "Net.h" #include "CardType.h" #include "LeafValue.h" #include "Printer.h" /** @file BufferUnop.C * Unary operators on queues and stacks */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ BufferUnop::BufferUnop (enum BufferUnop::Op op, class Expression& buffer, class Expression* i) : myOp (op), myBuffer (&buffer), myIndex (i) { assert (myBuffer && myBuffer->getType ()->getKind () == Type::tBuffer); assert (!myIndex || myIndex->getType ()->getKind () == Type::tCard); assert (myBuffer->isBasic ()); assert (!myIndex || myIndex->isBasic ()); switch (myOp) { case bPeek: setType (static_cast (myBuffer->getType ())->getItemType ()); break; case bFree: case bUsed: assert (!myIndex); setType (Net::getCardType ()); break; default: assert (false); } } BufferUnop::~BufferUnop () { myBuffer->destroy (); myIndex->destroy (); } class Value* BufferUnop::do_eval (const class Valuation& valuation) const { class Value* buffer = myBuffer->eval (valuation); if (!buffer) return NULL; assert (buffer->getType ().getKind () == Type::tBuffer); class BufferValue* bv = static_cast(buffer); card_t idx = 0, capacity = bv->getCapacity (); if (myIndex) { if (class Value* iv = myIndex->eval (valuation)) { assert (iv->getType ().getKind () == Type::tCard); card_t i = card_t (static_cast(*iv)); delete iv; if (i >= capacity) { valuation.flag (errBuf, *this); delete bv; return NULL; } idx = i; } else { delete bv; return NULL; } } switch (myOp) { case bPeek: if (!capacity) { valuation.flag (errBuf, *this); delete bv; return NULL; } else { class Value* item = (*bv)[idx]->copy (); delete bv; return item; } case bFree: { class Value* result = constrain (valuation, new class LeafValue (*getType (), bv->getSize () - capacity)); delete bv; return result; } case bUsed: delete bv; return constrain (valuation, new class LeafValue (*getType (), capacity)); } assert (false); return NULL; } class Expression* BufferUnop::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* buffer = myBuffer->ground (valuation, transition, declare); if (!buffer) return NULL; class Expression* i = myIndex ? myIndex->ground (valuation, transition, declare) : 0; if (myIndex && !i) { buffer->destroy (); return NULL; } assert (valuation.isOK ()); if (buffer == myBuffer && i == myIndex) { buffer->destroy (); i->destroy (); return copy (); } else return static_cast (new class BufferUnop (myOp, *buffer, i))->ground (valuation); } class Expression* BufferUnop::substitute (class Substitution& substitution) { class Expression* buffer = myBuffer->substitute (substitution); class Expression* i = myIndex ? myIndex->substitute (substitution) : 0; if (buffer == myBuffer && i == myIndex) { buffer->destroy (); i->destroy (); return copy (); } return (new class BufferUnop (myOp, *buffer, i))->cse (); } bool BufferUnop::depends (const class VariableSet& vars, bool complement) const { return myBuffer->depends (vars, complement) || (myIndex && myIndex->depends (vars, complement)); } bool BufferUnop::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myBuffer->forExpressions (operation, data) && (!myIndex || myIndex->forExpressions (operation, data)); } #ifdef EXPR_COMPILE # include "CExpression.h" # include "Constant.h" void BufferUnop::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { char* buf; if (cexpr.getVariable (*myBuffer, buf)) myBuffer->compile (cexpr, indent, buf, vars); char* ixvalue = 0; if (myIndex && myIndex->getKind () != Expression::eConstant && cexpr.getVariable (*myIndex, ixvalue)) myIndex->compile (cexpr, indent, ixvalue, vars); class StringBuffer& out = cexpr.getOut (); switch (myOp) { case bPeek: out.indent (indent); out.append ("if ("); if (ixvalue) out.append (ixvalue); else if (myIndex) { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } else out.append ("0"); out.append (">="); out.append (buf); out.append (".s)\n"); cexpr.compileError (indent + 2, errBuf); out.indent (indent); out.append (lvalue); out.append ("="); out.append (buf); out.append (".a["); if (ixvalue) out.append (ixvalue); else if (myIndex) { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } else out.append ("0"); out.append ("];\n"); break; case bFree: case bUsed: out.indent (indent); out.append (lvalue); out.append ("="); if (myOp == bFree) { out.append (static_cast(myBuffer->getType ()) ->getSize ()); out.append ("-"); } out.append (buf); out.append (".s;\n"); break; } delete[] buf; delete[] ixvalue; if (myOp != bPeek) compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eVectorIndex: case Expression::eNot: case Expression::eTypecast: case Expression::eUnop: case Expression::eBufferUnop: case Expression::eCardinality: return false; case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: case Expression::eBooleanBinop: case Expression::eUnionType: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eStruct: case Expression::eUnion: case Expression::eVector: case Expression::eBinop: case Expression::eRelop: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: assert (false); case Expression::eIfThenElse: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: break; } return true; } void BufferUnop::display (const class Printer& printer) const { char op = '?'; switch (myOp) { case bPeek: op = '*'; break; case bFree: op = '%'; break; case bUsed: op = '/'; break; } printer.delimiter (op); if (myIndex) { printer.delimiter ('(')++; myBuffer->display (printer); printer.delimiter ('[')++; myIndex->display (printer); --printer.delimiter (']'); --printer.delimiter (')'); } else if (::needParentheses (myBuffer->getKind ())) { printer.delimiter ('(')++; myBuffer->display (printer); --printer.delimiter (')'); } else myBuffer->display (printer); } maria-1.3.5/Expression/BufferUnop.h0000644000175000017500000001165607722340367017365 0ustar msmakelamsmakela// Buffer unary operator class -*- c++ -*- #ifndef BUFFERUNOP_H_ # define BUFFERUNOP_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file BufferUnop.h * Unary operators on queues and stacks */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Buffer unary operator expression */ class BufferUnop : public Expression { public: /** Unary operators */ enum Op { bPeek, bFree, bUsed }; /** Constructor * @param op Operator * @param buffer Buffer the operator is applied to * @param i Indexing expression (optional) */ BufferUnop (enum Op op, class Expression& buffer, class Expression* i); private: /** Copy constructor */ BufferUnop (const class BufferUnop& old); /** Assignment operator */ class BufferUnop& operator= (const class BufferUnop& old); protected: /** Destructor */ ~BufferUnop (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eBufferUnop; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class BufferUnop& other) const { return myOp == other.myOp && (myIndex || !other.myIndex) && (other.myIndex || !myIndex) && *myBuffer == *other.myBuffer && (!myIndex || *myIndex == *other.myIndex); } /** Ordering comparison operator */ bool operator< (const class BufferUnop& other) const { if (myOp < other.myOp) return true; if (other.myOp < myOp) return false; if (!myIndex && other.myIndex) return true; if (!other.myIndex && myIndex) return false; if (myIndex) { if (*myIndex < *other.myIndex) return true; if (*other.myIndex < *myIndex) return false; } return *myBuffer < *other.myBuffer; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The operator */ enum Op myOp; /** The buffer expression */ class Expression* myBuffer; /** The optional index expression */ class Expression* myIndex; }; #endif // BUFFERUNOP_H_ maria-1.3.5/Expression/BufferWrite.C0000644000175000017500000003176207722340367017471 0ustar msmakelamsmakela// Buffer write expression -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BufferWrite.h" #include "BufferType.h" #include "BufferValue.h" #include "LeafValue.h" #include "Printer.h" /** @file BufferWrite.C * Write operation to queues and stacks */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ BufferWrite::BufferWrite (class Expression& buffer, class Expression& item, class Expression* i) : myBuffer (&buffer), myItem (&item), myIndex (i) { assert (myBuffer && myItem); assert (myBuffer->getType ()->getKind () == Type::tBuffer); assert (myItem->isAssignable (static_cast (myBuffer->getType ())->getItemType ())); assert (!myIndex || myIndex->getType ()->getKind () == Type::tCard); assert (myBuffer->isBasic () && myItem->isBasic ()); assert (!myIndex || myIndex->isBasic ()); setType (*myBuffer->getType ()); } BufferWrite::~BufferWrite () { myBuffer->destroy (); myItem->destroy (); myIndex->destroy (); } class Value* BufferWrite::do_eval (const class Valuation& valuation) const { class Value* buffer = myBuffer->eval (valuation); if (!buffer) return NULL; class Value* item = myItem->eval (valuation); if (!item) { delete buffer; return NULL; } assert (buffer->getType ().getKind () == Type::tBuffer); assert (item->getType ().isAssignable (static_cast (buffer->getType ()).getItemType ())); class BufferValue* bv = static_cast(buffer); card_t idx = 0, capacity = bv->getCapacity (); if (myIndex) { if (class Value* iv = myIndex->eval (valuation)) { assert (iv->getType ().getKind () == Type::tCard); card_t i = card_t (static_cast(*iv)); delete iv; if (i > capacity) { valuation.flag (errBuf, *this); delete buffer; delete item; return NULL; } idx = i; } else { delete buffer; delete item; return NULL; } } if (capacity == bv->getSize ()) { valuation.flag (errBuf, *this); delete buffer; delete item; return NULL; } card_t i; if (static_cast(getType ())->isStack ()) for (i = capacity; i > idx; i--) (*bv)[i] = (*bv)[i - 1]; else for (i = capacity; i > capacity - idx; i--) (*bv)[i] = (*bv)[i - 1]; (*bv)[i] = item; return bv; } class Expression* BufferWrite::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* buffer = myBuffer->ground (valuation, transition, declare); if (!buffer) return NULL; class Expression* item = myItem->ground (valuation, transition, declare); if (!item) { buffer->destroy (); return NULL; } class Expression* i = myIndex ? myIndex->ground (valuation, transition, declare) : NULL; if (myIndex && !i) { buffer->destroy (); item->destroy (); return NULL; } assert (valuation.isOK ()); if (buffer == myBuffer && item == myItem && i == myIndex) { buffer->destroy (); item->destroy (); i->destroy (); return copy (); } else return static_cast (new class BufferWrite (*buffer, *item, i))->ground (valuation); } class Expression* BufferWrite::substitute (class Substitution& substitution) { class Expression* buffer = myBuffer->substitute (substitution); class Expression* item = myItem->substitute (substitution); class Expression* i = myIndex ? myIndex->substitute (substitution) : NULL; if (buffer == myBuffer && item == myItem && i == myIndex) { buffer->destroy (); item->destroy (); i->destroy (); return copy (); } return (new class BufferWrite (*buffer, *item, i))->cse (); } bool BufferWrite::depends (const class VariableSet& vars, bool complement) const { return myBuffer->depends (vars, complement) || myItem->depends (vars, complement) || (myIndex && myIndex->depends (vars, complement)); } bool BufferWrite::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myBuffer->forExpressions (operation, data) && myItem->forExpressions (operation, data) && (!myIndex || myIndex->forExpressions (operation, data)); } #ifdef EXPR_COMPILE # include "CExpression.h" # include "Constant.h" void BufferWrite::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { char* buf; if (cexpr.getVariable (*myBuffer, buf)) myBuffer->compile (cexpr, indent, buf, vars); char* ixvalue = 0; if (myIndex && myIndex->getKind () != Expression::eConstant && cexpr.getVariable (*myIndex, ixvalue)) myIndex->compile (cexpr, indent, ixvalue, vars); char* itvalue = 0; if (cexpr.getVariable (*myItem, itvalue)) myItem->compile (cexpr, indent, itvalue, vars); class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append ("if ("); out.append (buf); out.append (".s>="); out.append (static_cast(myBuffer->getType ()) ->getSize ()); if (myIndex) { out.append (" || "); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } out.append (">"); out.append (buf); out.append (".s"); } out.append (")\n"); cexpr.compileError (indent + 2, errBuf); out.indent (indent); out.append (lvalue); out.append (".s="); out.append (buf); out.append (".s+1;\n"); if (static_cast(getType ())->isStack ()) { if (myIndex) { out.indent (indent); out.append ("memcpy ("); out.append (lvalue); out.append (".a, "); out.append (buf); out.append (".a, "); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } out.append (" * sizeof *"); out.append (buf); out.append (".a);\n"); } out.indent (indent); out.append ("memcpy ("); out.append (lvalue); out.append (".a"); if (myIndex) { out.append ("+"); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } } out.append ("+1, "); out.append (buf); out.append (".a"); if (myIndex) { out.append ("+"); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } } out.append (", ("); out.append (buf); out.append (".s"); if (myIndex) { out.append ("-"); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } } out.append (") * sizeof *"); out.append (buf); out.append (".a);\n"); out.indent (indent); out.append (lvalue); out.append (".a["); if (ixvalue) out.append (ixvalue); else if (myIndex) { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } else out.append ("0"); out.append ("]="); out.append (itvalue); out.append (";\n"); } else if (myIndex) { out.indent (indent); out.append ("memcpy ("); out.append (lvalue); out.append (".a, "); out.append (buf); out.append (".a, ("); out.append (buf); out.append (".s-"); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } out.append (") * sizeof *"); out.append (buf); out.append (".a);\n"); out.indent (indent); out.append ("memcpy ("); out.append (lvalue); out.append (".a+"); out.append (buf); out.append (".s"); out.append ("-"); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex) ->getValue ().compile (out); } out.append ("+1, "); out.append (buf); out.append (".a+"); out.append (buf); out.append (".s"); out.append ("-"); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } out.append (", "); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } out.append (" * sizeof *"); out.append (buf); out.append (".a);\n"); out.indent (indent); out.append (lvalue); out.append (".a["); out.append (buf); out.append (".s-"); if (ixvalue) out.append (ixvalue); else { assert (myIndex->getKind () == Expression::eConstant); static_cast(myIndex)->getValue ().compile (out); } out.append ("]="); out.append (itvalue); out.append (";\n"); } else { out.indent (indent); out.append ("memcpy ("); out.append (lvalue); out.append (".a, "); out.append (buf); out.append (".a, "); out.append (buf); out.append (".s * sizeof *"); out.append (buf); out.append (".a);\n"); out.indent (indent); out.append (lvalue); out.append (".a["); out.append (buf); out.append (".s]="); out.append (itvalue); out.append (";\n"); } delete[] ixvalue; delete[] itvalue; delete[] buf; compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eUnionType: case Expression::eVectorIndex: case Expression::eUnop: case Expression::eBufferUnop: case Expression::eTypecast: case Expression::eCardinality: case Expression::eNot: case Expression::eRelop: case Expression::eStruct: case Expression::eVector: case Expression::eBuffer: case Expression::eBufferIndex: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: return false; case Expression::eMarking: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: assert (false); case Expression::eTransitionQualifier: case Expression::eBooleanBinop: case Expression::eBinop: case Expression::eIfThenElse: case Expression::eUnion: case Expression::eBufferWrite: case Expression::eBufferRemove: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: break; } return true; } void BufferWrite::display (const class Printer& printer) const { const char* cast = myItem->getType ()->getName (); switch (myItem->getType ()->getKind ()) { case Type::tBool: case Type::tChar: case Type::tInt: case Type::tCard: cast = 0; default: break; } if (myIndex) { printer.delimiter ('(')++; myBuffer->display (printer); --printer.delimiter (')'); printer.delimiter ('[')++; myIndex->display (printer); --printer.delimiter (']'); } else myBuffer->display (printer); printer.delimiter ('+'); if (cast) { printer.printRaw ("is"); printer.delimiter (' '); printer.print (cast); printer.delimiter (' '); } if (::needParentheses (myItem->getKind ())) { printer.delimiter ('(')++; myItem->display (printer); --printer.delimiter (')'); } else myItem->display (printer); } maria-1.3.5/Expression/BufferWrite.h0000644000175000017500000001165707722340367017537 0ustar msmakelamsmakela// Buffer write expression -*- c++ -*- #ifndef BUFFERWRITE_H_ # define BUFFERWRITE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file BufferWrite.h * Write operation to queues and stacks */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Buffer write expression */ class BufferWrite : public Expression { public: /** Constructor * @param buffer The buffer * @param item The item to be read or written * @param i Indexing expression (optional) */ BufferWrite (class Expression& buffer, class Expression& item, class Expression* i); private: /** Copy constructor */ BufferWrite (const class BufferWrite& old); /** Assignment operator */ class BufferWrite& operator= (const class BufferWrite& old); protected: /** Destructor */ ~BufferWrite (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eBufferWrite; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class BufferWrite& other) const { return (myIndex || !other.myIndex) && (other.myIndex || !myIndex) && *myBuffer == *other.myBuffer && *myItem == *other.myItem && (!myIndex || *myIndex == *other.myIndex); } /** Ordering comparison operator */ bool operator< (const class BufferWrite& other) const { if (!myIndex && other.myIndex) return true; if (!other.myIndex && myIndex) return false; if (myIndex) { if (*myIndex < *other.myIndex) return true; if (*other.myIndex < *myIndex) return false; } if (*myBuffer < *other.myBuffer) return true; if (*other.myBuffer < *myBuffer) return false; return *myItem < *other.myItem; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The buffer expression */ class Expression* myBuffer; /** The item expression */ class Expression* myItem; /** The optional index expression */ class Expression* myIndex; }; #endif // BUFFERWRITE_H_ maria-1.3.5/Expression/CardinalityExpression.C0000644000175000017500000001467007722340367021567 0ustar msmakelamsmakela// Marking cardinality/multiplicity expression class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "CardinalityExpression.h" #include "PlaceMarking.h" #include "Net.h" #include "CardType.h" #include "LeafValue.h" #include "Valuation.h" #include "Printer.h" /** @file CardinalityExpression.C * Aggregate operations on multi-sets */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ CardinalityExpression::CardinalityExpression (enum Op op, class Expression& expr) : Expression (), myOp (op), myExpr (&expr) { assert (myExpr && !myExpr->isTemporal ()); setType (Net::getCardType ()); } CardinalityExpression::~CardinalityExpression () { myExpr->destroy (); } class Value* CardinalityExpression::do_eval (const class Valuation& valuation) const { if (class PlaceMarking* p = myExpr->meval (valuation)) { card_t count = myOp == cMin ? CARD_T_MAX : 0; for (PlaceMarking::const_iterator i = p->begin (); i != p->end (); i++) { card_t add = PlaceMarking::getCount (i); switch (myOp) { case cCard: if (CARD_T_MAX - count < add) { valuation.flag (errOver, *this); delete p; return NULL; } else count += add; break; case cMin: if (count > add) count = add; break; case cMax: if (count < add) count = add; break; } } delete p; return constrain (valuation, new class LeafValue (*getType (), count)); } return NULL; } class Expression* CardinalityExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* e = myExpr->ground (valuation, transition, declare); if (!e) return NULL; assert (valuation.isOK ()); if (e == myExpr) { e->destroy (); return copy (); } else return static_cast (new class CardinalityExpression (myOp, *e))->ground (valuation); } class Expression* CardinalityExpression::substitute (class Substitution& substitution) { class Expression* e = myExpr->substitute (substitution); if (!e) return NULL; if (e == myExpr) { e->destroy (); return copy (); } else return (new class CardinalityExpression (myOp, *e))->cse (); } bool CardinalityExpression::depends (const class VariableSet& vars, bool complement) const { return myExpr->depends (vars, complement); } bool CardinalityExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myExpr->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" # include "PlaceContents.h" # include "Place.h" void CardinalityExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { class StringBuffer& out = cexpr.getOut (); if (myExpr->getKind () == Expression::ePlaceContents) { const class PlaceContents& p = *static_cast(myExpr); if (!p.getPlace ().getCapacityBits ()) { out.indent (indent); out.append (lvalue); out.append ("="); out.append (p.getPlace ().getMaxNumTokens ()); out.append (";\n"); return; } if (p.getPlace ().getMaxNumTokens () == 1) { out.indent (indent); out.append (lvalue); out.append ("="); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (p.getPlace ().getIndex ()); out.append (myOp == cMin ? "?1:UINT_MAX" : "?1:0;\n"); return; } } char* expr; if (cexpr.getVariable (*myExpr, expr)) myExpr->compileMset (cexpr, indent, 0, expr, vars); char* iter = cexpr.getLabel (); out.indent (indent); out.append ("{\n"); out.indent (indent + 2); out.append ("register const "); myExpr->getType ()->appendMSetName (out); out.append ("* "); out.append (iter); out.append (" = "); out.append (expr); out.append (";\n"); out.indent (indent + 2); out.append ("FIRST ("); out.append (iter); out.append (");\n"); out.indent (indent + 2); out.append ("for ("); out.append (lvalue); out.append (myOp == cMin ? "=UINT_MAX; " : "=0; "); out.append (iter); out.append ("; ) {\n"); switch (myOp) { case cCard: out.indent (indent + 4); out.append ("if ("), out.append (lvalue), out.append (">UINT_MAX-"); out.append (iter), out.append ("->count)\n"); cexpr.compileError (indent + 6, errOver); out.indent (indent + 4); out.append (lvalue); out.append ("+="); out.append (iter); out.append ("->count;\n"); break; case cMin: case cMax: out.indent (indent + 4); out.append ("if ("), out.append (lvalue); out.append (myOp == cMin ? ">" : "<"); out.append (iter), out.append ("->count) "); out.append (lvalue), out.append ("="); out.append (iter), out.append ("->count;\n"); break; } out.indent (indent + 4); out.append ("NEXT ("); out.append (iter); out.append (");\n"); out.indent (indent + 2); out.append ("}\n"); out.indent (indent); out.append ("}\n"); delete[] iter; delete[] expr; compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE void CardinalityExpression::display (const class Printer& printer) const { switch (myOp) { case cCard: printer.printRaw ("cardinality"); break; case cMin: printer.printRaw ("min"); break; case cMax: printer.printRaw ("max"); break; } printer.delimiter (' '); if (myExpr->getKind () == Expression::eMarking) { printer.delimiter ('(')++; myExpr->display (printer); --printer.delimiter (')'); } else myExpr->display (printer); } maria-1.3.5/Expression/CardinalityExpression.h0000644000175000017500000001116607722340367021631 0ustar msmakelamsmakela// Marking cardinality/multiplicity expression class -*- c++ -*- #ifndef CARDINALITYEXPRESSION_H_ # define CARDINALITYEXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include "Marking.h" /** @file CardinalityExpression.h * Aggregate operations on multi-sets */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Marking cardinality/multiplicity expression */ class CardinalityExpression : public Expression { public: /** Operators */ enum Op { cCard, cMin, cMax }; /** Constructor * @param op the operator * @param expr the multiset-valued expression */ CardinalityExpression (enum Op op, class Expression& expr); private: /** Copy constructor */ CardinalityExpression (const class CardinalityExpression& old); /** Assignment operator */ class CardinalityExpression& operator= (const class CardinalityExpression& old); protected: /** Destructor */ ~CardinalityExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eCardinality; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class CardinalityExpression& other) const { return myOp == other.myOp && *myExpr == *other.myExpr; } /** Ordering comparison operator */ bool operator< (const class CardinalityExpression& other) const { if (myOp < other.myOp) return true; if (other.myOp < myOp) return false; return *myExpr < *other.myExpr; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** the operator */ enum Op myOp; /** the multiset-valued expression */ class Expression* myExpr; }; #endif // CARDINALITYEXPRESSION_H_ maria-1.3.5/Expression/Constant.C0000644000175000017500000000610107722340367017023 0ustar msmakelamsmakela// constant class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Constant.h" #include "LeafValue.h" #include "Property.h" /** @file Constant.C * Constant literals in expressions */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Constant::Constant (class Value& value) : Expression (), myValue (&value) { Expression::setType (myValue->getType ()); } Constant::~Constant () { delete myValue; } bool Constant::operator== (const class Constant& other) const { if (getValue ().getKind () != other.getValue ().getKind ()) return false; return getValue () == other.getValue (); } bool Constant::operator< (const class Constant& other) const { if (getValue ().getKind () < other.getValue ().getKind ()) return true; if (other.getValue ().getKind () < getValue ().getKind ()) return false; return getValue () < other.getValue (); } class Value* Constant::do_eval (const class Valuation&) const { return myValue->copy (); } bool Constant::depends (const class VariableSet&, bool) const { return false; } bool Constant::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data); } class Ltl* Constant::toFormula (class Property& property) { assert (myValue->getKind () == Value::vLeaf && myValue->getType ().getKind () == Type::tBool); return property.addConstant (static_cast(*myValue)); } #ifdef EXPR_COMPILE # include "CExpression.h" void Constant::compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet&, const char* value) const { if (getType ()->getNumValues () != 1) { class StringBuffer& out = cexpr.getOut (); out.indent (indent), out.append ("if ("); myValue->compileEqual (out, indent + 4, value, false, true, true); out.append (")\n"); cexpr.compileError (indent + 2, errComp); } } void Constant::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet*) const { myValue->compileInit (lvalue, indent, cexpr.getOut ()); } #endif // EXPR_COMPILE void Constant::display (const class Printer& printer) const { myValue->display (printer); } maria-1.3.5/Expression/Constant.h0000644000175000017500000001076207722340367017100 0ustar msmakelamsmakela// constant class -*- c++ -*- #ifndef CONSTANT_H_ # define CONSTANT_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file Constant.h * Constant literals in expressions */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Constant */ class Constant : public Expression { public: /** Constructor * @param value Value of the constant */ Constant (class Value& value); private: /** Copy constructor */ Constant (const class Constant& old); /** Assignment operator */ class Constant& operator= (const class Constant& old); protected: /** Destructor */ ~Constant (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eConstant; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Determine the constant value */ const class Value& getValue () const { return *myValue; } /** Equality comparison operator */ bool operator== (const class Constant& other) const; /** Ordering comparison operator */ bool operator< (const class Constant& other) const; /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation&, class Transition*, bool) { return copy (); } /** Substitute some variables in the expression with expressions * @return substituted expression */ class Expression* substitute (class Substitution&) { return copy (); } /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Translate the expression to a list of temporal logic connectives * and Boolean propositions * @param property the property automaton * @return the translated object */ class Ltl* toFormula (class Property& property); # ifdef EXPR_COMPILE /** Generate compatibility check code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables that have been unified * @param value C expression referring to the desired value */ void compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const; /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** Value of the constant */ class Value* myValue; }; #endif // CONSTANT_H_ maria-1.3.5/Expression/EmptySet.C0000644000175000017500000000305207722340367017006 0ustar msmakelamsmakela// Empty set expression -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "EmptySet.h" #include "PlaceMarking.h" #include "Printer.h" /** @file EmptySet.C * Literal for empty multi-sets */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class PlaceMarking* EmptySet::meval (const class Valuation&) const { return new class PlaceMarking; } bool EmptySet::depends (const class VariableSet&, bool) const { return false; } bool EmptySet::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data); } void EmptySet::display (const class Printer& printer) const { printer.printRaw ("empty"); } maria-1.3.5/Expression/EmptySet.h0000644000175000017500000000746107722340367017063 0ustar msmakelamsmakela// Empty set expression -*- c++ -*- #ifndef EMPTYSET_H_ # define EMPTYSET_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file EmptySet.h * Literal for empty multi-sets */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Empty multi-set expression */ class EmptySet : public Expression { public: /** Constructor */ EmptySet () {} private: /** Copy constructor */ EmptySet (const class EmptySet& old); /** Assignment operator */ class EmptySet& operator= (const class EmptySet& old); protected: /** Destructor */ ~EmptySet () {} public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eEmptySet; } /** * Determine whether this is a basic expression containing * no temporal logic or set operations * @return true if this is a basic expression */ bool isBasic () const { return false; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** * Determine whether this is a multiset-valued expression * @return true if this is a multiset-valued expression */ bool isSet () const { return true; } /** Equality comparison operator */ bool operator== (const class EmptySet&) const { return true; } /** Ordering comparison operator */ bool operator< (const class EmptySet&) const { return false; } /** Evaluate the multiset expression * @param valuation variable substitutions and the global marking * @return the filtered marking */ class PlaceMarking* meval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation&, class Transition*, bool) { return copy (); } /** Substitute some variables in the expression with expressions * @return substituted expression */ class Expression* substitute (class Substitution&) { return copy (); } /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression */ void compile (class CExpression&, unsigned, const char*, const class VariableSet*) const { assert (false); } # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; }; #endif // EMPTYSET_H_ maria-1.3.5/Expression/Expression.C0000644000175000017500000003627707653665617017425 0ustar msmakelamsmakela// Maria expression class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Expression.h" #include "allExpressions.h" #include "Property.h" #include #include "ExpressionSet.h" /** Cache for common subexpression elimination */ static class ExpressionSet exprs; /** @file Expression.C * Abstract base class for expressions */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Expression::Expression () : myReferences (1), myType (0), myIsAtomic (false) { } Expression::~Expression () { assert (!myReferences); } class Expression* Expression::cse () { return this ? exprs.insert (this) : 0; } void Expression::setType (const class Type& type) { assert (!myType || type.isAssignable (*myType)); myType = &type; } bool Expression::operator== (const class Expression& other) const { if (this == &other) return true; if (getKind () != other.getKind () || getType () != other.getType ()) return false; switch (getKind ()) { case eVariable: return static_cast(*this) == static_cast(other); case eConstant: return static_cast(*this) == static_cast(other); case eUndefined: return static_cast(*this) == static_cast(other); case eStruct: return static_cast(*this) == static_cast(other); case eStructComponent: return static_cast(*this) == static_cast(other); case eStructAssign: return static_cast(*this) == static_cast(other); case eUnion: return static_cast(*this) == static_cast(other); case eUnionComponent: return static_cast(*this) == static_cast(other); case eUnionType: return static_cast(*this) == static_cast(other); case eVector: return static_cast(*this) == static_cast(other); case eVectorIndex: return static_cast(*this) == static_cast(other); case eVectorAssign: return static_cast(*this) == static_cast(other); case eVectorShift: return static_cast(*this) == static_cast(other); case eUnop: return static_cast(*this) == static_cast(other); case eBinop: return static_cast(*this) == static_cast(other); case eBooleanBinop: return static_cast(*this) == static_cast(other); case eNot: return static_cast(*this) == static_cast(other); case eRelop: return static_cast(*this) == static_cast(other); case eBuffer: return static_cast(*this) == static_cast(other); case eBufferUnop: return static_cast(*this) == static_cast(other); case eBufferRemove: return static_cast(*this) == static_cast(other); case eBufferWrite: return static_cast(*this) == static_cast(other); case eBufferIndex: return static_cast(*this) == static_cast(other); case eSet: return static_cast(*this) == static_cast(other); case eIfThenElse: return static_cast(*this) == static_cast(other); case eTemporalBinop: return static_cast(*this) == static_cast(other); case eTemporalUnop: return static_cast(*this) == static_cast(other); case eTypecast: return static_cast(*this) == static_cast(other); case eCardinality: return static_cast(*this) == static_cast(other); case eMarking: return static_cast(*this) == static_cast(other); case eTransitionQualifier: return static_cast(*this) == static_cast(other); case ePlaceContents: return static_cast(*this) == static_cast(other); case eSubmarking: return static_cast(*this) == static_cast(other); case eMapping: return static_cast(*this) == static_cast(other); case eEmptySet: return static_cast(*this) == static_cast(other); } assert (false); return false; } bool Expression::operator< (const class Expression& other) const { if (this == &other) return false; if (getKind () < other.getKind ()) return true; if (getKind () > other.getKind ()) return false; if (getType () < other.getType ()) return true; if (getType () > other.getType ()) return false; switch (getKind ()) { case eVariable: return static_cast(*this) < static_cast(other); case eConstant: return static_cast(*this) < static_cast(other); case eUndefined: return static_cast(*this) < static_cast(other); case eStruct: return static_cast(*this) < static_cast(other); case eStructComponent: return static_cast(*this) < static_cast(other); case eStructAssign: return static_cast(*this) < static_cast(other); case eUnion: return static_cast(*this) < static_cast(other); case eUnionComponent: return static_cast(*this) < static_cast(other); case eUnionType: return static_cast(*this) < static_cast(other); case eVector: return static_cast(*this) < static_cast(other); case eVectorIndex: return static_cast(*this) < static_cast(other); case eVectorAssign: return static_cast(*this) < static_cast(other); case eVectorShift: return static_cast(*this) < static_cast(other); case eUnop: return static_cast(*this) < static_cast(other); case eBinop: return static_cast(*this) < static_cast(other); case eBooleanBinop: return static_cast(*this) < static_cast(other); case eNot: return static_cast(*this) < static_cast(other); case eRelop: return static_cast(*this) < static_cast(other); case eBuffer: return static_cast(*this) < static_cast(other); case eBufferUnop: return static_cast(*this) < static_cast(other); case eBufferRemove: return static_cast(*this) < static_cast(other); case eBufferWrite: return static_cast(*this) < static_cast(other); case eBufferIndex: return static_cast(*this) < static_cast(other); case eSet: return static_cast(*this) < static_cast(other); case eIfThenElse: return static_cast(*this) < static_cast(other); case eTemporalBinop: return static_cast(*this) < static_cast(other); case eTemporalUnop: return static_cast(*this) < static_cast(other); case eTypecast: return static_cast(*this) < static_cast(other); case eCardinality: return static_cast(*this) < static_cast(other); case eMarking: return static_cast(*this) < static_cast(other); case eTransitionQualifier: return static_cast(*this) < static_cast(other); case ePlaceContents: return static_cast(*this) < static_cast(other); case eSubmarking: return static_cast(*this) < static_cast(other); case eMapping: return static_cast(*this) < static_cast(other); case eEmptySet: return static_cast(*this) < static_cast(other); } assert (false); return false; } class Value* Expression::do_eval (const class Valuation&) const { assert (false); return 0; } class Expression* Expression::ground (const class Valuation& valuation) { assert (valuation.isOK ()); if (!isBasic () || getKind () == eConstant); else if (class Value* v = eval (valuation)) { destroy (); return (new class Constant (*v))->cse (); } else if (!valuation.isOKorVar ()) { destroy (); return 0; } valuation.clearErrors (); return cse (); } class PlaceMarking* Expression::meval (const class Valuation&) const { assert (false); return 0; } bool Expression::isTypeCompatible (const class Value& value) const { return isAssignable (value.getType ()); } bool Expression::isCompatible (const class Value& value, const class Valuation& valuation) const { assert (isTypeCompatible (value)); if (class Value* v = eval (valuation)) { bool compatible = value == *v; delete v; return compatible; } assert (!valuation.isOK ()); if (valuation.getError () != errVar) return false; valuation.clearErrors (); return true; } void Expression::getLvalues (const class Value&, class Valuation&, const class VariableSet&) const { } void Expression::getLvalues (const class VariableSet&, class VariableSet*&) const { } class Ltl* Expression::toFormula (class Property& property) { assert (getType () && getType ()->getKind () == Type::tBool); return property.addExpression (*this); } class Expression* Expression::disqualify (const class Transition&) { return copy (); } #ifdef EXPR_COMPILE # include "CExpression.h" void Expression::compileLvalue (class CExpression&, unsigned, const class VariableSet&, const char*) const { } void Expression::compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const { if (myType->getNumValues () == 1 || depends (vars, true)) return; bool* checkpoint = 0; unsigned checkpointSize = cexpr.getCheckpoint (checkpoint); class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append ("do {\n"); char* result; if (cexpr.getVariable (*this, result)) compile (cexpr, indent + 2, result, &vars); out.indent (indent + 2); out.append ("if ("); if (!myType->compileEqual (out, indent + 6, result, value, false, true, true, false)) out.append ("1"); out.append (")\n"); cexpr.compileError (indent + 4, errComp); out.indent (indent); out.append ("} while (0);\n"); cexpr.setCheckpoint (indent, checkpoint, checkpointSize); delete[] checkpoint; delete[] result; } void Expression::compileScalarMset (class CExpression& cexpr, unsigned indent, const char* result, const class VariableSet* vars, bool check) const { class StringBuffer& out = cexpr.getOut (); char* tmp; if (cexpr.getVariable (*this, tmp)) compileMset (cexpr, indent, 0, tmp, vars); if (check) { out.indent (indent); out.append ("if ("); out.append (result); out.append (" && singleton ("); out.append (tmp); out.append ("))\n"); cexpr.compileError (indent + 2, errConst); } out.indent (indent); out.append (result); out.append (" = singleton ("); out.append (tmp); out.append (");\n"); delete[] tmp; } void Expression::compileMset (class CExpression&, unsigned, const char*, const char*, const class VariableSet*) const { assert (getKind () == eEmptySet); } #endif // EXPR_COMPILE maria-1.3.5/Expression/Expression.h0000644000175000017500000002675707722340367017461 0ustar msmakelamsmakela// Maria expression class -*- c++ -*- #ifndef EXPRESSION_H_ # define EXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Type.h" # include "Constraint.h" # include "Value.h" # include "Valuation.h" /** @file Expression.h * Abstract base class for expressions */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Abstract base class for expressions */ class Expression { public: /** Expression kinds (@see getKind) */ enum Kind { eVariable, eConstant, eUndefined, eStruct, eStructComponent, eStructAssign, eUnion, eUnionComponent, eUnionType, eVector, eVectorIndex, eVectorAssign, eVectorShift, eUnop, eBinop, eBooleanBinop, eNot, eRelop, eBuffer, eBufferUnop, eBufferRemove, eBufferWrite, eBufferIndex, eSet, eIfThenElse, eTemporalBinop, eTemporalUnop, eTypecast, eCardinality, eMarking, eTransitionQualifier, ePlaceContents, eSubmarking, eMapping, eEmptySet }; /** Constructor */ Expression (); private: /** Copy constructor */ Expression (const class Expression& old); /** Assignment operator */ class Expression& operator= (const class Expression& old); protected: /** Destructor */ virtual ~Expression (); public: /** Common subexpression elimination * @return pointer to this, or to a similar object */ class Expression* cse (); /** Get a shared copy of the expression */ class Expression* copy () { myReferences++; return this; } /** Destructs Expression, provided that there aren't any references to it */ void destroy () { if (this && !--myReferences) delete this; } /** Determine whether this is the last copy of an expression */ bool isLastCopy () const { return myReferences == 1; } /** Determine the type of the expression */ virtual enum Expression::Kind getKind () const = 0; /** Set the atomicity flag * @param atomic specifies whether this should be treated * as an atomic (non-temporal) expression */ void setAtomic (bool atomic) { myIsAtomic = atomic; } /** Read the atomicity flag */ bool isAtomic () const { return myIsAtomic; } /** Set the type of the expression * @param type Type of the expression */ virtual void setType (const class Type& type); /** Get the type associated with the expression */ const class Type* getType () const { return myType; } /** * Determine whether this is a basic expression containing * no temporal logic or set operations * @return true if this is a basic expression */ virtual bool isBasic () const = 0; /** * Determine whether this is a temporal logic expression * @return true if this is a temporal logic expression */ virtual bool isTemporal () const = 0; /** * Determine whether this is a multiset-valued expression * @return true if this is a multiset-valued expression */ virtual bool isSet () const { return false; } /** Equality comparison operator */ bool operator== (const class Expression& other) const; /** Ordering comparison operator */ bool operator< (const class Expression& other) const; /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* eval (const class Valuation& valuation) const { return do_eval (valuation); } /** Evaluate the multiset expression * @param valuation variable substitutions and the global marking * @return a marking */ virtual class PlaceMarking* meval (const class Valuation& valuation) const; private: /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ virtual class Value* do_eval (const class Valuation& valuation) const; protected: /** Check the constraints of a value * @param valuation Variable substitutions (for error reporting) * @param value the value to be checked * @return value, or NULL in case of error */ class Value* constrain (const class Valuation& valuation, class Value* value) const { assert (!!value); if (const class Constraint* const constraint = myType->getConstraint ()) { if (!constraint->isConstrained (*value)) { valuation.flag (errConst, *this); delete value; return NULL; } } return value; } public: /** Try to evaluate the expression using a valuation * @param valuation Variable substitutions * @return new pointer to this */ class Expression* ground (const class Valuation& valuation); /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ virtual class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare) = 0; /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ virtual class Expression* substitute (class Substitution& substitution) = 0; /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ virtual bool depends (const class VariableSet& vars, bool complement) const = 0; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ virtual bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const = 0; /** Remove transition qualifiers from the expression * @param transition the transition for which the expression is qualified * @return the expession without qualifiers, or NULL */ virtual class Expression* disqualify (const class Transition& transition); /** Determine whether the expression is assignable to the given data type * (perform static analysis) * @param type Data type to be checked * @return true if the expression is assignable to the type */ bool isAssignable (const class Type& type) const { return myType->isAssignable (type); } /** Determine whether the expression is type compatible with the specified * value (whether it ever could evaluate to the value) */ bool isTypeCompatible (const class Value& value) const; /** Determine whether the expression is compatible with the specified value, * neglecting subexpressions that cannot be evaluated * @param value value the expression will be compared to * @param valuation variable substitutions * @return true if the expression is compatible with the value */ virtual bool isCompatible (const class Value& value, const class Valuation& valuation) const; /** Unify variables from this expression * @param value the value the expression should evaluate to * @param valuation variable substitutions * @param vars the variables to unify */ virtual void getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const; /** Determine which variables could be unified from this expression * @param rvalues variables unified so far * @param lvalues (output) variables that could be unified */ virtual void getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const; /** Translate the expression to a list of temporal logic connectives * and Boolean propositions * @param property the property automaton * @return the translated object */ virtual class Ltl* toFormula (class Property& property); # ifdef EXPR_COMPILE /** Generate lvalue gathering code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables * @param lvalue C expression referring to the value */ virtual void compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const; /** Generate compatibility check code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables that have been assigned a value * @param value C expression referring to the desired value */ virtual void compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const; /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ virtual void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const = 0; /** Generate C code for evaluating a multi-set expression as a scalar * @param cexpr the compilation * @param indent indentation level * @param result scalar to assign the multi-set to (must be singleton) * @param vars the variables that have been assigned a value * @param check flag: check for result overflow */ virtual void compileScalarMset (class CExpression& cexpr, unsigned indent, const char* result, const class VariableSet* vars, bool check) const; /** Generate C code for evaluating the multi-set expression * @param cexpr the compilation * @param indent indentation level * @param resulttype type of result (optional typecast qualifier) * @param result multi-set to add items to * @param vars the variables that have been assigned a value */ virtual void compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const; /** Generate C code for checking the constraint of this expression * @param cexpr the compilation * @param indent indentation level * @param value C expression referring to the value */ void compileConstraint (class CExpression& cexpr, unsigned indent, const char* value) const { if (const class Constraint* c = myType->getConstraint ()) c->compileCheck (cexpr, indent, value); } # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ virtual void display (const class Printer& printer) const = 0; private: /** Number of references to the expression */ unsigned myReferences; /** Type of the expression */ const class Type* myType; /** Flag: is this an atomic expression */ bool myIsAtomic; }; #endif // EXPRESSION_H_ maria-1.3.5/Expression/ExpressionList.C0000644000175000017500000001220407722340367020226 0ustar msmakelamsmakela// Expression list class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "ExpressionList.h" #include "Expression.h" #include /** @file ExpressionList.C * List of expressions */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ ExpressionList::ExpressionList () : myReferences (1), mySize (0), myExprs (0) { } ExpressionList::~ExpressionList () { assert (!myReferences); for (card_t i = 0; i < size (); i++) myExprs[i]->destroy (); delete[] myExprs; } void ExpressionList::append (class Expression& expression) { assert (expression.getKind () == Expression::eUndefined || expression.getKind () == Expression::eEmptySet || expression.getKind () == Expression::eMarking || expression.getType ()); if (empty ()) { assert (!myExprs); myExprs = new class Expression*[1]; } else { class Expression** exprs = new class Expression*[mySize + 1]; memcpy (exprs, myExprs, mySize * sizeof *exprs); delete[] myExprs; myExprs = exprs; } myExprs[mySize++] = &expression; } void ExpressionList::prepend (class Expression& expression) { assert (expression.getKind () == Expression::eUndefined || expression.getKind () == Expression::eEmptySet || expression.getKind () == Expression::eMarking || expression.getType ()); if (empty ()) { assert (!myExprs); myExprs = new class Expression*[1]; } else { class Expression** exprs = new class Expression*[mySize + 1]; memcpy (exprs + 1, myExprs, mySize * sizeof *exprs); delete[] myExprs; myExprs = exprs; } *myExprs = &expression, mySize++; } const class Type* ExpressionList::getType () const { const class Type* type = NULL; for (card_t i = 0; i < mySize; i++) if ((type = myExprs[i]->getType ())) break; return type; } bool ExpressionList::isBasic () const { for (card_t i = 0; i < size (); i++) if (!myExprs[i]->isBasic ()) return false; return true; } bool ExpressionList::isTemporal () const { for (card_t i = 0; i < size (); i++) if (myExprs[i]->isTemporal ()) return true; return false; } bool ExpressionList::isSet () const { for (card_t i = 0; i < size (); i++) if (myExprs[i]->isSet ()) return true; return false; } bool ExpressionList::operator== (const class ExpressionList& other) const { if (this == &other) return true; if (size () != other.size ()) return false; for (card_t i = 0; i < size (); i++) if (!(*myExprs[i] == *other.myExprs[i])) return false; return true; } bool ExpressionList::operator< (const class ExpressionList& other) const { if (this == &other) return false; if (size () < other.size ()) return true; if (other.size () < size ()) return false; for (card_t i = 0; i < size (); i++) { if (*myExprs[i] < *other.myExprs[i]) return true; if (*other.myExprs[i] < *myExprs[i]) return false; } return false; } class ExpressionList* ExpressionList::ground (const class Valuation& valuation, class Transition* transition, bool declare) { bool same = true; class ExpressionList* l = new class ExpressionList; for (card_t i = 0; i < size (); i++) { class Expression* e = myExprs[i]->ground (valuation, transition, declare); if (!e) { l->destroy (); return NULL; } assert (valuation.isOK ()); if (e != myExprs[i]) same = false; l->append (*e); } if (same) { l->destroy (); return copy (); } return l; } class ExpressionList* ExpressionList::substitute (class Substitution& substitution) { bool same = true; class ExpressionList* l = new class ExpressionList; for (card_t i = 0; i < size (); i++) { class Expression* e = myExprs[i]->substitute (substitution); if (e != myExprs[i]) same = false; l->append (*e); } if (same) { l->destroy (); return copy (); } return l; } bool ExpressionList::depends (const class VariableSet& vars, bool complement) const { for (card_t i = 0; i < size (); i++) if (myExprs[i]->depends (vars, complement)) return true; return false; } bool ExpressionList::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { for (card_t i = 0; i < size (); i++) if (!myExprs[i]->forExpressions (operation, data)) return false; return true; } maria-1.3.5/Expression/ExpressionList.h0000644000175000017500000001166707722340367020307 0ustar msmakelamsmakela// Expression list class -*- c++ -*- #ifndef EXPRESSIONLIST_H_ # define EXPRESSIONLIST_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "typedefs.h" # include /** @file ExpressionList.h * List of expressions */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** List of expressions of same type */ class ExpressionList { public: /** Constructor */ ExpressionList (); private: /** Copy constructor */ ExpressionList (const class ExpressionList& old); /** Assignment operator */ class ExpressionList& operator= (const class ExpressionList& old); protected: /** Destructor */ ~ExpressionList (); public: /** Get a shared copy of the expression list */ class ExpressionList* copy () { myReferences++; return this; } /** Destructs ExpressionList, provided there aren't any references to it */ void destroy () { if (this && !--myReferences) delete this; } # ifndef NDEBUG /** Determine whether this is the last copy of an expression list */ bool isLastCopy () const { return myReferences == 1; } # endif // NDEBUG /** Append an expression to the list */ void append (class Expression& expression); /** Prepend an expression to the list */ void prepend (class Expression& expression); /** Get the type associated with the expression list */ const class Type* getType () const; /** * Determine whether this is a basic expression list containing * no temporal logic or set operations * @return true if this is a basic expression */ bool isBasic () const; /** * Determine whether this is a temporal logic expression * @return true if this is a temporal logic expression */ bool isTemporal () const; /** * Determine whether this is a multiset-valued expression * @return true if this is a multiset-valued expression */ bool isSet () const; /** Get the number of expressions in the list */ card_t size () const { return mySize; } /** Determine whether the expression list is empty */ bool empty () const { return !mySize; } /** Get an expression from the list * @param i index to the expression * @return the expression */ const class Expression& operator[] (card_t i) const { assert (i < size ()); return *myExprs[i]; } /** Get an expression from the list * @param i index to the expression * @return the expression */ class Expression& operator[] (card_t i) { assert (i < size ()); return *myExprs[i]; } /** Equality comparison operator */ bool operator== (const class ExpressionList& other) const; /** Ordering comparison operator */ bool operator< (const class ExpressionList& other) const; /** Partially evaluate the expression list using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression list, or NULL in case of error */ class ExpressionList* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression list with expressions * @param substitution Variable substitutions * @return substituted expression */ class ExpressionList* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; private: /** Number of references to the expression list */ unsigned myReferences; /** Number of list members */ card_t mySize; /** The list of expressions */ class Expression** myExprs; }; #endif // EXPRESSIONLIST_H_ maria-1.3.5/Expression/ExpressionMSet.C0000644000175000017500000000421407643235732020166 0ustar msmakelamsmakela// Set of symbolic markings -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "ExpressionMSet.h" #include "Marking.h" #include "Constant.h" #include "CardType.h" #include "LeafValue.h" #include "Net.h" /** @file ExpressionMSet.C * Multi-set of expressions (transient storage for quantification) */ /* Copyright © 2000-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class Marking* ExpressionMSet::toMarking (const class Place* place) { class Marking* m = NULL; for (iterator i = begin (); i != end (); i++) { assert (i->second > 0); class Expression* mult = i->second != 1 ? (new class Constant (*new class LeafValue (Net::getCardType (), i->second)))->cse () : NULL; class Expression* expr = i->first; class Marking* mm; if (expr->getKind () == Expression::eMarking) { mm = static_cast(expr); assert (mm->getPlace () == place); if (mm->getNext () || (mult && mm->getMultiplicity ())) (mm = new class Marking (place, mm))->setMultiplicity (mult); else if (mult) mm->setMultiplicity (mult); } else { mm = new class Marking (place); mm->setToken (expr); mm->setMultiplicity (mult); } if (m) m->append (*mm); else m = mm; } return static_cast(m->cse ()); } maria-1.3.5/Expression/ExpressionMSet.h0000644000175000017500000000711507643235732020236 0ustar msmakelamsmakela// Multi-set of expressions -*- c++ -*- #ifndef EXPRESSIONMSET_H_ # define EXPRESSIONMSET_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include /** @file ExpressionMSet.h * Multi-set of expressions (transient storage for quantification) */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Multi-set of expressions */ class ExpressionMSet { /** Pointer wrapper */ class eptr { public: eptr () : ptr (0) {} eptr (class Expression& expr) : ptr (expr.copy ()) {} ~eptr () { if (ptr) ptr->destroy (); } eptr (const class eptr& old) : ptr (old.ptr ? old.ptr->copy () : 0) {} private: class eptr& operator= (const class eptr& old); public: operator class Expression* () const { return ptr->copy (); } operator const class Expression* () const { return ptr; } bool operator== (const class eptr& other) const { return *ptr == *other.ptr; } bool operator< (const class eptr& other) const { return *ptr < *other.ptr; } private: class Expression* ptr; }; /*@{*/ /** Multi-set of expressions implemented as a map */ typedef std::map Map; /** Constant iterator to the multi-set */ typedef Map::const_iterator const_iterator; /** Iterator to the multi-set */ typedef Map::iterator iterator; /*@}*/ public: /** Constructor */ ExpressionMSet () : myMap () {} private: /** Copy constructor */ ExpressionMSet (const class ExpressionMSet& old); /** Assignment operator */ class ExpressionMSet& operator= (const class ExpressionMSet& old); public: /** Destructor */ ~ExpressionMSet () {} /** Insert an expression to the multi-set * @param expr expression to be inserted * @param count multiplicity of the expression * @return whether the operation was successful (no overflow) */ bool insert (class Expression& expr, card_t count) { assert (count > 0); std::pair status = myMap.insert (Map::value_type (expr, count)); if (!status.second) { if (count >= CARD_T_MAX - status.first->second) return false; else status.first->second += count; } return true; } /** Convert the multi-set to a marking expression * @param place the place associated with the marking expressions * @return a marking list */ class Marking* toMarking (const class Place* place); /** @name Accessors to the expression multi-set */ /*@{*/ void clear () { myMap.clear (); } iterator begin () { return myMap.begin (); } iterator end () { return myMap.end (); } const_iterator begin () const { return myMap.begin (); } const_iterator end () const { return myMap.end (); } /*@}*/ private: /** The marking set */ Map myMap; }; #endif // EXPRESSIONMSET_H_ maria-1.3.5/Expression/ExpressionSet.C0000644000175000017500000000207507643235732020054 0ustar msmakelamsmakela// Set of expressions -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "ExpressionSet.h" /** @file ExpressionSet.C * Set of expressions */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ maria-1.3.5/Expression/ExpressionSet.h0000644000175000017500000000656407643235732020130 0ustar msmakelamsmakela// Set of expressions -*- c++ -*- #ifndef EXPRESSIONSET_H_ # define EXPRESSIONSET_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include # include /** @file ExpressionSet.h * Set of expressions */ /* Copyright © 1999-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Set of expressions */ class ExpressionSet { /** Pointer wrapper */ class eptr { public: eptr () : ptr (0) {} eptr (class Expression* expr) : ptr (expr->copy ()) {} ~eptr () { if (ptr) ptr->destroy (); } eptr (const class eptr& old) : ptr (old.ptr ? old.ptr->copy () : 0) {} private: class eptr& operator= (const class eptr& old); public: operator class Expression* () const { return ptr->copy (); } operator const class Expression* () const { return ptr; } bool operator== (const class eptr& other) const { return *ptr == *other.ptr; } bool operator< (const class eptr& other) const { return *ptr < *other.ptr; } private: class Expression* ptr; }; /*@{*/ /** Set of expressions */ typedef std::set Set; /** Constant iterator to the expression set */ typedef Set::const_iterator const_iterator; /** Iterator to the expression set */ typedef Set::iterator iterator; /*@}*/ public: /** Constructor */ ExpressionSet () : mySet () {} private: /** Copy constructor */ ExpressionSet (const class ExpressionSet& old); /** Assignment operator */ class ExpressionSet& operator= (const class ExpressionSet& old); public: /** Destructor */ ~ExpressionSet () {} /** Determine whether the ExpressionSet is empty */ bool empty () const { return mySet.empty (); } /** Insert an Expression to the set * @param expr Expression to be inserted * @return expr or an equivalent expression */ class Expression* insert (class Expression* expr) { assert (expr != NULL); std::pair status; { eptr e (expr); status = mySet.insert (e); } if (!status.second) { assert (expr->isLastCopy () || expr == static_cast(*status.first)); expr->destroy (); return *status.first; } else return expr; } /** @name Accessors to the expression set */ /*@{*/ iterator begin () { return mySet.begin (); } iterator end () { return mySet.end (); } const_iterator begin () const { return mySet.begin (); } const_iterator end () const { return mySet.end (); } /*@}*/ private: /** The expression set */ Set mySet; }; #endif // EXPRESSIONSET_H_ maria-1.3.5/Expression/Function.C0000644000175000017500000000423007643235732017021 0ustar msmakelamsmakela// Function definition -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Function.h" #include "VariableDefinition.h" #include "Variable.h" #include "ExpressionList.h" #include "Substitution.h" /** @file Function.C * Function (typed macro) definition */ /* Copyright © 1999-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Function::Function (char* name, unsigned arity, class VariableDefinition** params, class Expression* expr, bool copy) : myName (name), myArity (arity), myParams (params), myExpr (expr), myCopy (copy) { assert (name && expr); } Function::~Function () { delete[] myName; myExpr->destroy (); for (unsigned i = 0; i < myArity; i++) delete myParams[i]; delete[] myParams; } void Function::substitute (class Substitution& substitution) { class Expression* expr = myExpr->substitute (substitution); assert (!!expr); myExpr->destroy (); myExpr = expr; } class Expression* Function::expand (class ExpressionList* params) { if (myArity != (params ? params->size () : 0)) return NULL; class Substitution substitution; for (unsigned i = 0; i < myArity; i++) { if (!(*params)[i].isAssignable (myParams[i]->getType ())) return NULL; substitution.setExpr (*myParams[i], *(*params)[i].copy ()); } return myExpr->substitute (substitution); } maria-1.3.5/Expression/Function.h0000644000175000017500000000557207643235732017100 0ustar msmakelamsmakela// Function definition -*- c++ -*- #ifndef FUNCTION_H_ # define FUNCTION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include /** @file Function.h * Function (typed macro) definition */ /* Copyright © 1999-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Function definition */ class Function { public: /** Constructor * @param name Name of the function * @param arity Arity (number of function parameters) * @param params Parameter list of the function * @param expr Function definition * @param copy Flag: is this a copied definition? */ Function (char* name, unsigned arity, class VariableDefinition** params, class Expression* expr, bool copy = false); private: /** Copy constructor */ Function (const class Function& old); /** Assignment operator */ class Function& operator= (const class Function& old); public: /** Destructor */ ~Function (); /** Determine the name of the function */ const char* getName () const { return myName; } /** Determine the arity of the function */ unsigned getArity () const { return myArity; } /** Get a formal parameter */ const class VariableDefinition& operator[] (unsigned i) const { assert (i < myArity); return *myParams[i]; } /** Get the expression */ const class Expression& getExpr () const { return *myExpr; } /** Determine whether this is a copied function definition */ bool isCopy () const { return myCopy; } /** Substitute the expression */ void substitute (class Substitution& substitution); /** Expand the function * @param params The expression list * @return The expanded function, or NULL in case of error */ class Expression* expand (class ExpressionList* params); private: /** Name of the function */ char* myName; /** Arity of the function */ unsigned myArity; /** Function parameters */ class VariableDefinition** myParams; /** Function definition */ class Expression* myExpr; /** Flag: is this a copied function definition? */ const bool myCopy; }; #endif // FUNCTION_H_ maria-1.3.5/Expression/IfThenElse.C0000644000175000017500000002221207722340367017221 0ustar msmakelamsmakela// Maria if-then-else expression class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "IfThenElse.h" #include "Type.h" #include "Printer.h" /** @file IfThenElse.C * Selection expression */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ IfThenElse::IfThenElse (class Expression& condition, class ExpressionList& exprList) : Expression (), myCondition (&condition), myExprList (&exprList) { assert (myCondition->getType ()->getNumValues () == exprList.size ()); setType (*myExprList->getType ()); } IfThenElse::~IfThenElse () { myCondition->destroy (); myExprList->destroy (); } bool IfThenElse::isBasic () const { return myCondition->isBasic () && myExprList->isBasic (); } bool IfThenElse::isTemporal () const { return myCondition->isTemporal () || myExprList->isTemporal (); } bool IfThenElse::isSet () const { return myExprList->isSet (); } void IfThenElse::setType (const class Type& type) { Expression::setType (type); assert (myExprList->getType () == &type); } class Value* IfThenElse::do_eval (const class Valuation& valuation) const { if (class Value* cond = myCondition->eval (valuation)) { const card_t i = myCondition->getType ()->convert (*cond); delete cond; return (*myExprList)[i].eval (valuation); } else return NULL; } class PlaceMarking* IfThenElse::meval (const class Valuation& valuation) const { if (class Value* cond = myCondition->eval (valuation)) { const card_t i = myCondition->getType ()->convert (*cond); delete cond; return (*myExprList)[i].meval (valuation); } else return NULL; } class Expression* IfThenElse::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* expr = NULL; if (class Value* cond = myCondition->eval (valuation)) { const card_t i = myCondition->getType ()->convert (*cond); delete cond; if (!(expr = (*myExprList)[i].ground (valuation, transition, declare))) return NULL; } else { assert (!valuation.isOK ()); valuation.clearErrors (); class Expression* condition = myCondition->ground (valuation, transition, declare); if (!condition) return NULL; class ExpressionList* exprList = myExprList->ground (valuation, transition, declare); if (!exprList) { condition->destroy (); return NULL; } if (condition == myCondition && exprList == myExprList) { condition->destroy (); exprList->destroy (); return copy (); } else expr = (new class IfThenElse (*condition, *exprList))->cse (); } return expr->ground (valuation); } class Expression* IfThenElse::substitute (class Substitution& substitution) { class Expression* condition = myCondition->substitute (substitution); class ExpressionList* exprList = myExprList->substitute (substitution); if (condition == myCondition && exprList == myExprList) { condition->destroy (); exprList->destroy (); return copy (); } else return (new class IfThenElse (*condition, *exprList))->cse (); } bool IfThenElse::depends (const class VariableSet& vars, bool complement) const { return myCondition->depends (vars, complement) || myExprList->depends (vars, complement); } bool IfThenElse::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myCondition->forExpressions (operation, data) && myExprList->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" void IfThenElse::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { class StringBuffer& out = cexpr.getOut (); char* cond; if (cexpr.getVariable (*myCondition, cond)) myCondition->compile (cexpr, indent, cond, vars); char* condconv = 0; if (!getType ()->isLeaf () && cexpr.getConverted (*myCondition, condconv)) myCondition->getType ()->compileConversion (out, indent, cond, condconv, false); bool* checkpoint; unsigned checkpointSize = cexpr.getCheckpoint (checkpoint); out.indent (indent); out.append ("switch ("); if (getType ()->isLeaf ()) out.append (cond); else out.append (condconv); out.append (") {\n"); for (card_t i = 0; i < myExprList->size (); i++) { out.indent (indent); out.append ("case "); if (getType ()->isLeaf ()) { class Value* v = myCondition->getType ()->convert (i); v->compile (out); delete v; } else out.append (i); out.append (":\n"); (*myExprList)[i].compile (cexpr, indent + 2, lvalue, vars); cexpr.setCheckpoint (indent + 2, checkpoint, checkpointSize); out.indent (indent + 2); out.append ("break;\n"); } out.indent (indent); out.append ("}\n"); delete[] checkpoint; delete[] cond; delete[] condconv; } void IfThenElse::compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const { class StringBuffer& out = cexpr.getOut (); char* cond; if (cexpr.getVariable (*myCondition, cond)) myCondition->compile (cexpr, indent, cond, vars); char* condconv = 0; if (!getType ()->isLeaf () && cexpr.getConverted (*myCondition, condconv)) myCondition->getType ()->compileConversion (out, indent, cond, condconv, false); bool* checkpoint; unsigned checkpointSize = cexpr.getCheckpoint (checkpoint); out.indent (indent); out.append ("switch ("); if (getType ()->isLeaf ()) out.append (cond); else out.append (condconv); out.append (") {\n"); for (card_t i = 0; i < myExprList->size (); i++) { out.indent (indent); out.append ("case "); if (getType ()->isLeaf ()) { class Value* v = myCondition->getType ()->convert (i); v->compile (out); delete v; } else out.append (i); out.append (":\n"); (*myExprList)[i].compileMset (cexpr, indent + 2, resulttype, result, vars); cexpr.setCheckpoint (indent + 2, checkpoint, checkpointSize); out.indent (indent + 2); out.append ("break;\n"); } out.indent (indent); out.append ("}\n"); delete[] checkpoint; delete[] cond; delete[] condconv; } #endif // EXPR_COMPILE void IfThenElse::display (const class Printer& printer) const { myCondition->display (printer); printer.delimiter ('?'); for (card_t i = myExprList->size (); i--; ) { const class Expression& expr = (*myExprList)[i]; switch (expr.getKind ()) { case Expression::eVariable: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eStructAssign: case Expression::eUnionComponent: case Expression::eUnionType: case Expression::eVectorIndex: case Expression::eVectorAssign: case Expression::eVectorShift: case Expression::eUnop: case Expression::eBinop: case Expression::eBooleanBinop: case Expression::eNot: case Expression::eRelop: case Expression::eBufferUnop: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eTypecast: case Expression::eCardinality: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: break; case Expression::eIfThenElse: case Expression::eMarking: printer.delimiter ('(')++; expr.display (printer); --printer.delimiter (')'); if (i) printer.delimiter (':'); continue; case Expression::eConstant: case Expression::eStruct: case Expression::eUnion: case Expression::eVector: case Expression::eBuffer: if (const char* name = expr.getType ()->getName ()) { printer.printRaw ("is"); printer.delimiter (' '); printer.print (name); printer.delimiter (' '); } else { switch (expr.getType ()->getKind ()) { case Type::tInt: case Type::tCard: printer.printRaw ("is"); printer.delimiter (' '); printer.print (expr.getType ()->getSyntacticName ()); printer.delimiter (' '); break; default: break; } } break; } expr.display (printer); if (i) printer.delimiter (':'); } } maria-1.3.5/Expression/IfThenElse.h0000644000175000017500000001267707722340367017304 0ustar msmakelamsmakela// Maria if-then-else expression class -*- c++ -*- #ifndef IFTHENELSE_H_ # define IFTHENELSE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include "ExpressionList.h" /** @file IfThenElse.h * Selection expression */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** If-then-else expression */ class IfThenElse : public Expression { public: /** Constructor * @param condition "if" expression * @param exprList expression list */ IfThenElse (class Expression& condition, class ExpressionList& exprList); private: /** Copy constructor */ IfThenElse (const class IfThenElse& old); /** Assignment operator */ class IfThenElse& operator= (const class IfThenElse& old); protected: /** Destructor */ ~IfThenElse (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eIfThenElse; } /** Determine whether this is a basic expression */ bool isBasic () const; /** Determine whether this is a temporal logic expression */ bool isTemporal () const; /** Determine whether this is a multiset-valued expression */ bool isSet () const; /** Set the type of the subexpressions */ void setType (const class Type& type); /** Equality comparison operator */ bool operator== (const class IfThenElse& other) const { return *myCondition == *other.myCondition && *myExprList == *other.myExprList; } /** Ordering comparison operator */ bool operator< (const class IfThenElse& other) const { if (*myCondition < *other.myCondition) return true; if (*other.myCondition < *myCondition) return false; if (*myExprList < *other.myExprList) return true; if (*other.myExprList < *myExprList) return false; return false; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Evaluate the multiset expression * @param valuation variable substitutions and the global marking * @return a marking */ class PlaceMarking* meval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; /** Generate C code for evaluating the multi-set expression * @param cexpr the compilation * @param indent indentation level * @param resulttype type of result (optional typecast qualifier) * @param result multi-set to add items to * @param vars the variables that have been assigned a value * @return the compiled multi-set expression */ void compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** "if" expression */ class Expression* myCondition; /** expression list */ class ExpressionList* myExprList; }; #endif // IFTHENELSE_H_ maria-1.3.5/Expression/Mapping.C0000644000175000017500000002443707722340367016641 0ustar msmakelamsmakela// Multi-set mapping expression -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Mapping.h" #include "Marking.h" #include "VariableDefinition.h" #include "Valuation.h" #include "PlaceMarking.h" #include "LeafValue.h" #include "Substitution.h" #include "Variable.h" #include "Printer.h" /** @file Mapping.C * Multi-set mapping operation */ /* Copyright © 1999-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Mapping::Mapping (class VariableDefinition& variable, class VariableDefinition* cardinality, class Expression& marking, class Expression& expr) : myVariable (&variable), myCardinality (cardinality), myMarking (&marking), myExpr (&expr) { assert (myVariable && myExpr); assert (myMarking && myMarking->getType ()); assert (!myMarking->isTemporal ()); if (myCardinality) { assert (myCardinality->getType ().getKind () == Type::tCard); assert (myExpr->getKind () == Expression::eMarking); } else assert (myExpr->isBasic ()); setType (*myExpr->getType ()); } Mapping::~Mapping () { delete myVariable; delete myCardinality; myMarking->destroy (); myExpr->destroy (); } class PlaceMarking* Mapping::meval (const class Valuation& valuation) const { if (class PlaceMarking* p = myMarking->meval (valuation)) { p->setPlace (NULL); class Valuation v (valuation); class PlaceMarking* q = new class PlaceMarking (); #ifndef NDEBUG q->setType (myExpr->getType ()); #endif // NDEBUG for (PlaceMarking::iterator i = p->begin (); i != p->end (); i++) { if (!PlaceMarking::getCount (i)) continue; v.setValue (*myVariable, *PlaceMarking::getValue (i).copy ()); if (myCardinality) { v.setValue (*myCardinality, *new class LeafValue (myCardinality->getType (), PlaceMarking::getCount (i))); if (!static_cast(myExpr)->add (*q, 1, v)) { error: valuation.copyErrors (v); error2: delete p; delete q; return NULL; } } else if (class Value* val = myExpr->eval (v)) { if (!q->add (*val, PlaceMarking::getCount (i))) { valuation.flag (errCard, *this); goto error2; } } else goto error; } delete p; return q; } return NULL; } /** Create a Mapping, substituting the iterator variables * @param variable the old token iterator variable * @param cardinality the old cardinality iterator variable * @param marking the marking expression * @param condition the mapping expression (iterator substituted) * @return the corresponding Submarking expression */ static class Mapping* newMapping (const class VariableDefinition& variable, const class VariableDefinition* cardinality, class Expression& marking, class Expression& expr) { class VariableDefinition& v = *new class VariableDefinition (variable); class VariableDefinition* c = cardinality ? new class VariableDefinition (*cardinality) : 0; class Substitution s; s.setExpr (variable, *(new class Variable (v))->cse ()); if (cardinality) s.setExpr (*cardinality, *(new class Variable (*c))->cse ()); class Expression* e = expr.substitute (s); assert (!!e); expr.destroy (); return static_cast ((new class Mapping (v, c, marking, *e))->cse ()); } class Expression* Mapping::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* marking = myMarking->ground (valuation, transition, declare); if (!marking) return NULL; class Expression* expr = myExpr->ground (valuation, transition, declare); if (!expr) { marking->destroy (); return NULL; } assert (valuation.isOK ()); if (marking == myMarking && expr == myExpr) { marking->destroy (); expr->destroy (); return copy (); } else return newMapping (*myVariable, myCardinality, *marking, *expr); } class Expression* Mapping::substitute (class Substitution& substitution) { class Expression* marking = myMarking->substitute (substitution); class Expression* expr = myExpr->substitute (substitution); if (!marking || !expr) { marking->destroy (); expr->destroy (); return NULL; } if (marking == myMarking && expr == myExpr) { marking->destroy (); expr->destroy (); return copy (); } else return newMapping (*myVariable, myCardinality, *marking, *expr); } bool Mapping::depends (const class VariableSet& vars, bool complement) const { return myMarking->depends (vars, complement) || myExpr->depends (vars, complement); } bool Mapping::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myMarking->forExpressions (operation, data) && myExpr->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" # include "Constant.h" # include "PlaceContents.h" # include "Place.h" void Mapping::compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const { assert (myVariable && myMarking && myExpr); /** the multi-set iterator */ char* iter; /** the mapping expression */ char* expr; /** the item iterator */ char* var; /** the multiplicity iterator */ char* card; if (myExpr->getKind () == Expression::eConstant) { if (cexpr.getVariable (static_cast(*myExpr), expr)) myExpr->compile (cexpr, indent, expr, vars); var = card = 0; } else { var = cexpr.getIterator (*myVariable); card = myCardinality ? cexpr.getIterator (*myCardinality) : 0; cexpr.getVariable (*myExpr, expr); } class StringBuffer& out = cexpr.getOut (); /** flag: is the marking the contents of a place with at most one token? */ bool place1 = myMarking->getKind () == Expression::ePlaceContents && static_cast (myMarking)->getPlace ().getMaxNumTokens () == 1; if (place1) { iter = static_cast(myMarking)->getName (cexpr); out.indent (indent); out.append ("if ("), out.append (iter), out.append (") {\n"); if (myExpr->getKind () != Expression::eConstant) { out.indent (indent + 2); myVariable->getType ().appendName (out); out.append (" "), out.append (var), out.append (" = *"); out.append (iter); out.append (";\n"); if (card) { out.indent (indent + 2); out.append ("card_t "), out.append (card), out.append ("=1;\n"); myExpr->compileMset (cexpr, indent + 2, resulttype, result, vars); } else myExpr->compile (cexpr, indent + 2, expr, vars); } if (!card) { out.indent (indent + 2); out.append (result); out.append ("=insert"); getType ()->appendIndex (out); out.append (" ("); if (resulttype) out.append (resulttype); out.append (result), out.append (", "); out.append ("&"), out.append (expr), out.append (", 1);\n"); } } else { /** the multi-set */ char* mset; if (cexpr.getVariable (*myMarking, mset)) myMarking->compileMset (cexpr, indent, 0, mset, vars); iter = cexpr.getLabel (); out.indent (indent), out.append ("{\n"); out.indent (indent + 2); myMarking->getType ()->appendMSetName (out); out.append ("* "), out.append (iter), out.append (" = "); out.append (mset), out.append (";\n"); delete[] mset; out.indent (indent + 2); out.append ("FIRST ("), out.append (iter), out.append (");\n"); out.indent (indent + 2); out.append ("while ("), out.append (iter), out.append (") {\n"); out.indent (indent + 4); out.append ("if ("), out.append (iter), out.append ("->count) {\n"); /** checkpoint in the while iteration loop */ bool* checkpoint; const unsigned checkpointSize = cexpr.getCheckpoint (checkpoint); if (myExpr->getKind () != Expression::eConstant) { out.indent (indent + 6); myVariable->getType ().appendName (out); out.append (" "), out.append (var), out.append ("="); out.append (iter), out.append ("->item;\n"); if (card) { out.indent (indent + 6); out.append ("card_t "), out.append (card), out.append ("="); out.append (iter), out.append ("->count;\n"); myExpr->compileMset (cexpr, indent + 6, resulttype, result, vars); } else myExpr->compile (cexpr, indent + 6, expr, vars); } if (!card) { out.indent (indent + 6); out.append (result); out.append ("=insert"); getType ()->appendIndex (out); out.append (" ("); if (resulttype) out.append (resulttype); out.append (result), out.append (", "); out.append ("&"), out.append (expr), out.append (", "); out.append (iter), out.append ("->count"); out.append (");\n"); } cexpr.setCheckpoint (indent + 6, checkpoint, checkpointSize); out.indent (indent + 4), out.append ("}\n"); out.indent (indent + 4); out.append ("NEXT ("), out.append (iter), out.append (");\n"); out.indent (indent + 2), out.append ("}\n"); } out.indent (indent), out.append ("}\n"); delete[] card; delete[] var; delete[] expr; delete[] iter; } #endif // EXPR_COMPILE void Mapping::display (const class Printer& printer) const { printer.printRaw ("map"); printer.delimiter (' '); printer.print (myVariable->getName ()); if (myCardinality) { printer.delimiter ('#'); printer.print (myCardinality->getName ()); } printer.delimiter ('{')++; myMarking->display (printer); --printer.delimiter ('}'); printer.delimiter ('(')++; myExpr->display (printer); --printer.delimiter (')'); } maria-1.3.5/Expression/Mapping.h0000644000175000017500000001332107722340367016674 0ustar msmakelamsmakela// Multi-set mapping expression -*- c++ -*- #ifndef MAPPING_H_ # define MAPPING_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file Mapping.h * Multi-set mapping operation */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Multi-set mapping */ class Mapping : public Expression { public: /** Constructor * @param variable a variable that will run through marking values * @param cardinality a variable that will run through marking cardinalities * @param marking a multi-set expression * @param expr the mapping expression for values or cardinalities */ Mapping (class VariableDefinition& variable, class VariableDefinition* cardinality, class Expression& marking, class Expression& expr); private: /** Copy constructor */ Mapping (const class Mapping& old); /** Assignment operator */ class Mapping& operator= (const class Mapping& old); protected: /** Destructor */ ~Mapping (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eMapping; } /** * Determine whether this is a basic expression containing * no temporal logic or set operations * @return true if this is a basic expression */ bool isBasic () const { return false; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** * Determine whether this is a multiset-valued expression * @return true if this is a multiset-valued expression */ bool isSet () const { return true; } /** Equality comparison operator */ bool operator== (const class Mapping& other) const { return myVariable == other.myVariable && myCardinality == other.myCardinality && *myMarking == *other.myMarking && *myExpr == *other.myExpr; } /** Ordering comparison operator */ bool operator< (const class Mapping& other) const { if (myVariable < other.myVariable) return true; if (other.myVariable < myVariable) return false; if (myCardinality < other.myCardinality) return true; if (other.myCardinality < myCardinality) return false; if (*myMarking < *other.myMarking) return true; if (*other.myMarking < *myMarking) return false; return *myExpr < *other.myExpr; } /** Evaluate the multiset expression * @param valuation variable substitutions and the global marking * @return the filtered marking */ class PlaceMarking* meval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression */ void compile (class CExpression&, unsigned, const char *, const class VariableSet*) const { assert (false); } /** Generate C code for evaluating the multi-set expression * @param cexpr the compilation * @param indent indentation level * @param resulttype type of result (optional typecast qualifier) * @param result multi-set to add items to * @param vars the variables that have been assigned a value * @return the compiled multi-set expression */ void compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The value iterator variable */ class VariableDefinition* myVariable; /** The cardinality iterator variable */ class VariableDefinition* myCardinality; /** The marking expression */ class Expression* myMarking; /** The mapping expression */ class Expression* myExpr; }; #endif // MAPPING_H_ maria-1.3.5/Expression/Marking.C0000644000175000017500000005064607722340370016631 0ustar msmakelamsmakela// Marking -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Marking.h" #include "PlaceMarking.h" #include "LeafValue.h" #include "Valuation.h" #include "Place.h" #include "Constant.h" #include "Net.h" #include "CardType.h" #include "ExpressionList.h" #include "IfThenElse.h" #include "Typecast.h" #include "VariableDefinition.h" #include "ExpressionMSet.h" #include "EmptySet.h" #include "Printer.h" /** @file Marking.C * Basic multi-set constructor operation */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Calculate the multiplicity of a marking * @param valuation variable substitutions * @param expr the multiplicity expression * @param count multiplicity of the surrounding marking expression * @return multiplicity of the marking expression (count * expr) */ inline static card_t calcMultiplicity (const class Valuation& valuation, const class Expression& expr, card_t count) { assert (count); if (class Value* v = expr.eval (valuation)) { assert (v->getKind () == Value::vLeaf); card_t c = card_t (static_cast(*v)); delete v; if (c >= CARD_T_MAX / count) { valuation.flag (errCard, expr); return 0; } else return count * c; } assert (!valuation.isOK ()); return 0; } Marking::Marking (const class Place* place, class Marking* child) : myChild (child), myParent (0), myNext (0), myPlace (place), myMultiplicity (0), myToken (0) { if (myPlace) Expression::setType (myPlace->getType ()); else if (myChild) Expression::setType (*myChild->getType ()); assert (!myChild || (myChild->myPlace == myPlace && myChild->getType () == getType ())); assert (!myChild || !myChild->myParent); for (class Marking* m = myChild; m; m = m->myNext) m->myParent = this; } Marking::~Marking () { myChild->destroy (); myNext->destroy (); myMultiplicity->destroy (); myToken->destroy (); } void Marking::setPlace (const class Place* place) { assert (!myPlace || myPlace == place); myPlace = place; if (myChild) myChild->setPlace (place); if (myNext) myNext->setPlace (place); } void Marking::setMultiplicity (class Expression* multiplicity) { assert (!multiplicity || multiplicity->isBasic ()); myMultiplicity = multiplicity; } void Marking::setToken (class Expression* token) { assert (!myToken && !myChild); myToken = token; if (myToken->getKind () == Expression::eEmptySet) return; assert (myToken && myToken->getType ()); Expression::setType (*myToken->getType ()); } void Marking::setType (const class Type& type) { for (class Marking* m = this; m; m = m->myNext) { Expression::setType (type); if (myToken) { myToken->setType (type); assert (!myChild); } else { assert (!!myChild); myChild->setType (type); } } } /** Inequality null comparison for member components that may be null * @param c component name * @return true if one of this.c and other.c is null */ #define NULLCMP(c) ((c && !other.c) || (!c && other.c)) bool Marking::operator== (const class Marking& other) const { if (myPlace != other.myPlace || NULLCMP (myChild) || NULLCMP (myToken) || NULLCMP (myMultiplicity) || NULLCMP (myNext)) return false; if (myChild) { assert (!myToken); if (!(*myChild == *other.myChild)) return false; } else { assert (myToken != NULL); if (!(*myToken == *other.myToken)) return false; } if (myMultiplicity && !(*myMultiplicity == *other.myMultiplicity)) return false; return !myNext || *myNext == *other.myNext; } #undef NULLCMP bool Marking::operator< (const class Marking& other) const { // the shorter chain of markings is smaller for (const class Marking *l = this, *r = &other; l && r; ) { l = l->myNext, r = r->myNext; if (!l && r) return true; if (!r && l) return false; } // the chains are of the same length => compare other things // place referred to by the first marking if (myPlace < other.myPlace) return true; if (other.myPlace < myPlace) return false; // presence of child marking if (!myChild && other.myChild) return true; if (!other.myChild && myChild) return false; if (myChild) { // ordering of child markings assert (!myToken); if (*myChild < *other.myChild) return true; if (*other.myChild < *myChild) return false; } // presence of token expression if (!myToken && other.myToken) return true; if (!other.myToken && myToken) return false; if (myToken) { // ordering of token expressions assert (!myChild); if (*myToken < *other.myToken) return true; if (*other.myToken < *myToken) return false; } else assert (!!myChild); // presence of multiplicity expression if (!myMultiplicity && other.myMultiplicity) return true; if (!other.myMultiplicity && myMultiplicity) return false; // ordering of multiplicity expressions if (myMultiplicity) { if (*myMultiplicity < *other.myMultiplicity) return true; if (*other.myMultiplicity < *myMultiplicity) return false; } // the next marking in the chain return myNext && *myNext < *other.myNext; } class Expression* Marking::ground (const class Valuation& valuation, class Transition* transition, bool declare) { valuation.clearErrors (); class ExpressionMSet result; if (ground (valuation, transition, declare, result, 1)) { assert (valuation.isOK ()); return result.toMarking (myPlace); } else { assert (!valuation.isOKorVar ()); return NULL; } } bool Marking::ground (const class Valuation& valuation, class Transition* transition, bool declare, class ExpressionMSet& result, card_t count) { assert (count > 0); for (class Marking* m = this; m; m = m->myNext) { assert (m->myPlace == myPlace); assert (valuation.isOK ()); valuation.clearErrors (); class Expression* multiplicity = m->myMultiplicity ? m->myMultiplicity->ground (valuation, transition, declare) : NULL; if (m->myMultiplicity && !multiplicity) return false; if (!multiplicity || multiplicity->getKind () == Expression::eConstant) { card_t c; if (multiplicity) { const class Value& mv = static_cast(multiplicity)->getValue (); assert (mv.getKind () == Value::vLeaf); c = card_t (static_cast(mv)); multiplicity->destroy (); if (!c) continue; else if (c >= CARD_T_MAX / count) { valuation.flag (errCard, *m); return false; } } else c = 1; if (m->myChild) { assert (!m->myToken); if (!m->myChild->ground (valuation, transition, declare, result, c * count)) return false; } else { assert (m->myToken && m->myToken->getKind () != Expression::eMarking); class Expression* token = m->myToken->ground (valuation, transition, declare); if (!token) return false; assert (valuation.isOK ()); if (!result.insert (*token, c * count)) { token->destroy (); valuation.flag (errCard, *m); return false; } token->destroy (); } } else { // variable multiplicity assert (m->myChild ? !m->myToken : !!m->myToken); class Expression* expr = m->myChild ? m->myChild->ground (valuation, transition, declare) : m->myToken->ground (valuation, transition, declare); if (!expr) { assert (!valuation.isOKorVar ()); multiplicity->destroy (); expr->destroy (); return false; } assert (valuation.isOK ()); class Marking* mm; if (m->myChild) { assert (expr && expr->getKind () == Expression::eMarking); mm = static_cast(expr); if (mm->myMultiplicity) mm = new class Marking (myPlace, mm); } else { mm = new class Marking (myPlace); mm->setToken (expr); } assert (!mm->myMultiplicity && multiplicity); mm->setMultiplicity (multiplicity); mm = static_cast(mm->cse ()); if (!result.insert (*mm, count)) { mm->destroy (); valuation.flag (errCard, *mm); return false; } mm->destroy (); } } return true; } class Expression* Marking::substitute (class Substitution& substitution) { class Marking* child = myChild ? static_cast(myChild->substitute (substitution)) : NULL; class Marking* n = myNext ? static_cast(myNext->substitute (substitution)) : NULL; class Expression* token = myToken ? myToken->substitute (substitution) : NULL; class Expression* multiplicity = myMultiplicity ? myMultiplicity->substitute (substitution) : NULL; if (child == myChild && n == myNext && token == myToken && multiplicity == myMultiplicity) { child->destroy (); n->destroy (); token->destroy (); multiplicity->destroy (); return copy (); } else { class Marking* m = new class Marking (myPlace, child); m->myMultiplicity = multiplicity; m->myNext = n; m->myToken = token; static_cast(m)->setType (*getType ()); return m->cse (); } } bool Marking::depends (const class VariableSet& vars, bool complement) const { return (myChild && myChild->depends (vars, complement)) || (myNext && myNext->depends (vars, complement)) || (myMultiplicity && myMultiplicity->depends (vars, complement)) || (myToken && myToken->depends (vars, complement)); } bool Marking::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && (!myChild || myChild->forExpressions (operation, data)) && (!myNext || myNext->forExpressions (operation, data)) && (!myMultiplicity || myMultiplicity->forExpressions (operation, data)) && (!myToken || myToken->forExpressions (operation, data)); } bool Marking::eval (class PlaceMarking* const source, class PlaceMarking* const target, const card_t count, const class Valuation& valuation) const { assert (count > 0); assert (valuation.isOK ()); for (const class Marking* m = this; m; m = m->myNext) { assert (valuation.isOK ()); card_t tokencount; if (m->myMultiplicity) { tokencount = calcMultiplicity (valuation, *m->myMultiplicity, count); if (!valuation.isOK ()) return false; } else tokencount = count; if (const class Expression* const expr = m->myToken) { assert (!m->myChild); if (tokencount) { if (expr->isSet ()) { if (class PlaceMarking* p = expr->meval (valuation)) { assert (!source && target); bool ok = target->add (*p, tokencount); delete p; if (!ok) { valuation.flag (errCard, *m); return false; } } else return false; } else if (class Value* token = expr->eval (valuation)) { if (source) source->remove (*token, tokencount); if (target) { if (!target->add (*token, tokencount)) { valuation.flag (errCard, *m); return false; } } else delete token; } else return false; } } else { assert (!!m->myChild); if (tokencount && !m->myChild->eval (source, target, tokencount, valuation)) return false; } } return true; } class PlaceMarking* Marking::meval (const class Valuation& valuation) const { class PlaceMarking* const p = new class PlaceMarking; #ifndef NDEBUG p->setType (getType ()); #endif if (add (*p, 1, valuation)) return p; delete p; return NULL; } card_t Marking::getMultiplicity (const class Valuation& valuation) const { card_t mult = myParent ? myParent->getMultiplicity (valuation) : 1; return mult && myMultiplicity ? calcMultiplicity (valuation, *myMultiplicity, mult) : mult; } class Expression* Marking::quantify (const class Valuation& valuation, class Transition* transition, class VariableDefinition& variable, class Expression* condition, bool declare) { class Valuation v (valuation); class ExpressionMSet result; assert (valuation.isOK ()); if (condition) { for (class Marking* m = this; m; m = m->myNext) if (m->myMultiplicity) { class ExpressionList* l = new class ExpressionList; l->append (*(new class Constant (*new class LeafValue (Net::getCardType (), 0)))->cse ()); l->append (*m->myMultiplicity); m->myMultiplicity = (new class IfThenElse (*condition->copy (), *l))->cse (); } else m->myMultiplicity = (new class Typecast (Net::getCardType (), *condition->copy ()))->cse (); } v.setValue (variable, variable.getType ().getFirstValue ()); do { if (!ground (v, transition, declare, result, 1)) { valuation.copyErrors (v); return NULL; } } while (v.increment (variable)); if (class Marking* m = result.toMarking (myPlace)) return m; else return (new class EmptySet)->cse (); } bool Marking::hasVariableMultiplicity () const { for (const class Marking* m = this; m; m = m->myParent) if (m->myMultiplicity && m->myMultiplicity->getKind () != Expression::eConstant) return true; return false; } #ifdef EXPR_COMPILE # include "CExpression.h" bool Marking::hasMultiplicity () const { for (const class Marking* m = this; m; m = m->myParent) if (m->myMultiplicity) return true; return false; } void Marking::compileScalarMset (class CExpression& cexpr, unsigned indent, const char* result, const class VariableSet* vars, bool check) const { if (myMultiplicity || myChild || myNext) Expression::compileScalarMset (cexpr, indent, result, vars, check); else if (myToken->isSet ()) myToken->compileScalarMset (cexpr, indent, result, vars, check); else { class StringBuffer& out = cexpr.getOut (); char* tmp; if (check) { out.indent (indent); out.append ("if ("); out.append (result); out.append (")\n"); cexpr.compileError (indent + 2, errConst); } if (myToken->getKind () == Expression::eConstant ? cexpr.getVariable (*static_cast(myToken), tmp) : cexpr.getVariable (*myToken, tmp)); myToken->compile (cexpr, indent, tmp, vars); out.indent (indent); out.append (result); out.append (" = &"); out.append (tmp); out.append (";\n"); delete[] tmp; } } void Marking::compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const { const class Constant* oldtoken = 0; char* token; for (const class Marking* m = first (); m; m = m->next ()) { assert (m->getType () == getType () && m->myToken); class StringBuffer& out = cexpr.getOut (); char* mult = 0; bool* checkpoint = 0; unsigned checkpointSize = 0; if (m->myToken->getKind () == Expression::eEmptySet) continue; if (m->hasMultiplicity ()) { mult = cexpr.getLabel (); out.indent (indent); out.append ("{\n"); out.indent (indent += 2); out.append ("card_t "); out.append (mult); out.append (";\n"); m->compileMultiplicity (cexpr, indent, mult, vars); checkpointSize = cexpr.getCheckpoint (checkpoint); out.indent (indent); out.append ("if ("), out.append (mult), out.append (") {\n"); indent += 2; } if (m->myToken->isSet ()) { if (cexpr.getVariable (*m->myToken, token)) m->myToken->compileMset (cexpr, indent, 0, token, vars); out.indent (indent); out.append (result); out.append (mult ? "=copyc" : "=copy"); getType ()->appendIndex (out); out.append (" ("); if (resulttype) out.append (resulttype); out.append (result); out.append (", "); out.append (token); if (mult) out.append (", "), out.append (mult); out.append (");\n"); delete[] token; } else { if (oldtoken) cexpr.recycle (*oldtoken, *m->myToken); if (m->myToken->getKind () == Expression::eConstant) { oldtoken = static_cast(m->myToken); if (cexpr.getVariable (*oldtoken, token)) oldtoken->compile (cexpr, indent, token, vars); } else if (oldtoken = 0, cexpr.getVariable (*m->myToken, token)) m->myToken->compile (cexpr, indent, token, vars); out.indent (indent); out.append (result); out.append ("=insert"); getType ()->appendIndex (out); out.append (" ("); if (resulttype) out.append (resulttype); out.append (result); out.append (", &"); out.append (token); out.append (", "); out.append (mult ? mult : "1"); out.append (");\n"); delete[] token; } if (mult) { cexpr.setCheckpoint (indent, checkpoint, checkpointSize); delete[] checkpoint; delete[] mult; out.indent (indent -= 2), out.append ("}\n"); out.indent (indent -= 2), out.append ("}\n"); } } } void Marking::compileMultiplicity (class CExpression& cexpr, unsigned indent, const char* result, const class VariableSet* vars) const { class StringBuffer& out = cexpr.getOut (); /** number of multiplicity expressions */ unsigned p, parents = 0; const class Marking* m; for (m = this; m; m = m->myParent) if (m->myMultiplicity) parents++; if (!parents) { out.indent (indent); out.append (result); out.append ("=1;\n"); return; } for (m = this; !m->myMultiplicity; m = m->myParent); for (p = parents; --p; ) while (!(m = m->myParent)->myMultiplicity); m->myMultiplicity->compile (cexpr, indent, result, vars); while (--parents) { for (m = this; !m->myMultiplicity; m = m->myParent); for (p = parents; --p; ) while (!(m = m->myParent)->myMultiplicity); bool* checkpoint = 0; unsigned checkpointSize = cexpr.getCheckpoint (checkpoint); out.indent (indent); out.append ("if ("); out.append (result); out.append (") {\n"); const char* work = cexpr.getVarTmpCount (); m->myMultiplicity->compile (cexpr, indent + 2, work, vars); out.indent (indent + 2); out.append ("if ("); out.append (work); out.append (">=CARD_T_MAX/"); out.append (result); out.append (")\n"); cexpr.compileError (indent + 4, errCard); out.indent (indent + 2); out.append (result); out.append ("*="); out.append (work); out.append (";\n"); cexpr.setCheckpoint (indent + 2, checkpoint, checkpointSize); delete[] checkpoint; out.indent (indent); out.append ("}\n"); } } #endif // EXPR_COMPILE void Marking::display (const class Printer& printer) const { for (const class Marking* m = this;; ) { if (m->myMultiplicity) { switch (m->myMultiplicity->getKind ()) { case eCardinality: case eUnop: case eConstant: case eVariable: m->myMultiplicity->display (printer); break; default: printer.delimiter ('(')++; m->myMultiplicity->display (printer); --printer.delimiter (')'); break; } printer.delimiter ('#'); } if (m->myToken) m->myToken->display (printer), assert (!m->myChild); else { assert (!!m->myChild); printer.delimiter ('(')++; m->myChild->display (printer); --printer.delimiter (')'); } if ((m = m->myNext)) printer.delimiter (','); else break; } } /** Display the multiplicity of a marking * @param printer the printer object * @param m the marking */ inline static void displayMultiplicity (const class Printer& printer, const class Marking& m) { if (m.getParent ()) displayMultiplicity (printer, *m.getParent ()); if (const class Expression* mult = m.getMultiplicity ()) mult->display (printer), printer.delimiter ('#'); } void Marking::displayToken (const class Printer& printer) const { const class Marking* m; for (m = this; m->myChild; m = m->myChild); assert (m && m->myToken); displayMultiplicity (printer, *m); m->myToken->display (printer); } maria-1.3.5/Expression/Marking.h0000644000175000017500000002634407722340370016674 0ustar msmakelamsmakela// Marking -*- c++ -*- #ifndef MARKING_H_ # define MARKING_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include /** @file Marking.h * Basic multi-set constructor operation */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Marking (basic multi-set) expression */ class Marking : public Expression { public: /** Result of a check */ enum Result { undefined, pass, fail }; /** Constructor * @param place the place the marking is associated with * @param child child marking */ Marking (const class Place* place, class Marking* child = 0); private: /** Copy constructor */ Marking (const class Marking& old); /** Assignment operator */ class Marking& operator= (const class Marking& old); protected: /** Destructor */ ~Marking (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eMarking; } /** Get the child marking */ const class Marking* getChild () const { return myChild; } /** Get the parent marking */ const class Marking* getParent () const { return myParent; } /** Set the place associated with this marking (and its neighbours) */ void setPlace (const class Place* place); /** Get the place associated with this marking */ const class Place* getPlace () const { return myPlace; } /** Set the multiplicity associated with this marking */ void setMultiplicity (class Expression* multiplicity); /** Get the multiplicity associated with this marking */ const class Expression* getMultiplicity () const { return myMultiplicity; } /** Get the multiplicity expression associated with this marking */ class Expression* getMultiplicity () { return myMultiplicity; } /** Set the token value expression associated with this marking */ void setToken (class Expression* token); /** Get the token value expression associated with this marking */ class Expression* getToken () const { return myToken; } /** Get the next marking in the list */ const class Marking* getNext () const { return myNext; } /** * Determine whether this is a basic expression containing * no temporal logic or set operations * @return true if this is a basic expression */ bool isBasic () const { return true; } /** * Determine whether this is a temporal logic expression * @return true if this is a temporal logic expression */ bool isTemporal () const { return false; } /** * Determine whether this is a multiset-valued expression * @return true if this is a multiset-valued expression */ bool isSet () const { return true; } /** Set the type of the expression and its subexpressions */ void setType (const class Type& type); /** Equality comparison operator */ bool operator== (const class Marking& other) const; /** Ordering comparison operator */ bool operator< (const class Marking& other) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Partially evaluate the marking using a valuation * @param valuation variable substitutions * @param transition transition for registering quantified variables * @param declare flag: declare new variables if required * @param result placeholder for the grounded markings * @param count initial multiplicity * @return true if the operation was successful */ bool ground (const class Valuation& valuation, class Transition* transition, bool declare, class ExpressionMSet& result, card_t count); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Evaluate the marking and add it to or remove it from a PlaceMarking * @param source the PlaceMarking object whose tokens are to be removed * @param target the PlaceMarking object to receive the tokens * @param count token multiplier * @param valuation variable substitutions * @return true if everything evaluated ok; false otherwise */ bool eval (class PlaceMarking* const source, class PlaceMarking* const target, const card_t count, const class Valuation& valuation) const; /** Evaluate the marking and add it to a PlaceMarking * @param target the PlaceMarking object to receive the tokens * @param count token multiplier * @param valuation variable substitutions * @return true if everything evaluated ok; false otherwise */ bool add (class PlaceMarking& target, const card_t count, const class Valuation& valuation) const { return eval (NULL, &target, count, valuation); } /** Evaluate the marking and remove it from a PlaceMarking * @param source the PlaceMarking object whose tokens are to be removed * @param count token multiplier * @param valuation variable substitutions * @return true if everything evaluated ok; false otherwise */ bool remove (class PlaceMarking& source, const card_t count, const class Valuation& valuation) const { return eval (&source, NULL, count, valuation); } /** Evaluate the marking expression * @param valuation variable substitutions * @return a PlaceMarking object, or NULL */ class PlaceMarking* meval (const class Valuation& valuation) const; /** Calculate the multiplicity of the marking * @param valuation Valuation for evaluating the expressions * @return the multiplicity (0 in case of an error) */ card_t getMultiplicity (const class Valuation& valuation) const; /** Append a marking to the list of markings * @param expr Marking to be appended */ void append (class Marking& expr) { class Marking* m = this; assert (&expr != this); while (m->myNext) { assert (&expr != m->myNext); assert (m->myParent == myParent); m = m->myNext; } m->myNext = &expr, m->myParent = myParent; } /** Get first marking expression */ const class Marking* first () const { const class Marking* m = this; while (m->myChild) m = m->myChild; return m; } /** Get next marking expression */ const class Marking* next () const { for (const class Marking* m = this; m; m = m->myParent) if (m->myNext) return m->myNext->first (); return 0; } /** Quantify the marking * @param valuation variable substitutions (mainly for error reporting) * @param transition transition for registering quantified variables * @param variable the quantifier variable * @param condition quantification condition (optional) * @param declare flag: declare new variables if required * @return a corresponding multi-set expression, or NULL */ class Expression* quantify (const class Valuation& valuation, class Transition* transition, class VariableDefinition& variable, class Expression* condition, bool declare); /** Determine if a marking expression has a non-constant multiplicity * @return whether the marking expression has a variable multiplicity */ bool hasVariableMultiplicity () const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression */ void compile (class CExpression&, unsigned, const char*, const class VariableSet*) const { assert (false); } /** Determine if a marking expression is associated with a multiplicity * @return whether the marking expression has a multiplicity */ bool hasMultiplicity () const; /** Generate C code for evaluating a multi-set expression as a scalar * @param cexpr the compilation * @param indent indentation level * @param result scalar to assign the multi-set to (must be singleton) * @param vars the variables that have been assigned a value * @param check flag: check for result overflow */ void compileScalarMset (class CExpression& cexpr, unsigned indent, const char* result, const class VariableSet* vars, bool check) const; /** Generate C code for evaluating the multi-set expression * @param cexpr the compilation * @param indent indentation level * @param resulttype type of result (optional typecast qualifier) * @param result multi-set to add items to * @param vars the variables that have been assigned a value */ void compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const; /** Generate C code for evaluating the multiplicity * @param cexpr the compilation * @param indent indentation level * @param result placeholder for the result * @param vars the variables that have been assigned a value */ void compileMultiplicity (class CExpression& cexpr, unsigned indent, const char* result, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; /** Display the token * @param printer the printer object */ void displayToken (const class Printer& printer) const; private: /** The child marking */ class Marking* myChild; /** The parent marking (of a child marking) */ const class Marking* myParent; /** The sibling marking */ class Marking* myNext; /** The place associated with the marking */ const class Place* myPlace; /** The multiplicity of the marking */ class Expression* myMultiplicity; /** The token expression of the marking */ class Expression* myToken; }; #endif // MARKING_H_ maria-1.3.5/Expression/NotExpression.C0000644000175000017500000001356507722340370020060 0ustar msmakelamsmakela// Maria boolean negation operator class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "NotExpression.h" #include "Type.h" #include "LeafValue.h" #include "Constant.h" #include "Property.h" #include "Printer.h" /** @file NotExpression.C * Boolean negation operator */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ NotExpression::NotExpression (class Expression& expr) : Expression (), myExpr (&expr) { setType (*myExpr->getType ()); assert (getType ()->getKind () == Type::tBool); } NotExpression::~NotExpression () { myExpr->destroy (); } class Expression* NotExpression::construct (class Expression& expr) { if (expr.getKind () == Expression::eNot) { class Expression* e = const_cast (static_cast(expr).myExpr)->copy (); expr.destroy (); return e; } return (new class NotExpression (expr))->cse (); } class Value* NotExpression::do_eval (const class Valuation& valuation) const { if (class Value* v = myExpr->eval (valuation)) { assert (v->getKind () == Value::vLeaf); static_cast(v)-> setValue (!bool (static_cast(*v))); return constrain (valuation, v); } else return NULL; } class Expression* NotExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* e = myExpr->ground (valuation, transition, declare); if (!e) return NULL; assert (valuation.isOK ()); if (e == myExpr) { e->destroy (); return copy (); } else return construct (*e)->ground (valuation); } class Expression* NotExpression::substitute (class Substitution& substitution) { class Expression* e = myExpr->substitute (substitution); if (e == myExpr) { e->destroy (); return copy (); } else return construct (*e); } bool NotExpression::depends (const class VariableSet& vars, bool complement) const { return myExpr->depends (vars, complement); } bool NotExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myExpr->forExpressions (operation, data); } class Expression* NotExpression::disqualify (const class Transition& transition) { if (class Expression* expr = myExpr->disqualify (transition)) { if (expr == myExpr) { expr->destroy (); return copy (); } if (expr->getKind () == Expression::eConstant) { const class Value& v = static_cast(expr)->getValue (); assert (v.getKind () == Value::vLeaf); return (new class Constant (*new class LeafValue (*getType (), !bool (static_cast(v)))))->cse (); } else return construct (*expr); } return 0; } class Ltl* NotExpression::toFormula (class Property& property) { return property.addUnop (Property::opNot, *myExpr); } #ifdef EXPR_COMPILE # include "CExpression.h" void NotExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { myExpr->compile (cexpr, indent, lvalue, vars); class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append (lvalue); out.append ("=!"); out.append (lvalue); out.append (";\n"); compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eVectorIndex: case Expression::eNot: case Expression::eTypecast: return false; case Expression::eStruct: case Expression::eUnion: case Expression::eVector: case Expression::eUnop: case Expression::eBinop: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferUnop: case Expression::eBufferWrite: case Expression::eBufferIndex: case Expression::eCardinality: case Expression::eMarking: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: assert (false); case Expression::eBooleanBinop: case Expression::eUnionType: case Expression::eIfThenElse: case Expression::eSet: case Expression::eRelop: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eTransitionQualifier: break; } return true; } void NotExpression::display (const class Printer& printer) const { printer.delimiter ('!'); if (::needParentheses (myExpr->getKind ())) { printer.delimiter ('(')++; myExpr->display (printer); --printer.delimiter (')'); } else myExpr->display (printer); } maria-1.3.5/Expression/NotExpression.h0000644000175000017500000001172007722340370020114 0ustar msmakelamsmakela// Maria boolean negation operator class -*- c++ -*- #ifndef NOTEXPRESSION_H_ # define NOTEXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file NotExpression.h * Boolean negation operator */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Boolean negation operator expression */ class NotExpression : public Expression { protected: /** Constructor * @param expr Expression the negation is applied to */ NotExpression (class Expression& expr); private: /** Copy constructor */ NotExpression (const class NotExpression& old); /** Assignment operator */ class NotExpression& operator= (const class NotExpression& old); protected: /** Destructor */ ~NotExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eNot; } /** Determine whether this is a basic expression */ bool isBasic () const { return myExpr->isBasic (); } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return myExpr->isTemporal (); } /** Construct a NotExpression, optimizing double negations away * @param expr expression to be negated * @return negation of the expression */ static class Expression* construct (class Expression& expr); /** Equality comparison operator */ bool operator== (const class NotExpression& other) const { return *myExpr == *other.myExpr; } /** Ordering comparison operator */ bool operator< (const class NotExpression& other) const { return *myExpr < *other.myExpr; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Remove transition qualifiers from the expression * @param transition the transition for which the expression is qualified * @return the expession without qualifiers, or NULL */ class Expression* disqualify (const class Transition& transition); /** Translate the expression to a list of temporal logic connectives * and Boolean propositions * @param property the property automaton * @return the translated object */ class Ltl* toFormula (class Property& property); # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The subexpression */ class Expression* myExpr; }; #endif // NOTEXPRESSION_H_ maria-1.3.5/Expression/PlaceContents.C0000644000175000017500000001154307722340370017774 0ustar msmakelamsmakela// Dynamic place contents -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "PlaceContents.h" #include #include "Place.h" #include "GlobalMarking.h" #include "Valuation.h" #include "Printer.h" /** @file PlaceContents.C * Operation for reading the marking of a place */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ PlaceContents::PlaceContents (const class Place& place) : myPlace (place) { setType (place.getType ()); } PlaceContents::~PlaceContents () { } class PlaceMarking* PlaceContents::meval (const class Valuation& valuation) const { if (const class GlobalMarking* m = valuation.getGlobalMarking ()) return new class PlaceMarking ((*m)[myPlace]); else { valuation.flag (errVar, *this); return NULL; } } bool PlaceContents::depends (const class VariableSet&, bool) const { return false; } bool PlaceContents::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data); } #ifdef EXPR_COMPILE # include "CExpression.h" void PlaceContents::compileScalarMset (class CExpression& cexpr, unsigned indent, const char* result, const class VariableSet*, bool check) const { class StringBuffer& out = cexpr.getOut (); if (check) { out.indent (indent); out.append ("if ("); out.append (result); if (myPlace.getMaxNumTokens () == 1) { out.append (" && "); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (myPlace.getIndex ()); } else { out.append (" && singleton ("); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (myPlace.getIndex ()); out.append (")"); } out.append (")\n"); cexpr.compileError (indent + 2, errConst); } if (myPlace.getMaxNumTokens () == 1) { out.indent (indent); out.append (result); out.append (" = "); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (myPlace.getIndex ()); out.append (";\n"); } else { out.indent (indent); out.append (result); out.append (" = singleton ("); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (myPlace.getIndex ()); out.append (");\n"); } } void PlaceContents::compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet*) const { class StringBuffer& out = cexpr.getOut (); if (myPlace.getMaxNumTokens () == 1) { out.indent (indent); if (myPlace.getCapacityBits ()) { out.append ("if ("); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (myPlace.getIndex ()); out.append (")\n"); out.indent (indent + 2); } out.append (result); out.append ("=insert"); getType ()->appendIndex (out); out.append (" ("); if (resulttype) out.append (resulttype); out.append (result); out.append (", "); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (myPlace.getIndex ()); out.append (", 1);\n"); } else { out.indent (indent); out.append (result); out.append ("=copy"); getType ()->appendIndex (out); out.append (" ("); if (resulttype) out.append (resulttype); out.append (result); out.append (", "); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (myPlace.getIndex ()); out.append (");\n"); } } char* PlaceContents::getName (const class CExpression& cexpr) const { const char* mset = cexpr.getMultiset (); assert (!!mset); class StringBuffer buf; buf.append (mset); buf.append (".p"); buf.append (myPlace.getIndex ()); char* name = new char[buf.getLength () + 1]; memcpy (name, buf.getString (), buf.getLength () + 1); return name; } #endif // EXPR_COMPILE void PlaceContents::display (const class Printer& printer) const { printer.printRaw ("place"); printer.delimiter (' '); printer.print (myPlace.getName ()); } maria-1.3.5/Expression/PlaceContents.h0000644000175000017500000001260707722340370020043 0ustar msmakelamsmakela// Dynamic place contents -*- c++ -*- #ifndef PLACECONTENTS_H_ # define PLACECONTENTS_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file PlaceContents.h * Operation for reading the marking of a place */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Place contents expression */ class PlaceContents : public Expression { public: /** Constructor * @param place the place whose marking is to be determined */ PlaceContents (const class Place& place); private: /** Copy constructor */ PlaceContents (const class PlaceContents& old); /** Assignment operator */ class PlaceContents& operator= (const class PlaceContents& old); protected: /** Destructor */ ~PlaceContents (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return ePlaceContents; } /** Get the place */ const class Place& getPlace () const { return myPlace; } /** * Determine whether this is a basic expression containing * no temporal logic or set operations * @return true if this is a basic expression */ bool isBasic () const { return false; } /** * Determine whether this is a temporal logic expression * @return true if this is a temporal logic expression */ bool isTemporal () const { return false; } /** * Determine whether this is a multiset-valued expression * @return true if this is a multiset-valued expression */ bool isSet () const { return true; } /** Equality comparison operator */ bool operator== (const class PlaceContents& other) const { return &myPlace == &other.myPlace; } /** Ordering comparison operator */ bool operator< (const class PlaceContents& other) const { return &myPlace < &other.myPlace; } /** Evaluate the multiset expression * @param valuation variable substitutions and the global marking * @return the marking of myPlace */ class PlaceMarking* meval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation&, class Transition*, bool) { return copy (); } /** Substitute some variables in the expression with expressions * @return substituted expression */ class Expression* substitute (class Substitution&) { return copy (); } /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression */ void compile (class CExpression&, unsigned, const char*, const class VariableSet*) const { assert (false); } /** Generate C code for evaluating a multi-set expression as a scalar * @param cexpr the compilation * @param indent indentation level * @param result scalar to assign the multi-set to (must be singleton) * @param vars the variables that have been assigned a value * @param check flag: check for result overflow */ void compileScalarMset (class CExpression& cexpr, unsigned indent, const char* result, const class VariableSet* vars, bool check) const; /** Generate C code for evaluating the multi-set expression * @param cexpr the compilation * @param indent indentation level * @param resulttype type of result (optional typecast qualifier) * @param result multi-set to add items to * @param vars the variables that have been assigned a value */ void compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const; /** Get the name of the compiled multi-set * @param cexpr the compilation * @return C expression referring to the multi-set */ char* getName (const class CExpression& cexpr) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The place */ const class Place& myPlace; }; #endif // PLACECONTENTS_H_ maria-1.3.5/Expression/Quantifier.C0000644000175000017500000000742007643235732017347 0ustar msmakelamsmakela// Quantifier expression -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Quantifier.h" #include "Expression.h" #include "VariableDefinition.h" #include "LeafValue.h" /** @file Quantifier.C * Quantifier variables */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Quantifier::Quantifier (char* name, const class Type& type, class Expression* condition) : myVariable (new class VariableDefinition (name, type, true)), myCondition (condition) { assert (!condition || condition->getType ()->getKind () == Type::tBool); } Quantifier::Quantifier (class VariableDefinition& variable, class Expression* condition) : myVariable (&variable), myCondition (condition) { assert (!condition || condition->getType ()->getKind () == Type::tBool); } Quantifier::~Quantifier () { myCondition->destroy (); delete myVariable; } enum Quantifier::Result Quantifier::isAcceptable (const class Valuation& valuation) const { if (myCondition) { if (class Value* v = myCondition->eval (valuation)) { assert (v->getType ().getKind () == Type::tBool); enum Result result = bool (static_cast(*v)) ? pass : fail; delete v; return result; } else return undefined; } return pass; } QuantifierList::QuantifierList () : myList () { } QuantifierList::~QuantifierList () { for (iterator i = begin (); i != end (); i++) delete *i; } enum Quantifier::Result QuantifierList::augment (class Valuation& valuation) const { bool skipFirst = false; for (const_iterator i = begin (); i != end (); i++) { valuation.setValue ((*i)->getVariable (), (*i)->getVariable ().getType ().getFirstValue ()); switch ((*i)->isAcceptable (valuation)) { case Quantifier::pass: break; case Quantifier::fail: skipFirst = true; break; case Quantifier::undefined: return Quantifier::undefined; } } return skipFirst ? Quantifier::fail : Quantifier::pass; } enum Quantifier::Result QuantifierList::advance (class Valuation& valuation) const { next: for (const_iterator i = begin (); i != end (); i++) { bool noWrap = valuation.increment ((*i)->getVariable ()); switch ((*i)->isAcceptable (valuation)) { case Quantifier::pass: if (!noWrap) continue; else { const_iterator j = i; while (++j != end ()) { switch ((*j)->isAcceptable (valuation)) { case Quantifier::fail: goto next; case Quantifier::pass: continue; case Quantifier::undefined: return Quantifier::undefined; } } return Quantifier::pass; } case Quantifier::fail: if (noWrap) goto next; return Quantifier::fail; case Quantifier::undefined: return Quantifier::undefined; } } return Quantifier::fail; } void QuantifierList::clear (class Valuation& valuation) const { for (const_iterator i = begin (); i != end (); i++) if (!valuation.undefine ((*i)->getVariable ())) break; } maria-1.3.5/Expression/Quantifier.h0000644000175000017500000001331310232531535017376 0ustar msmakelamsmakela// Quantifier expression -*- c++ -*- #ifndef QUANTIFIER_H_ # define QUANTIFIER_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include # include /** @file Quantifier.h * Quantifier variables */ /* Copyright © 1998-2002,2005 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Quantifier variable */ class Quantifier { public: /** Result of a check */ enum Result { undefined, pass, fail }; /** Constructor * @param name variable name * @param type variable type * @param condition optional condition for the quantifier */ Quantifier (char* name, const class Type& type, class Expression* condition); /** Constructor * @param variable variable * @param condition optional condition for the quantifier */ Quantifier (class VariableDefinition& variable, class Expression* condition); private: /** Copy constructor */ Quantifier (const class Quantifier& old); /** Assignment operator */ class Quantifier& operator= (const class Quantifier& old); public: /** Destructor */ ~Quantifier (); /** Determine the variable */ const class VariableDefinition& getVariable () const { return *myVariable; } /** Determine the condition expression */ const class Expression* getCondition () const { return myCondition; } /** Set the condition expression */ void setCondition (class Expression& condition) { assert (!myCondition); myCondition = &condition; } /** Determine whether the given valuation is accepted by submarking criteria * @param valuation Valuation to be checked * @return (@see Result) */ enum Result isAcceptable (const class Valuation& valuation) const; /** Equality comparison operator */ bool operator== (const class Quantifier& other) const { return myVariable == other.myVariable && *myCondition == *other.myCondition; } /** Ordering comparison operator */ bool operator< (const class Quantifier& other) const { if (myVariable < other.myVariable) return true; if (other.myVariable < myVariable) return false; return *myCondition < *other.myCondition; } private: /** Variable */ class VariableDefinition* myVariable; /** Quantifier condition */ class Expression* myCondition; }; /** Quantifier variable list */ class QuantifierList { public: /** List of quantifier variables */ typedef std::list List; /** Iterator to the quantifier list */ typedef List::iterator iterator; /** Constant iterator to the quantifier list */ typedef List::const_iterator const_iterator; /** Constructor */ QuantifierList (); private: /** Copy constructor */ QuantifierList (const QuantifierList& old); /** Assignment operator */ class QuantifierList& operator= (const class QuantifierList& old); public: /** Destructor */ ~QuantifierList (); /** Prepend a quantifier to the list * @param quantifier quantifier to be prepended */ void prepend (class Quantifier& quantifier) { myList.push_front (&quantifier); } /** Append a quantifier to the list * @param quantifier quantifier to be appended */ void append (class Quantifier& quantifier) { myList.insert (end (), &quantifier); } /** @name Accessors to the quantifier list */ /*@{*/ bool empty () const { return myList.empty (); } size_t size () const { return myList.size (); } const_iterator begin () const { return myList.begin (); } const_iterator end () const { return myList.end (); } iterator begin () { return myList.begin (); } iterator end () { return myList.end (); } /*@}*/ /** Equality comparison operator */ bool operator== (const class QuantifierList& other) const { if (size () != other.size ()) return false; for (const_iterator i = begin (), j = other.begin (); i != end (); i++, j++) if (!(**i == **j)) return false; return true; } /** Ordering comparison operator */ bool operator< (const class QuantifierList& other) const { if (size () < other.size ()) return true; if (other.size () < size ()) return false; for (const_iterator i = begin (), j = other.begin (); i != end (); i++, j++) if (**i < **j) return true; else if (**j < **i) return false; return false; } /** Augment a valuation with the first values of the quantifiers * @param valuation valuation to be augmented * @return pass, fail (invalid valuation) or undefined (error) */ enum Quantifier::Result augment (class Valuation& valuation) const; /** Step to the next values of the quantifiers * @return pass, fail (wrapped) or undefined (error) */ enum Quantifier::Result advance (class Valuation& valuation) const; /** Clear a valuation from assignments to the quantifiers * @param valuation valuation to be cleared */ void clear (class Valuation& valuation) const; private: /** The list of quantifiers */ List myList; }; #endif // QUANTIFIER_H_ maria-1.3.5/Expression/RelopExpression.C0000644000175000017500000002704707722340370020401 0ustar msmakelamsmakela// relation operator class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "RelopExpression.h" #include "Net.h" #include "BoolType.h" #include "LeafValue.h" #include "Constant.h" #include "Printer.h" /** @file RelopExpression.C * Comparison operations */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ RelopExpression::RelopExpression (bool equal, class Expression& left, class Expression& right) : Expression (), myEqual (equal), myLeft (&left), myRight (&right) { setType (Net::getBoolType ()); assert (myLeft->getType () == myRight->getType ()); assert (myEqual || (myLeft->getType ()->isOrdered () && myRight->getType ()->isOrdered ())); assert (myLeft->isBasic () && myRight->isBasic ()); } RelopExpression::~RelopExpression () { myLeft->destroy (); myRight->destroy (); } class Expression* RelopExpression::construct (bool equal, class Expression& left, class Expression& right) { if ((left == right || (left.getType () == right.getType () && left.getType () && left.getType ()->getNumValues () == 1)) && (left.getKind () == Expression::eConstant || left.getKind () == Expression::eVariable) && (right.getKind () == Expression::eConstant || right.getKind () == Expression::eVariable)) { left.destroy (); right.destroy (); return (new class Constant (*new class LeafValue (Net::getBoolType (), equal)))->cse (); } return (new class RelopExpression (equal, left, right))->cse (); } class Value* RelopExpression::do_eval (const class Valuation& valuation) const { class Value* left = myLeft->eval (valuation); if (!left) return NULL; class Value* right = myRight->eval (valuation); if (!right) { delete left; return NULL; } bool result = myEqual ? *left == *right : *left < *right; delete left; delete right; return constrain (valuation, new class LeafValue (*getType (), result)); } class Expression* RelopExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* left = myLeft->ground (valuation, transition, declare); if (!left) return NULL; class Expression* right = myRight->ground (valuation, transition, declare); if (!right) { left->destroy (); return NULL; } assert (valuation.isOK ()); if (left == myLeft && right == myRight) { left->destroy (); right->destroy (); return copy (); } else return construct (myEqual, *left, *right)->ground (valuation); } class Expression* RelopExpression::substitute (class Substitution& substitution) { class Expression* left = myLeft->substitute (substitution); class Expression* right = myRight->substitute (substitution); if (left == myLeft && right == myRight) { left->destroy (); right->destroy (); return copy (); } else { class Expression* expr = construct (myEqual, *left, *right); expr->setType (*getType ()); return expr; } } bool RelopExpression::depends (const class VariableSet& vars, bool complement) const { return myLeft->depends (vars, complement) || myRight->depends (vars, complement); } bool RelopExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myLeft->forExpressions (operation, data) && myRight->forExpressions (operation, data); } class Expression* RelopExpression::disqualify (const class Transition& transition) { class Expression* left = myLeft->disqualify (transition); class Expression* right = myRight->disqualify (transition); if (left == myLeft && right == myRight) { left->destroy (), right->destroy (); return copy (); } if (!left || !right) { left->destroy (), right->destroy (); return 0; } class Expression* expr = construct (myEqual, *left, *right); class Valuation valuation; if (class Value* v = expr->eval (valuation)) { expr->destroy (); return (new class Constant (*v))->cse (); } else return expr; } #ifdef EXPR_COMPILE # include "CExpression.h" /** Compile a comparison against a constant * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value * @param valuation the valuation * @param out the output stream * @param expr the expression * @param value the value being compared against * @param right flag: is the constant on the right-hand-side * @param equal flag: equality comparison (instead of less-than) */ inline static void compileComparison (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars, class StringBuffer& out, const class Expression& expr, const class Value& value, bool right, bool equal) { char* var = 0; if (cexpr.getVariable (expr, var)) expr.compile (cexpr, indent, var, vars); if (indent) out.indent (indent); if (lvalue) out.append (lvalue), out.append ("="); if (equal) value.compileEqual (out, indent, var, true, true, true); else value.compileOrder (out, indent, var, right, false, true, true); delete[] var; out.append (";\n"); } void RelopExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { class StringBuffer& out = cexpr.getOut (); if (myLeft->getKind () == Expression::eConstant) ::compileComparison (cexpr, indent, lvalue, vars, out, *myRight, static_cast (myLeft)->getValue (), false, myEqual); else if (myRight->getKind () == Expression::eConstant) ::compileComparison (cexpr, indent, lvalue, vars, out, *myLeft, static_cast (myRight)->getValue (), true, myEqual); else { char* left; char* right; if (cexpr.getVariable (*myLeft, left)) myLeft->compile (cexpr, indent, left, vars); if (cexpr.getVariable (*myRight, right)) myRight->compile (cexpr, indent, right, vars); if (myLeft->getType ()->getNumValues () == 1) { out.indent (indent); out.append (lvalue); out.append (myEqual ? "=1;\n" : "=0;\n"); } else if (myEqual) { out.indent (indent); out.append (lvalue); out.append ("="); if (!myLeft->getType ()->compileEqual (out, indent + strlen (lvalue) + 1, left, right, true, true, true, false)) out.append ("1"); out.append (";\n"); } else if (myLeft->getType ()->isLeaf ()) { out.indent (indent); out.append (lvalue); out.append ("="); out.append (left); out.append ("<"); out.append (right); out.append (";\n"); } else { out.append ("#define CMP(l,r,L,G)"); myLeft->getType ()->compileCompare3 (out); out.append ("\n"); out.indent (indent); out.append ("CMP ("); out.append (left); out.append (", "); out.append (right); char* less = cexpr.getLabel (); char* greater = cexpr.getLabel (); char* done = cexpr.getLabel (); out.append (", goto "), out.append (less); out.append (", goto "), out.append (greater); out.append (");\n#undef CMP\n"); out.indent (indent); out.append ("goto "); out.append (greater); out.append (";\n"); out.indent (indent - 2); out.append (less); out.append (":\n"); out.indent (indent); out.append (lvalue), out.append ("=1;\n"); out.indent (indent); out.append ("goto "), out.append (done); out.append (";\n"); out.indent (indent - 2); out.append (greater); out.append (":\n"); out.indent (indent); out.append (lvalue), out.append ("=0;\n"); out.indent (indent - 2); out.append (done); out.append (":\n"); delete[] less; delete[] greater; delete[] done; } delete[] left; delete[] right; } compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eUndefined: case Expression::eStruct: case Expression::eStructComponent: case Expression::eUnion: case Expression::eUnionComponent: case Expression::eUnionType: case Expression::eVector: case Expression::eVectorIndex: case Expression::eUnop: case Expression::eNot: case Expression::eBuffer: case Expression::eBufferUnop: case Expression::eBufferIndex: case Expression::eSet: case Expression::eTypecast: return false; case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: assert (false); case Expression::eBinop: case Expression::eBooleanBinop: case Expression::eRelop: case Expression::eIfThenElse: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eCardinality: case Expression::eBufferWrite: case Expression::eBufferRemove: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: break; } return true; } void RelopExpression::display (const class Printer& printer) const { const char* cast = myLeft->getType ()->getName (); switch (myLeft->getType ()->getKind ()) { case Type::tBool: case Type::tChar: case Type::tInt: case Type::tCard: cast = 0; default: break; } if (cast && myLeft->getKind () != Expression::eVariable && (myLeft->getKind () != Expression::eConstant || myLeft->getType ()->getKind () == Type::tEnum)) { printer.printRaw ("is"); printer.delimiter (' '); printer.print (cast); printer.delimiter (' '); } if (::needParentheses (myLeft->getKind ())) { printer.delimiter ('(')++; myLeft->display (printer); --printer.delimiter (')'); } else myLeft->display (printer); printer.printRaw (myEqual ? "==" : "<"); if (cast && myRight->getKind () != Expression::eVariable && (myRight->getKind () != Expression::eConstant || myRight->getType ()->getKind () == Type::tEnum)) { if (const char* rcast = myRight->getType ()->getName ()) cast = rcast; printer.printRaw ("is"); printer.delimiter (' '); printer.print (cast); printer.delimiter (' '); } if (::needParentheses (myRight->getKind ())) { printer.delimiter ('(')++; myRight->display (printer); --printer.delimiter (')'); } else myRight->display (printer); } maria-1.3.5/Expression/RelopExpression.h0000644000175000017500000001264307722340370020442 0ustar msmakelamsmakela// relation operator class -*- c++ -*- #ifndef RELOPEXPRESSION_H_ # define RELOPEXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file RelopExpression.h * Comparison operations */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Comparison operator */ class RelopExpression : public Expression { protected: /** Constructor * @param equal Flag: equality comparison instead of less-than * @param left Left-hand expression of the operator * @param right Right-hand expression of the operator */ RelopExpression (bool equal, class Expression& left, class Expression& right); private: /** Copy constructor */ RelopExpression (const class RelopExpression& old); /** Assignment operator */ class RelopExpression& operator= (const class RelopExpression& old); protected: /** Destructor */ ~RelopExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eRelop; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Construct a RelopExpression, optimizing if possible * @param equal Flag: equality comparison instead of less-than * @param left Left-hand expression of the operator * @param right Right-hand expression of the operator * @return a corresponding expression */ static class Expression* construct (bool equal, class Expression& left, class Expression& right); /** Equality comparison operator */ bool operator== (const class RelopExpression& other) const { return myEqual == other.myEqual && *myLeft == *other.myLeft && *myRight == *other.myRight; } /** Ordering comparison operator */ bool operator< (const class RelopExpression& other) const { if (myEqual < other.myEqual) return true; if (other.myEqual < myEqual) return false; if (*myLeft < *other.myLeft) return true; if (*other.myLeft < *myLeft) return false; return *myRight < *other.myRight; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Remove transition qualifiers from the expression * @param transition the transition for which the expression is qualified * @return the expession without qualifiers, or NULL */ class Expression* disqualify (const class Transition& transition); # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** Flag: equality comparison instead of less-than */ bool myEqual; /** Left-hand expression */ class Expression* myLeft; /** Right-hand expression */ class Expression* myRight; }; #endif // RELOPEXPRESSION_H_ maria-1.3.5/Expression/SetExpression.C0000644000175000017500000002541607722340370020051 0ustar msmakelamsmakela// set expression class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "SetExpression.h" #include "Net.h" #include "Constant.h" #include "EmptySet.h" #include "BoolType.h" #include "LeafValue.h" #include "PlaceMarking.h" #include "Printer.h" /** @file SetExpression.C * Basic operations on multi-sets */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ SetExpression::SetExpression (enum Op op, class Expression& left, class Expression& right) : Expression (), myOp (op), myLeft (&left), myRight (&right) { assert (myLeft->getType () || myRight->getType ()); assert (!myLeft->getType () || !myRight->getType () || myLeft->getType () == myRight->getType ()); assert (!myLeft->isTemporal () && !myRight->isTemporal ()); // the following assertions should be guaranteed by construct () assert (!myRight->getKind () != eEmptySet); assert (myLeft->getKind () != eEmptySet || myOp == sEquals); switch (myOp) { case sSubset: case sEquals: setType (Net::getBoolType ()); break; case sIntersection: case sMinus: case sUnion: setType (*myLeft->getType ()); break; } } SetExpression::~SetExpression () { myLeft->destroy (); myRight->destroy (); } class Expression* SetExpression::construct (enum Op op, class Expression& left, class Expression& right) { if (left == right) { switch (op) { case sSubset: case sEquals: True: right.destroy (); left.destroy (); return (new class Constant (*new class LeafValue (Net::getBoolType (), true)))->cse (); case sMinus: right.destroy (); left.destroy (); return (new class EmptySet ())->cse (); break; case sIntersection: case sUnion: right.destroy (); return &left; } } else if (left.getKind () == eEmptySet) { switch (op) { case sSubset: goto True; case sEquals: return (new class SetExpression (op, left, right))->cse (); case sMinus: case sIntersection: right.destroy (); return &left; case sUnion: left.destroy (); return &right; } } else if (right.getKind () == eEmptySet) { switch (op) { case sSubset: case sEquals: return (new class SetExpression (sEquals, right, left))->cse (); case sMinus: right.destroy (); return &left; case sIntersection: case sUnion: left.destroy (); return &right; } } else { switch (op) { case sEquals: case sIntersection: case sUnion: if (right < left) // transform the expression to canonical form return (new class SetExpression (op, right, left))->cse (); // fall through case sMinus: case sSubset: return (new class SetExpression (op, left, right))->cse (); } } assert (false); return NULL; } class Value* SetExpression::do_eval (const class Valuation& valuation) const { class PlaceMarking* l = myLeft->meval (valuation); if (!l) return NULL; class PlaceMarking* r = myRight->meval (valuation); if (!r) { delete l; return NULL; } bool result; switch (myOp) { case sSubset: result = *l <= *r; break; case sEquals: result = *l == *r; break; default: assert (false); return NULL; } delete l; delete r; return constrain (valuation, new class LeafValue (*getType (), result)); } class PlaceMarking* SetExpression::meval (const class Valuation& valuation) const { class PlaceMarking* l = myLeft->meval (valuation); if (!l) return NULL; class PlaceMarking* r = myRight->meval (valuation); if (!r) { delete l; return NULL; } switch (myOp) { case sIntersection: if (l->size () < r->size ()) { class PlaceMarking* p = r; r = l; l = p; } *l &= *r; break; case sMinus: *l -= *r; break; case sUnion: if (l->size () < r->size ()) { class PlaceMarking* p = r; r = l; l = p; } if (!l->add (*r, 1)) { valuation.flag (errCard, *this); delete l; delete r; return NULL; } break; default: assert (false); return NULL; } delete r; l->setPlace (NULL); return l; } class Expression* SetExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* left = myLeft->ground (valuation, transition, declare); if (!left) return NULL; class Expression* right = myRight->ground (valuation, transition, declare); if (!right) { left->destroy (); return NULL; } assert (valuation.isOK ()); if (left == myLeft && right == myRight) { left->destroy (); right->destroy (); return copy (); } else return static_cast (new class SetExpression (myOp, *left, *right))->ground (valuation); } class Expression* SetExpression::substitute (class Substitution& substitution) { class Expression* left = myLeft->substitute (substitution); class Expression* right = myRight->substitute (substitution); if (left == myLeft && right == myRight) { left->destroy (); right->destroy (); return copy (); } else return (new class SetExpression (myOp, *left, *right))->cse (); } bool SetExpression::depends (const class VariableSet& vars, bool complement) const { return myLeft->depends (vars, complement) || myRight->depends (vars, complement); } bool SetExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myLeft->forExpressions (operation, data) && myRight->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" void SetExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { assert (myOp == sSubset || myOp == sEquals); char* left; char* right; class StringBuffer& out = cexpr.getOut (); if (cexpr.getVariable (*myLeft, left)) myLeft->compileMset (cexpr, indent, 0, left, vars); if (cexpr.getVariable (*myRight, right)) myRight->compileMset (cexpr, indent, 0, right, vars); out.indent (indent); out.append (lvalue); out.append ("="); if (myLeft->getKind () == eEmptySet) { assert (myOp == sEquals); out.append ("!nonempty ("); out.append (right); out.append (");\n"); } else { out.append (myOp == sSubset ? "subset" : "equal"); const class Type* type = myLeft->getType (); if (!type) type = myRight->getType (); type->appendIndex (out); out.append (" ("); out.append (left); out.append (", "); out.append (right); out.append (");\n"); } delete[] left; delete[] right; compileConstraint (cexpr, indent, lvalue); } void SetExpression::compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const { myLeft->compileMset (cexpr, indent, resulttype, result, vars); if (myOp == sUnion) myRight->compileMset (cexpr, indent, resulttype, result, vars); else { assert (myOp == sIntersection || myOp == sMinus); char* right; class StringBuffer& out = cexpr.getOut (); if (cexpr.getVariable (*myRight, right)) myRight->compileMset (cexpr, indent, 0, right, vars); out.indent (indent); out.append (myOp == sIntersection ? "intersect" : "subtract"); getType ()->appendIndex (out); out.append (" ("); if (resulttype) out.append (resulttype); out.append (result); out.append (", "); out.append (right); out.append (");\n"); delete[] right; } } #endif // EXPR_COMPILE /** Determine whether an expression requires a type cast * @param kind kind of the expression * @return true or false, according to whether a cast is required */ inline static bool needsCast (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eUnionType: case Expression::eVectorIndex: case Expression::eUnop: case Expression::eBinop: case Expression::eBooleanBinop: case Expression::eNot: case Expression::eRelop: case Expression::eBufferIndex: case Expression::eSet: case Expression::eIfThenElse: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eTypecast: case Expression::eCardinality: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: return false; default: return true; } } /** Convert an operator to a string * @param op the operator to convert * @return a string corresponding to the operator */ inline static const char* getOpString (enum SetExpression::Op op) { switch (op) { case SetExpression::sSubset: return "subset"; case SetExpression::sEquals: return "equals"; case SetExpression::sIntersection: return "intersect"; case SetExpression::sMinus: return "minus"; case SetExpression::sUnion: return "union"; } return "???"; } void SetExpression::display (const class Printer& printer) const { const class Type* type = myLeft->getType (); if (!type) type = myRight->getType (); const char* cast = type ? type->getName () : 0; if (cast) { switch (type->getKind ()) { case Type::tBool: case Type::tChar: case Type::tInt: case Type::tCard: cast = 0; default: break; } } printer.delimiter ('(')++; if (cast && ::needsCast (myLeft->getKind ())) { printer.printRaw ("is"); printer.delimiter (' '); printer.print (cast); printer.delimiter (' '); } myLeft->display (printer); --printer.delimiter (')'); printer.printRaw (::getOpString (myOp)); printer.delimiter ('(')++; if (cast && ::needsCast (myRight->getKind ())) { printer.printRaw ("is"); printer.delimiter (' '); printer.print (cast); printer.delimiter (' '); } myRight->display (printer); --printer.delimiter (')'); } maria-1.3.5/Expression/SetExpression.h0000644000175000017500000001424507722340370020114 0ustar msmakelamsmakela// set expression class -*- c++ -*- #ifndef SETEXPRESSION_H_ # define SETEXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file SetExpression.h * Basic operations on multi-sets */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Set expression */ class SetExpression : public Expression { public: /** Set operator */ enum Op { sSubset, sEquals, sIntersection, sMinus, sUnion }; protected: /** Constructor * @param op Operator * @param left Left-hand expression of the operator * @param right Right-hand expression of the operator */ SetExpression (enum Op op, class Expression& left, class Expression& right); private: /** Copy constructor */ SetExpression (const class SetExpression& old); /** Assignment operator */ class SetExpression& operator= (const class SetExpression& old); protected: /** Destructor */ ~SetExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eSet; } /** Determine whether this is a basic expression */ bool isBasic () const { return !isSet (); } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** * Determine whether this is a multiset-valued expression * @return true if this is a multiset-valued expression */ bool isSet () const { switch (myOp) { case sSubset: case sEquals: break; case sIntersection: case sMinus: case sUnion: return true; } return false; } /** Construct a SetExpression, reducing to EmptySet or Constant if possible * @param op Operator * @param left Left-hand expression of the operator * @param right Right-hand expression of the operator * @return a corresponding expression */ static class Expression* construct (enum Op op, class Expression& left, class Expression& right); /** Equality comparison operator */ bool operator== (const class SetExpression& other) const { return myOp == other.myOp && *myLeft == *other.myLeft && *myRight == *other.myRight; } /** Ordering comparison operator */ bool operator< (const class SetExpression& other) const { if (myOp < other.myOp) return true; if (other.myOp < myOp) return false; if (*myLeft < *other.myLeft) return true; if (*other.myLeft < *myLeft) return false; return *myRight < *other.myRight; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Evaluate the multiset expression * @param valuation variable substitutions and the global marking * @return the filtered marking */ class PlaceMarking* meval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; /** Generate C code for evaluating the multi-set expression * @param cexpr the compilation * @param indent indentation level * @param resulttype type of result (optional typecast qualifier) * @param result multi-set to add items to * @param vars the variables that have been assigned a value * @return the compiled multi-set expression */ void compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The operator */ enum Op myOp; /** Left-hand expression */ class Expression* myLeft; /** Right-hand expression */ class Expression* myRight; }; #endif // SETEXPRESSION_H_ maria-1.3.5/Expression/StructAssign.C0000644000175000017500000001105507722340370017661 0ustar msmakelamsmakela// Maria structure assignment class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "StructAssign.h" #include "StructType.h" #include "StructValue.h" #include "Printer.h" /** @file StructAssign.C * Structure component assignment operation */ /* Copyright © 2001-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ StructAssign::StructAssign (class Expression& structure, card_t i, class Expression& expr) : Expression (), myStructure (structure), myIndex (i), myExpr (expr) { assert (myStructure.getType () && myStructure.getType ()->getKind () == Type::tStruct); assert (myStructure.isBasic () && myExpr.isBasic ()); assert (i < static_cast (myStructure.getType ())->getSize ()); setType (*structure.getType ()); } StructAssign::~StructAssign () { myStructure.destroy (); myExpr.destroy (); } class Value* StructAssign::do_eval (const class Valuation& valuation) const { class Value* v = myStructure.eval (valuation); if (!v) return NULL; assert (v->getKind () == Value::vStruct); class Value*& w = static_cast(*v)[myIndex]; delete w; if (!(w = myExpr.eval (valuation))) { delete v; return NULL; } return constrain (valuation, v); } class Expression* StructAssign::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* structure = myStructure.ground (valuation, transition, declare); if (!structure) return NULL; assert (valuation.isOK ()); class Expression* expr = myExpr.ground (valuation, transition, declare); if (!expr) { structure->destroy (); return NULL; } if (structure == &myStructure && expr == &myExpr) { structure->destroy (), expr->destroy (); return copy (); } else return static_cast (new class StructAssign (*structure, myIndex, *expr))->ground (valuation); } class Expression* StructAssign::substitute (class Substitution& substitution) { class Expression* structure = myStructure.substitute (substitution); class Expression* expr = myExpr.substitute (substitution); if (structure == &myStructure && expr == &myExpr) { structure->destroy (), expr->destroy (); return copy (); } else return (new class StructAssign (*structure, myIndex, *expr))->cse (); } bool StructAssign::depends (const class VariableSet& vars, bool complement) const { return myStructure.depends (vars, complement) || myExpr.depends (vars, complement); } bool StructAssign::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myStructure.forExpressions (operation, data) && myExpr.forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" # include # include void StructAssign::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { size_t len = strlen (lvalue); char* rvalue = new char[len + 23]; memcpy (rvalue, lvalue, len); snprintf (rvalue + len, 23, "[%u]", myIndex); myStructure.compile (cexpr, indent, lvalue, vars); myExpr.compile (cexpr, indent, rvalue, vars); delete[] rvalue; compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE void StructAssign::display (const class Printer& printer) const { myStructure.display (printer); printer.delimiter ('.'); printer.delimiter ('{')++; printer.print (static_cast(myStructure.getType ()) ->getComponentName (myIndex)); printer.delimiter (' '); myExpr.display (printer); --printer.delimiter ('}'); } maria-1.3.5/Expression/StructAssign.h0000644000175000017500000001141107722340370017722 0ustar msmakelamsmakela// Maria structure assignment class -*- c++ -*- #ifndef STRUCTASSIGN_H_ # define STRUCTASSIGN_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file StructAssign.h * Structure component assignment operation */ /* Copyright © 2001-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Structure component assignment */ class StructAssign : public Expression { public: /** Constructor * @param structure the structure * @param i index of the component to be assigned to * @param expr the value to assign to the struct component */ StructAssign (class Expression& structure, card_t i, class Expression& expr); private: /** Copy constructor */ StructAssign (const class StructAssign& old); /** Assignment operator */ class StructAssign& operator= (const class StructAssign& old); protected: /** Destructor */ ~StructAssign (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eStructAssign; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class StructAssign& other) const { return myIndex == other.myIndex && myStructure == other.myStructure && myExpr == other.myExpr; } /** Ordering comparison operator */ bool operator< (const class StructAssign& other) const { if (myIndex < other.myIndex) return true; if (other.myIndex < myIndex) return false; if (myStructure < other.myStructure) return true; if (other.myStructure < myStructure) return false; return myExpr < other.myExpr; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The structure */ class Expression& myStructure; /** Index of the component to be assigned to */ card_t myIndex; /** The replacement for the component */ class Expression& myExpr; }; #endif // STRUCTASSIGN_H_ maria-1.3.5/Expression/StructComponent.C0000644000175000017500000001267607722340370020411 0ustar msmakelamsmakela// Maria structure component reference expression class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "StructComponent.h" #include "StructType.h" #include "StructValue.h" #include "Printer.h" /** @file StructComponent.C * Structure component reference */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ StructComponent::StructComponent (class Expression& structure, card_t i) : myStructure (&structure), myIndex (i) { assert (myStructure && myStructure->getType ()->getKind () == Type::tStruct); const class StructType* type = static_cast(myStructure->getType ()); assert (myStructure->isBasic ()); setType ((*type)[myIndex]); } StructComponent::~StructComponent () { myStructure->destroy (); } class Value* StructComponent::do_eval (const class Valuation& valuation) const { class Value* v = myStructure->eval (valuation); if (!v) return NULL; assert (v->getKind () == Value::vStruct); class Value* u = NULL; if (const class Value* w = (*static_cast(v))[myIndex]) u = w->copy (); delete v; return u; } class Expression* StructComponent::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* structure = myStructure->ground (valuation, transition, declare); if (!structure) return NULL; assert (valuation.isOK ()); if (structure == myStructure) { structure->destroy (); return copy (); } else return static_cast (new class StructComponent (*structure, myIndex))->ground (valuation); } class Expression* StructComponent::substitute (class Substitution& substitution) { class Expression* structure = myStructure->substitute (substitution); if (structure == myStructure) { structure->destroy (); return copy (); } else return (new class StructComponent (*structure, myIndex))->cse (); } bool StructComponent::depends (const class VariableSet& vars, bool complement) const { return myStructure->depends (vars, complement); } bool StructComponent::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myStructure->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" void StructComponent::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { char* rvalue = 0; class StringBuffer& out = cexpr.getOut (); if (cexpr.getVariable (*myStructure, rvalue)) myStructure->compile (cexpr, indent, rvalue, vars); out.indent (indent); out.append (lvalue); out.append ("="); out.append (rvalue); out.append (".s"); out.append (myIndex); out.append (";\n"); delete[] rvalue; } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eVectorIndex: return false; case Expression::eCardinality: case Expression::eUnionType: case Expression::eUnion: case Expression::eVector: case Expression::eBinop: case Expression::eBooleanBinop: case Expression::eNot: case Expression::eRelop: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: case Expression::eVectorAssign: case Expression::eVectorShift: assert (false); case Expression::eUnop: case Expression::eConstant: case Expression::eStruct: case Expression::eStructAssign: case Expression::eIfThenElse: case Expression::eBufferUnop: case Expression::eTypecast: break; } return true; } void StructComponent::display (const class Printer& printer) const { if (::needParentheses (myStructure->getKind ())) { printer.delimiter ('(')++; myStructure->display (printer); --printer.delimiter (')'); } else myStructure->display (printer); printer.delimiter ('.'); printer.print (static_cast(myStructure->getType ()) ->getComponentName (myIndex)); } maria-1.3.5/Expression/StructComponent.h0000644000175000017500000001115007722340370020440 0ustar msmakelamsmakela// Maria structure component reference expression class -*- c++ -*- #ifndef STRUCTCOMPONENT_H_ # define STRUCTCOMPONENT_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include "typedefs.h" /** @file StructComponent.h * Structure component reference */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Structure component reference expression */ class StructComponent : public Expression { public: /** Constructor * @param structure Expression evaluating to the structure * @param i Index of the referenced structure component */ StructComponent (class Expression& structure, card_t i); private: /** Copy constructor */ StructComponent (const class StructComponent& old); /** Assignment operator */ class StructComponent& operator= (const class StructComponent& old); protected: /** Destructor */ ~StructComponent (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eStructComponent; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class StructComponent& other) const { return myIndex == other.myIndex && *myStructure == *other.myStructure; } /** Ordering comparison operator */ bool operator< (const class StructComponent& other) const { if (myIndex < other.myIndex) return true; if (other.myIndex < myIndex) return false; return *myStructure < *other.myStructure; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The structure being referenced */ class Expression* myStructure; /** Index of the referenced structure component */ card_t myIndex; }; #endif // STRUCTCOMPONENT_H_ maria-1.3.5/Expression/StructExpression.C0000644000175000017500000001664307722340370020604 0ustar msmakelamsmakela// Maria structure (or array) expression class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "StructExpression.h" #include "StructType.h" #include "StructValue.h" #include "Printer.h" /** @file StructExpression.C * Structure constructor */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ StructExpression::StructExpression (const class Type& type) : Expression (), myComponents () { assert (type.getKind () == Type::tStruct); Expression::setType (type); } StructExpression::~StructExpression () { for (iterator i = begin (); i != end (); i++) (*i)->destroy (); } void StructExpression::setType (const class Type& type) { Expression::setType (type); assert (type.getKind () == Type::tStruct); const class StructType& t = static_cast(type); assert (t.getSize () == size ()); card_t i; const_iterator j; for (i = 0, j = begin (); i < t.getSize (); i++, j++) (*j)->setType (t[i]); } void StructExpression::append (class Expression& expr) { assert (expr.isBasic ()); expr.setType (*getNextType ()); myComponents.insert (end (), &expr); } const class Type* StructExpression::getNextType () const { assert (getType () && getType ()->getKind () == Type::tStruct); const class StructType* type = static_cast(getType ()); assert (size () <= type->getSize ()); if (size () == type->getSize ()) return NULL; else return &(*type)[size ()]; } class Value* StructExpression::do_eval (const class Valuation& valuation) const { class StructValue* value = new class StructValue (*getType ()); const_iterator i; card_t j; for (i = begin (), j = 0; i != end (); i++, j++) { if (class Value* v = (*i)->eval (valuation)) (*value)[j] = v; else { delete value; return NULL; } } return constrain (valuation, value); } class Expression* StructExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { bool same = true; class StructExpression* expr = new class StructExpression (*getType ()); for (iterator i = begin (); i != end (); i++) { class Expression* e = (*i)->ground (valuation, transition, declare); if (!e) { expr->destroy (); return NULL; } assert (valuation.isOK ()); if (e != *i) same = false; expr->append (*e); } if (same) { expr->destroy (); return copy (); } return static_cast(expr)->ground (valuation); } class Expression* StructExpression::substitute (class Substitution& substitution) { bool same = true; class StructExpression* expr = new class StructExpression (*getType ()); for (iterator i = begin (); i != end (); i++) { class Expression* e = (*i)->substitute (substitution); if (e != *i) same = false; expr->append (*e); } if (same) { expr->destroy (); return copy (); } else return expr->cse (); } bool StructExpression::depends (const class VariableSet& vars, bool complement) const { for (const_iterator i = begin (); i != end (); i++) if ((*i)->depends (vars, complement)) return true; return false; } bool StructExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { if (!(*operation) (*this, data)) return false; for (const_iterator i = begin (); i != end (); i++) if (!(*i)->forExpressions (operation, data)) return false; return true; } bool StructExpression::isCompatible (const class Value& value, const class Valuation& valuation) const { assert (value.getKind () == Value::vStruct); assert (value.getType ().getKind () == Type::tStruct); const class StructValue& sv = static_cast(value); if (!sv.getType ().isAssignable (*getType ())) return false; const_iterator i; card_t j; for (i = begin (), j = 0; i != end (); i++, j++) if (!(*i)->isCompatible (sv[j], valuation)) return false; return true; } void StructExpression::getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const { assert (value.getKind () == Value::vStruct); assert (&value.getType () == getType ()); const class StructValue& sv = static_cast(value); const_iterator i; card_t j; for (i = begin (), j = 0; i != end (); i++, j++) (*i)->getLvalues (sv[j], valuation, vars); } void StructExpression::getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const { for (const_iterator i = begin (); i != end (); i++) (*i)->getLvalues (rvalues, lvalues); } #ifdef EXPR_COMPILE # include "CExpression.h" # include void StructExpression::compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const { assert (!!lvalue); const size_t len = strlen (lvalue); char* const newlvalue = new char[len + 23]; char* const suffix = newlvalue + len; memcpy (newlvalue, lvalue, len); card_t idx = 0; for (const_iterator i = begin (); i != end (); i++, idx++) { snprintf (suffix, 23, ".s%u", idx); (*i)->compileLvalue (cexpr, indent, vars, newlvalue); } delete[] newlvalue; } void StructExpression::compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const { const size_t len = strlen (value); char* const val = new char[len + 23]; char* const suffix = val + len; memcpy (val, value, len); card_t idx = 0; for (const_iterator i = begin (); i != end (); i++, idx++) { snprintf (suffix, 23, ".s%u", idx); (*i)->compileCompatible (cexpr, indent, vars, val); } delete[] val; } void StructExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { size_t len = strlen (lvalue); char* const newlvalue = new char[len + 23]; char* const suffix = newlvalue + len; memcpy (newlvalue, lvalue, len); card_t idx = 0; for (const_iterator i = begin (); i != end (); i++) { snprintf (suffix, 23, ".s%u", idx++); (*i)->compile (cexpr, indent, newlvalue, vars); } delete[] newlvalue; compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE void StructExpression::display (const class Printer& printer) const { printer.delimiter ('{')++; for (const_iterator i = begin (); i != end (); ) { (*i)->display (printer); if (++i == end ()) break; printer.delimiter (','); } --printer.delimiter ('}'); } maria-1.3.5/Expression/StructExpression.h0000644000175000017500000001704210232531557020642 0ustar msmakelamsmakela// Maria structure expression class -*- c++ -*- #ifndef STRUCTEXPRESSION_H_ # define STRUCTEXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include /** @file StructExpression.h * Structure constructor */ /* Copyright © 1999-2002,2005 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Structure expression */ class StructExpression : public Expression { public: /** List of the expressions inside the structure */ typedef std::list List; /** Iterator to the expression list */ typedef List::iterator iterator; /** Constant iterator to the expression list */ typedef List::const_iterator const_iterator; /** Constructor * @param type type of the struct */ StructExpression (const class Type& type); private: /** Copy constructor */ StructExpression (const class StructExpression& old); /** Assignment operator */ class StructExpression& operator= (const class StructExpression& old); protected: /** Destructor */ ~StructExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eStruct; } /** Set the type of the expression * @param type Type of the expression */ void setType (const class Type& type); /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Determine the type of the next component affected by append () * @return type of the next component; * NULL if the expression is fully initialized */ const class Type* getNextType () const; /** @name Accessors to the component list */ /*@{*/ bool empty () const { return myComponents.empty (); } size_t size () const { return myComponents.size (); } /*@}*/ /** Equality comparison operator */ bool operator== (const class StructExpression& other) const { if (size () != other.size ()) return false; for (const_iterator i = begin (), j = other.begin (); i != end (); i++, j++) { if (!(**i == **j)) return false; } return true; } /** Ordering comparison operator */ bool operator< (const class StructExpression& other) const { if (size () < other.size ()) return true; if (other.size () < size ()) return false; for (const_iterator i = begin (), j = other.begin (); i != end (); i++, j++) { if (**i < **j) return true; if (**j < **i) return false; } return false; } /** Append an expression to the component list * @param expr expression to be appended */ void append (class Expression& expr); /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Determine whether the expression is compatible with the specified value, * neglecting subexpressions that cannot be evaluated * @param value value the expression will be compared to * @param valuation variable substitutions * @return true if the expression is compatible with the value */ bool isCompatible (const class Value& value, const class Valuation& valuation) const; /** Unify variables from this expression * @param value the value the expression should evaluate to * @param valuation variable substitutions * @param vars the variables to unify */ void getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const; /** Determine which variables could be unified from this expression * @param rvalues variables unified so far * @param lvalues (output) variables that could be unified * @return variables that could be unified */ void getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const; # ifdef EXPR_COMPILE /** Generate lvalue gathering code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables * @param lvalue C expression referring to the value */ void compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const; /** Generate compatibility check code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables that have been unified * @param value C expression referring to the desired value */ void compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const; /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** @name STL accessors */ /*@{*/ const_iterator begin () const { return myComponents.begin (); } const_iterator end () const { return myComponents.end (); } iterator begin () { return myComponents.begin (); } iterator end () { return myComponents.end (); } /*@}*/ /** The struct components */ List myComponents; }; #endif // STRUCTEXPRESSION_H_ maria-1.3.5/Expression/Submarking.C0000644000175000017500000001623507722340370017337 0ustar msmakelamsmakela// Multi-set filter -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Submarking.h" #include "VariableDefinition.h" #include "Valuation.h" #include "PlaceMarking.h" #include "Substitution.h" #include "Variable.h" #include "LeafValue.h" #include "Printer.h" /** @file Submarking.C * Multi-set filter */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Submarking::Submarking (class VariableDefinition& variable, class Expression& marking, class Expression& condition) : myVariable (&variable), myMarking (&marking), myCondition (&condition) { assert (myVariable && myCondition); assert (myMarking && myMarking->getType ()); assert (!myMarking->isTemporal () && myCondition->isBasic ()); assert (myCondition->getKind () != Expression::eConstant); setType (*myMarking->getType ()); } Submarking::~Submarking () { delete myVariable; myMarking->destroy (); myCondition->destroy (); } class PlaceMarking* Submarking::meval (const class Valuation& valuation) const { if (class PlaceMarking* p = myMarking->meval (valuation)) { p->setPlace (NULL); class Valuation v (valuation); for (PlaceMarking::iterator i = p->begin (); i != p->end (); i++) { v.setValue (*myVariable, *PlaceMarking::getValue (i).copy ()); if (class Value* val = myCondition->eval (v)) { assert (val->getKind () == Value::vLeaf); bool pass = bool (static_cast(*val)); delete val; if (!pass) p->remove (i); } else { delete p; valuation.copyErrors (v); return NULL; } } return p; } return NULL; } /** Create a Submarking, substituting the iterator variable * @param variable the old iterator variable * @param marking the marking expression * @param condition the condition expression (iterator substituted) * @return the corresponding Submarking expression */ static class Submarking* newSubmarking (const class VariableDefinition& variable, class Expression& marking, class Expression& condition) { class VariableDefinition& v = *new class VariableDefinition (variable); class Substitution s; s.setExpr (variable, *(new class Variable (v))->cse ()); class Expression* cond = condition.substitute (s); assert (!!cond); condition.destroy (); return static_cast ((new class Submarking (v, marking, *cond))->cse ()); } class Expression* Submarking::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* marking = myMarking->ground (valuation, transition, declare); if (!marking) return NULL; class Expression* condition = myCondition->ground (valuation, transition, declare); if (!condition) { marking->destroy (); return NULL; } assert (valuation.isOK ()); if (marking == myMarking && condition == myCondition) { marking->destroy (); condition->destroy (); return copy (); } else return newSubmarking (*myVariable, *marking, *condition); } class Expression* Submarking::substitute (class Substitution& substitution) { class Expression* marking = myMarking->substitute (substitution); class Expression* condition = myCondition->substitute (substitution); if (!marking || !condition) { marking->destroy (); condition->destroy (); return NULL; } if (marking == myMarking && condition == myCondition) { marking->destroy (); condition->destroy (); return copy (); } else return newSubmarking (*myVariable, *marking, *condition); } bool Submarking::depends (const class VariableSet& vars, bool complement) const { return myMarking->depends (vars, complement) || myCondition->depends (vars, complement); } bool Submarking::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myMarking->forExpressions (operation, data) && myCondition->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" void Submarking::compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const { /** the multi-set iterator */ char* iter = cexpr.getLabel (); /** the multi-set */ char* mset; /** the filtering condition */ char* cond; /** the item iterator */ char* var = cexpr.getIterator (*myVariable); cexpr.getVariable (*myCondition, cond); if (cexpr.getVariable (*myMarking, mset)) myMarking->compileMset (cexpr, indent, 0, mset, vars); class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append (result), out.append ("=copy"), getType ()->appendIndex (out); out.append (" ("); if (resulttype) out.append (resulttype); out.append (result); out.append (", "), out.append (mset), out.append (");\n"); out.indent (indent), out.append ("{\n"); out.indent (indent + 2); getType ()->appendMSetName (out), out.append ("* "), out.append (iter); out.append ("="); if (resulttype) out.append (resulttype); out.append (result), out.append (";\n"); out.indent (indent + 2); out.append ("FIRST ("), out.append (iter), out.append (");\n"); out.indent (indent + 2); out.append ("while ("), out.append (iter), out.append (") {\n"); out.indent (indent + 4); out.append ("if ("), out.append (iter), out.append ("->count) {\n"); out.indent (indent + 6); myVariable->getType ().appendName (out); out.append (" "), out.append (var), out.append ("="); out.append (iter), out.append ("->item;\n"); myCondition->compile (cexpr, indent + 6, cond, vars); out.indent (indent + 6); out.append ("if (!"), out.append (cond), out.append (") "); out.append (iter), out.append ("->count=0;\n"); out.indent (indent + 4), out.append ("}\n"); out.indent (indent + 4); out.append ("NEXT ("), out.append (iter), out.append (");\n"); out.indent (indent + 2), out.append ("}\n"); out.indent (indent), out.append ("}\n"); delete[] var; delete[] cond; delete[] mset; delete[] iter; } #endif // EXPR_COMPILE void Submarking::display (const class Printer& printer) const { printer.printRaw ("subset"); printer.delimiter (' '); printer.print (myVariable->getName ()); printer.delimiter ('{')++; myMarking->display (printer); --printer.delimiter ('}'); printer.delimiter ('(')++; myCondition->display (printer); --printer.delimiter (')'); } maria-1.3.5/Expression/Submarking.h0000644000175000017500000001260207722340370017376 0ustar msmakelamsmakela// Multi-set filter -*- c++ -*- #ifndef SUBMARKING_H_ # define SUBMARKING_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file Submarking.h * Multi-set filter */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Multi-set filter */ class Submarking : public Expression { public: /** Constructor * @param variable a variable that will run through marking * @param marking a multi-set expression * @param condition the criterion for filtering the multiset items */ Submarking (class VariableDefinition& variable, class Expression& marking, class Expression& condition); private: /** Copy constructor */ Submarking (const class Submarking& old); /** Assignment operator */ class Submarking& operator= (const class Submarking& old); protected: /** Destructor */ ~Submarking (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eSubmarking; } /** * Determine whether this is a basic expression containing * no temporal logic or set operations * @return true if this is a basic expression */ bool isBasic () const { return false; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** * Determine whether this is a multiset-valued expression * @return true if this is a multiset-valued expression */ bool isSet () const { return true; } /** Equality comparison operator */ bool operator== (const class Submarking& other) const { return myVariable == other.myVariable && *myMarking == *other.myMarking && *myCondition == *other.myCondition; } /** Ordering comparison operator */ bool operator< (const class Submarking& other) const { if (myVariable < other.myVariable) return true; if (other.myVariable < myVariable) return false; if (*myMarking < *other.myMarking) return true; if (*other.myMarking < *myMarking) return false; return *myCondition < *other.myCondition; } /** Evaluate the multiset expression * @param valuation variable substitutions and the global marking * @return the filtered marking */ class PlaceMarking* meval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression */ void compile (class CExpression&, unsigned, const char*, const class VariableSet*) const { assert (false); } /** Generate C code for evaluating the multi-set expression * @param cexpr the compilation * @param indent indentation level * @param resulttype type of result (optional typecast qualifier) * @param result multi-set to add items to * @param vars the variables that have been assigned a value * @return the compiled multi-set expression */ void compileMset (class CExpression& cexpr, unsigned indent, const char* resulttype, const char* result, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The iterator variable */ class VariableDefinition* myVariable; /** The marking expression */ class Expression* myMarking; /** The submarking criterion */ class Expression* myCondition; }; #endif // SUBMARKING_H_ maria-1.3.5/Expression/Substitution.C0000644000175000017500000000424307643235732017754 0ustar msmakelamsmakela// Substitution (expression distribution for variables) -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Substitution.h" #include "Expression.h" #include "VariableDefinition.h" /** @file Substitution.C * Map from variables (quantifiers or function parameters) to expressions */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Substitution::Substitution () : myExprs () { } Substitution::~Substitution () { for (iterator i = myExprs.begin (); i != myExprs.end (); i++) i->second->destroy (); } class Expression* Substitution::getExpr (const class VariableDefinition& var) { const_iterator i = myExprs.find (&var); return i == myExprs.end () ? NULL : i->second->copy (); } void Substitution::setExpr (const class VariableDefinition& var, class Expression& expr) { assert (expr.isAssignable (var.getType ())); #ifndef NDEBUG std::pair status = #endif // !NDEBUG myExprs.insert (Map::value_type (&var, &expr)); assert (status.second); // must be new mapping // substitute the variable in existing substitutions again: for (iterator i = myExprs.begin (); i != myExprs.end (); i++) { class Expression* e = i->second->substitute (*this); assert (!!e); i->second->destroy (); if (i->second != e) { i->second = e; goto again; } } } maria-1.3.5/Expression/Substitution.h0000644000175000017500000000547207643235732020026 0ustar msmakelamsmakela// Substitution (expression distribution for variables) -*- c++ -*- #ifndef SUBSTITUTION_H_ # define SUBSTITUTION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include /** @file Substitution.h * Map from variables (quantifiers or function parameters) to expressions */ /* Copyright © 1999-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Substitution (expression distribution for variables) */ class Substitution { /** Pointer comparator */ struct vptr { bool operator () (const class VariableDefinition* v1, const class VariableDefinition* v2) const { return v1 < v2; } }; /** Map from variable definitions to expressions */ typedef std::map Map; /** Iterator to the map */ typedef Map::iterator iterator; /** Constant iterator to the map */ typedef Map::const_iterator const_iterator; public: /** Constructor */ Substitution (); private: /** Copy constructor */ Substitution (const class Substitution& old); /** Assignment operator */ class Substitution& operator= (const class Substitution& old); public: /** Destructor */ ~Substitution (); /** Get the expression of a variable * @param var identifies the variable * @return the expression, or NULL if there is none */ const class Expression* getExpr (const class VariableDefinition& var) const { const_iterator i = myExprs.find (&var); return i == myExprs.end () ? NULL : i->second; } /** Get the expression of a variable * @param var identifies the variable * @return the expression, or NULL if there is none */ class Expression* getExpr (const class VariableDefinition& var); /** Assign an expression to a variable. * @param var identifies the variable * @param expr expression to be assigned */ void setExpr (const class VariableDefinition& var, class Expression& expr); private: /** The expressions sorted by variables */ Map myExprs; }; #endif // SUBSTITUTION_H_ maria-1.3.5/Expression/TemporalBinop.C0000644000175000017500000000771607722340370020014 0ustar msmakelamsmakela// Maria temporal binary operator class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "TemporalBinop.h" #include "BoolType.h" #include "Net.h" #include "Property.h" #include "Printer.h" /** @file TemporalBinop.C * Temporal binary operators */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ TemporalBinop::TemporalBinop (enum Op op, class Expression& left, class Expression& right) : Expression (), myOp (op), myLeft (&left), myRight (&right) { assert (myLeft->getType ()->getKind () == Type::tBool); assert (myRight->getType ()->getKind () == Type::tBool); setType (Net::getBoolType ()); } TemporalBinop::~TemporalBinop () { myLeft->destroy (); myRight->destroy (); } class Expression* TemporalBinop::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* left = myLeft->ground (valuation, transition, declare); if (!left) return NULL; class Expression* right = myRight->ground (valuation, transition, declare); if (!right) { left->destroy (); return NULL; } assert (valuation.isOK ()); if (left == myLeft && right == myRight) { left->destroy (); right->destroy (); return copy (); } else return (new class TemporalBinop (myOp, *left, *right))->cse (); } class Expression* TemporalBinop::substitute (class Substitution& substitution) { class Expression* left = myLeft->substitute (substitution); class Expression* right = myRight->substitute (substitution); if (!left || !right) { left->destroy (); right->destroy (); return NULL; } if (left == myLeft && right == myRight) { left->destroy (); right->destroy (); return copy (); } else return (new class TemporalBinop (myOp, *left, *right))->cse (); } bool TemporalBinop::depends (const class VariableSet& vars, bool complement) const { return myLeft->depends (vars, complement) || myRight->depends (vars, complement); } bool TemporalBinop::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myLeft->forExpressions (operation, data) && myRight->forExpressions (operation, data); } class Ltl* TemporalBinop::toFormula (class Property& property) { switch (myOp) { case Until: return property.addBinop (Property::opUntil, *myLeft, *myRight); case Release: return property.addBinop (Property::opRelease, *myLeft, *myRight); } assert (false); return 0; } /** Convert an operator to a string * @param op the operator to convert * @return a string corresponding to the operator */ static const char* getOpString (enum TemporalBinop::Op op) { switch (op) { case TemporalBinop::Until: return "until"; case TemporalBinop::Release: return "release"; } return "???"; } void TemporalBinop::display (const class Printer& printer) const { printer.delimiter ('(')++; myLeft->display (printer); --printer.delimiter (')'); printer.printRaw (::getOpString (myOp)); printer.delimiter ('(')++; myRight->display (printer); --printer.delimiter (')'); } maria-1.3.5/Expression/TemporalBinop.h0000644000175000017500000001111607722340370020046 0ustar msmakelamsmakela// Maria temporal binary operator class -*- c++ -*- #ifndef TEMPORALBINOP_H_ # define TEMPORALBINOP_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file TemporalBinop.h * Temporal binary operators */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Temporal binary operator expression */ class TemporalBinop : public Expression { public: /** Temporal binary operators */ enum Op { Until, Release }; /** Constructor * @param op Operator * @param left Left-hand expression of the operator * @param right Right-hand expression of the operator */ TemporalBinop (enum Op op, class Expression& left, class Expression& right); private: /** Copy constructor */ TemporalBinop (const class TemporalBinop& old); /** Assignment operator */ class TemporalBinop& operator= (const class TemporalBinop& old); protected: /** Destructor */ ~TemporalBinop (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eTemporalBinop; } /** Determine whether this is a basic expression */ bool isBasic () const { return false; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return true; } /** Equality comparison operator */ bool operator== (const class TemporalBinop& other) const { return myOp == other.myOp && *myLeft == *other.myLeft && *myRight == *other.myRight; } /** Ordering comparison operator */ bool operator< (const class TemporalBinop& other) const { if (myOp < other.myOp) return true; if (other.myOp < myOp) return false; if (*myLeft < *other.myLeft) return true; if (*other.myLeft < *myLeft) return false; return *myRight < *other.myRight; } /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Translate the expression to a list of temporal logic connectives * and Boolean propositions * @param property the property automaton * @return the translated object */ class Ltl* toFormula (class Property& property); # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression */ void compile (class CExpression&, unsigned, const char*, const class VariableSet*) const { assert (false); } # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The operator */ enum Op myOp; /** Left-hand expression */ class Expression* myLeft; /** Right-hand expression */ class Expression* myRight; }; #endif // TEMPORALBINOP_H_ maria-1.3.5/Expression/TemporalUnop.C0000644000175000017500000000657407722340370017667 0ustar msmakelamsmakela// Maria temporal unary operator class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "TemporalUnop.h" #include "BoolType.h" #include "Net.h" #include "Property.h" #include "Printer.h" /** @file TemporalUnop.C * Temporal unary operators */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ TemporalUnop::TemporalUnop (enum Op op, class Expression& expr) : Expression (), myOp (op), myExpr (&expr) { assert (myExpr->getType ()->getKind () == Type::tBool); setType (Net::getBoolType ()); } TemporalUnop::~TemporalUnop () { myExpr->destroy (); } class Expression* TemporalUnop::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* expr = myExpr->ground (valuation, transition, declare); if (!expr) return NULL; assert (valuation.isOK ()); if (expr == myExpr) { expr->destroy (); return copy (); } else return (new class TemporalUnop (myOp, *expr))->cse (); } class Expression* TemporalUnop::substitute (class Substitution& substitution) { class Expression* expr = myExpr->substitute (substitution); if (!expr) return NULL; if (expr == myExpr) { expr->destroy (); return copy (); } else return (new class TemporalUnop (myOp, *expr))->cse (); } bool TemporalUnop::depends (const class VariableSet& vars, bool complement) const { return myExpr->depends (vars, complement); } bool TemporalUnop::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myExpr->forExpressions (operation, data); } class Ltl* TemporalUnop::toFormula (class Property& property) { switch (myOp) { case Finally: return property.addUnop (Property::opFinally, *myExpr); case Globally: return property.addUnop (Property::opGlobally, *myExpr); case Next: return property.addUnop (Property::opNext, *myExpr); } assert (false); return 0; } /** Convert an operator to a string * @param op the operator to convert * @return a string corresponding to the operator */ static const char* getOpString (enum TemporalUnop::Op op) { switch (op) { case TemporalUnop::Finally: return "<>"; case TemporalUnop::Globally: return "[]"; case TemporalUnop::Next: return "()"; } return "???"; } void TemporalUnop::display (const class Printer& printer) const { printer.printRaw (::getOpString (myOp)); printer.delimiter ('(')++; myExpr->display (printer); --printer.delimiter (')'); } maria-1.3.5/Expression/TemporalUnop.h0000644000175000017500000001044707722340370017726 0ustar msmakelamsmakela// Maria temporal unary operator class -*- c++ -*- #ifndef TEMPORALUNOP_H_ # define TEMPORALUNOP_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file TemporalUnop.h * Temporal unary operators */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Temporal unary operator expression */ class TemporalUnop : public Expression { public: /** Temporal unary operators */ enum Op { Finally, Globally, Next }; /** Constructor * @param op Operator * @param expr Subexpression of the operator */ TemporalUnop (enum Op op, class Expression& expr); private: /** Copy constructor */ TemporalUnop (const class TemporalUnop& old); /** Assignment operator */ class TemporalUnop& operator= (const class TemporalUnop& old); protected: /** Destructor */ ~TemporalUnop (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eTemporalUnop; } /** Determine whether this is a basic expression */ bool isBasic () const { return false; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return true; } /** Equality comparison operator */ bool operator== (const class TemporalUnop& other) const { return myOp == other.myOp && *myExpr == *other.myExpr; } /** Ordering comparison operator */ bool operator< (const class TemporalUnop& other) const { if (myOp < other.myOp) return true; if (other.myOp < myOp) return false; return *myExpr < *other.myExpr; } /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Translate the expression to a list of temporal logic connectives * and Boolean propositions * @param property the property automaton * @return the translated object */ class Ltl* toFormula (class Property& property); # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression */ void compile (class CExpression&, unsigned, const char*, const class VariableSet*) const { assert (false); } # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The operator */ enum Op myOp; /** The subexpression */ class Expression* myExpr; }; #endif // TEMPORALUNOP_H_ maria-1.3.5/Expression/Token.C0000644000175000017500000000746307643235732016327 0ustar msmakelamsmakela// Unified token -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Token.h" #include "VariableSet.h" /** @file Token.C * Tokens used in the unification process */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Token::~Token () { delete myUnifiedUndefined; delete myValue; } bool Token::isBindable (const class Valuation& valuation) { assert (valuation.isOK ()); const class Expression& expr = *myUnifier.m->getToken (); if (myUnifier.isSet) { delete myValue; if ((myValue = expr.meval (valuation))) { assert (valuation.isOK ()); if (*myValue <= myPlaceMarking) return true; } } else if (class Value* value = expr.eval (valuation)) { assert (valuation.isOK ()); myIterator = myPlaceMarking.find (value); delete value; if (myIterator != end ()) { if (myCardinality <= PlaceMarking::getCount (myIterator)) return true; myIterator = begin (); } } return false; } bool Token::isBindableUnfold (const class Valuation& valuation) { assert (valuation.isOK ()); const class Expression& expr = *myUnifier.m->getToken (); if (myUnifier.isSet) { delete myValue; if ((myValue = expr.meval (valuation))) { assert (valuation.isOK ()); return myValue->isSubset (myPlaceMarking); } } else if (class Value* value = expr.eval (valuation)) { assert (valuation.isOK ()); myIterator = myPlaceMarking.find (value); delete value; return myIterator != end (); } return false; } void Token::undefine (class Valuation& valuation) { if (!myUnifier.vars) return; const class VariableSet& vars = *myUnifier.vars; VariableSet::const_iterator i = vars.begin (); if (!myUnifier.varMult) for (; i != vars.end (); i++) valuation.undefine (**i); else for (; i != vars.end (); i++) if (!isUnified (**i)) valuation.undefine (**i); } void Token::addUnified (const class Valuation& valuation) { assert (myUnifier.varMult); assert (!myUnifiedUndefined); const class VariableSet& vars = *myUnifier.vars; for (VariableSet::const_iterator i = vars.begin (); i != vars.end (); i++) { if (valuation.getValue (**i)) { if (!myUnifiedUndefined) myUnifiedUndefined = new class VariableSet; myUnifiedUndefined->insert (**i); } } } bool Token::isUnified (const class VariableDefinition& var) const { return myUnifiedUndefined && myUnifiedUndefined->contains (var); } #ifndef NDEBUG # include "VariableDefinition.h" void Token::assertUndefined (const class Valuation& valuation) const { const class VariableSet& vars = *myUnifier.vars; for (VariableSet::const_iterator i = vars.begin (); i != vars.end (); i++) assert (!valuation.getValue (**i) || (*i)->isUndefined ()); } void Token::assertDefined (const class Valuation& valuation) const { const class VariableSet& vars = *myUnifier.vars; for (VariableSet::const_iterator i = vars.begin (); i != vars.end (); i++) assert (!!valuation.getValue (**i)); } #endif // NDEBUG maria-1.3.5/Expression/Token.h0000644000175000017500000002253210232531567016357 0ustar msmakelamsmakela// Unified token -*- c++ -*- #ifndef TOKEN_H_ # define TOKEN_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ /** @file Token.h * Tokens used in the unification process */ /* Copyright © 1999-2003,2005 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ # include "GlobalMarking.h" # include "Marking.h" # include /** List of tokens to be unified */ struct unif { /** next token */ struct unif* next; /** variables that are bound from this token */ class VariableSet* vars; /** flag: does the token have variable multiplicity? */ bool varMult; /** index of the input place in the net */ unsigned place; /** the token */ const class Marking* m; /** flag: is the token multiset-valued? */ bool isSet; }; /** Unified token */ class Token { typedef PlaceMarking::iterator iterator; typedef PlaceMarking::const_iterator const_iterator; public: /** Constructor * @param cardinality cardinality of the token * @param placeMarking the PlaceMarking containing the actual token(s) * @param unifier unification structure */ Token (card_t cardinality, class PlaceMarking& placeMarking, const struct unif& unifier) : myIsReserved (false), myCardinality (cardinality), myPlaceMarking (placeMarking), myValue (0), myUnifier (unifier), myIterator (placeMarking.begin ()), myUnifiedUndefined (0) { assert (myCardinality > 0); assert (myUnifier.isSet || !myPlaceMarking.empty ()); } private: /** Copy constructor */ Token (const class Token& old); /** Assignment operator */ class Token& operator= (const class Token& old); public: /** Destructor */ ~Token (); /** Get the unification structure */ const struct unif& getUnifier () const { return myUnifier; } /** Determine the cardinality of the actual token */ card_t getCardinality () const { return myCardinality; } /** Find the next candidate for the concrete token * @return true if a candidate was found */ bool getConcrete () { assert (!myIsReserved); for (; myIterator != end (); myIterator++) if (myCardinality <= myPlaceMarking.getCount (myIterator)) return true; return false; } /** Find the next candidate for the concrete token, disregarding multiplicity * @return true if a candidate was found */ bool getConcreteUnfold () { assert (!myIsReserved); return myIterator != end (); } /** Get the value of the concrete token candidate */ const class Value& getValue () const { assert (myIterator != myPlaceMarking.end ()); return PlaceMarking::getValue (myIterator); } /** Try to bind the token to a concrete token (and set myIterator to it) * @param valuation the valuation to observe * @return true if the token could be bound */ bool isBindable (const class Valuation& valuation); /** Try to bind the token to a concrete token, disregarding multiplicity * @param valuation the valuation to observe * @return true if the token could be bound */ bool isBindableUnfold (const class Valuation& valuation); private: const_iterator begin () const { return myPlaceMarking.begin (); } const_iterator end () const { return myPlaceMarking.end (); } iterator begin () { return myPlaceMarking.begin (); } iterator end () { return myPlaceMarking.end (); } public: /** Advance the iterator to the concrete tokens * @return false if the iterator reached the end */ bool next () { assert (!myIsReserved); assert (myIterator != end ()); return ++myIterator != end (); } /** Determine whether the token has been bound to a concrete token */ bool isReserved () const { return myIsReserved; } /** Bind the token to a concrete token */ void reserve () { assert (!myIsReserved); if (myValue) myPlaceMarking -= *myValue; else myPlaceMarking.reserve (myIterator, myCardinality); myIsReserved = true; } /** Remove the reservation (binding) of the concrete token */ void free () { assert (myIsReserved); if (myValue) { if (!myPlaceMarking.add (*myValue, 1)) assert (false); } else myPlaceMarking.free (myIterator, myCardinality); myIsReserved = false; } /** Undefine the variables that were unified from this token * @param valuation the valuation where the variables are defined */ void undefine (class Valuation& valuation); /** Set the "reserved" status (needed by the unfolding algorithm) */ void setReservedUnfold (bool reserved) { myIsReserved = reserved; } /** Augment the collection of removed tokens * @param pm the collection * @return true if the operation succeeded */ bool copyRemoved (class PlaceMarking& pm) const { assert (myIsReserved); return myValue ? pm.add (*myValue, 1) : pm.add (*PlaceMarking::getValue (myIterator).copy (), myCardinality); } /** Determine whether the valuations are compatible with the concrete tokens * @param valuation the valuation to observe * @return true if the token is compatible */ bool isCompatible (const class Valuation& valuation) const { return myUnifier.m->getToken ()->isCompatible (getValue (), valuation); } /** Update the set of unified possibly undefined variables * @param valuation the valuation to observe */ void addUnified (const class Valuation& valuation); /** See if a possibly undefined variable is already unified */ bool isUnified (const class VariableDefinition& var) const; # ifndef NDEBUG /** Assert that the token can be popped from the stack */ void assertPop () const { assert (this && myCardinality); assert (myUnifier.isSet || myIterator != myPlaceMarking.end ()); } /** Assert that none of the variables to unify have values * @param valuation the valuation to observe */ void assertUndefined (const class Valuation& valuation) const; /** Assert that all of the variables to unify have values * @param valuation the valuation to observe */ void assertDefined (const class Valuation& valuation) const; # endif // NDEBUG private: /** Flag: has the token been reserved from the place? */ bool myIsReserved; /** Cardinality of the actual token */ card_t myCardinality; /** PlaceMarking to which the Token belongs */ class PlaceMarking& myPlaceMarking; /** PlaceMarking to which the Token evaluates */ class PlaceMarking* myValue; /** the unification structure */ const struct unif& myUnifier; /** Iterator to the PlaceMarking */ iterator myIterator; /** Previously unified possibly undefined variables */ class VariableSet* myUnifiedUndefined; }; /** List of unified tokens */ class TokenList { public: /** List of tokens */ typedef std::list List; /** Iterator to the list of tokens */ typedef List::iterator iterator; /** Constant iterator to the list of tokens */ typedef List::const_iterator const_iterator; /** Constructor */ TokenList () : myList () {} private: /** Copy constructor */ TokenList (const class TokenList& old); /** Assignment operator */ class TokenList& operator= (const class TokenList& old); public: /** Destructor */ ~TokenList () { for (iterator i = begin (); i != end (); i++) delete *i; } /** @name Accessors to the token list */ /*@{*/ bool empty () const { return myList.empty (); } size_t size () const { return myList.size (); } iterator begin () { return myList.begin (); } iterator end () { return myList.end (); } const_iterator begin () const { return myList.begin (); } const_iterator end () const { return myList.end (); } void insert (class Token& token) { myList.push_front (&token); } void clear () { for (iterator i = begin (); i != end (); i++) delete *i; myList.clear (); } /*@}*/ /** Peek at the topmost token on the stack */ const class Token& top () const { assert (!empty ()); return **begin (); } /** Pop a token from the stack */ class Token& pop () { assert (!empty ()); iterator i = begin (); class Token* token = *i; myList.erase (i); #ifndef NDEBUG token->assertPop (); #endif // NDEBUG return *token; } /** Push a token to the stack */ void push (class Token& token) { myList.push_front (&token); } /** Determine whether the valuations are compatible with the concrete tokens * @param valuation the valuation to observe * @return true if all tokens are compatible */ bool isCompatible (const class Valuation& valuation) const { for (const_iterator i = begin (); i != end (); i++) if (!(*i)->isCompatible (valuation)) return false; return true; } private: /** The list of tokens */ List myList; }; #endif // TOKEN_H_ maria-1.3.5/Expression/TransitionQualifier.C0000644000175000017500000000600407722340370021222 0ustar msmakelamsmakela// Maria transition qualifier expression class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "TransitionQualifier.h" #include "Net.h" #include "BoolType.h" #include "Transition.h" #include "Printer.h" /** @file TransitionQualifier.C * Transition instance qualifier */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ TransitionQualifier::TransitionQualifier (const class Transition& transition, class Expression& expr) : Expression (), myTransition (&transition), myExpr (&expr) { assert (myExpr->getType ()->getKind () == Type::tBool); setType (*myExpr->getType ()); } TransitionQualifier::~TransitionQualifier () { myExpr->destroy (); } class Expression* TransitionQualifier::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* e = myExpr->ground (valuation, transition, declare); if (!e) return NULL; assert (valuation.isOK ()); if (e == myExpr) { e->destroy (); return copy (); } else return (new class TransitionQualifier (*myTransition, *e))->cse (); } class Expression* TransitionQualifier::substitute (class Substitution& substitution) { class Expression* e = myExpr->substitute (substitution); if (!e) return NULL; if (e == myExpr) { e->destroy (); return copy (); } else return (new class TransitionQualifier (*myTransition, *e))->cse (); } bool TransitionQualifier::depends (const class VariableSet& vars, bool complement) const { return myExpr->depends (vars, complement); } bool TransitionQualifier::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myExpr->forExpressions (operation, data); } class Expression* TransitionQualifier::disqualify (const class Transition& transition) { return myTransition == &transition ? myExpr->copy () : 0; } void TransitionQualifier::display (const class Printer& printer) const { printer.printRaw ("trans"); printer.delimiter (' '); printer.print (myTransition->getName ()); if (myExpr) { printer.delimiter (':'); myExpr->display (printer); } } maria-1.3.5/Expression/TransitionQualifier.h0000644000175000017500000001105407722340370021270 0ustar msmakelamsmakela// Maria transition qualifier expression class -*- c++ -*- #ifndef TRANSITIONQUALIFIER_H_ # define TRANSITIONQUALIFIER_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file TransitionQualifier.h * Transition instance qualifier */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Transition instance qualifier expression */ class TransitionQualifier : public Expression { public: /** Constructor * @param transition The transition whose instances are being qualified * @param expr Qualifying expression for the transition instances */ TransitionQualifier (const class Transition& transition, class Expression& expr); private: /** Copy constructor */ TransitionQualifier (const class TransitionQualifier& old); /** Assignment operator */ class TransitionQualifier& operator= (const class TransitionQualifier& old); protected: /** Destructor */ ~TransitionQualifier (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eTransitionQualifier; } /** Determine whether this is a basic expression */ bool isBasic () const { return false; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class TransitionQualifier& other) const { return myTransition == other.myTransition && *myExpr == *other.myExpr; } /** Ordering comparison operator */ bool operator< (const class TransitionQualifier& other) const { if (myTransition < other.myTransition) return true; if (other.myTransition < myTransition) return false; return *myExpr < *other.myExpr; } /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Remove transition qualifiers from the expression * @param transition the transition for which the expression is qualified * @return the expession without qualifiers, or NULL */ class Expression* disqualify (const class Transition& transition); # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression */ void compile (class CExpression&, unsigned, const char*, const class VariableSet*) const { assert (false); } # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The transition */ const class Transition* myTransition; /** The qualifier expression */ class Expression* myExpr; }; #endif // TRANSITIONQUALIFIER_H_ maria-1.3.5/Expression/Typecast.C0000644000175000017500000001275007722340370017027 0ustar msmakelamsmakela// Maria typecast expression -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Typecast.h" #include "Type.h" #include "LeafValue.h" #include "Printer.h" /** @file Typecast.C * Type conversion operation */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ bool Typecast::isCastable (const class Type& type) { switch (type.getKind ()) { case Type::tInt: case Type::tCard: case Type::tBool: case Type::tChar: case Type::tEnum: return true; default: return false; } } Typecast::Typecast (const class Type& type, class Expression& expr) : Expression (), myExpr (&expr) { setType (type); assert (getType () != expr.getType ()); assert (expr.isBasic () && !expr.isSet ()); assert ((isCastable (*getType ()) && isCastable (*myExpr->getType ())) || Type::isCompatible (*myExpr->getType (), *getType ())); } Typecast::~Typecast () { myExpr->destroy (); } class Value* Typecast::do_eval (const class Valuation& valuation) const { class Value* v = myExpr->eval (valuation); if (v && !(v = v->cast (*getType ()))) valuation.flag (errConst, *this); return v; } class Expression* Typecast::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* e = myExpr->ground (valuation, transition, declare); if (!e) return NULL; assert (valuation.isOK ()); if (e == myExpr) { e->destroy (); return copy (); } else return static_cast (new class Typecast (*getType (), *e))->ground (valuation); } class Expression* Typecast::substitute (class Substitution& substitution) { class Expression* e = myExpr->substitute (substitution); if (e == myExpr) { e->destroy (); return copy (); } else return (new class Typecast (*getType (), *e))->cse (); } bool Typecast::depends (const class VariableSet& vars, bool complement) const { return myExpr->depends (vars, complement); } bool Typecast::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myExpr->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" void Typecast::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { if (getType ()->isLeaf () && myExpr->getType ()->isLeaf ()) { myExpr->compile (cexpr, indent, lvalue, vars); if (const class Constraint* c = getType ()->getConstraint ()) c->compileCheck (cexpr, indent, lvalue); } else { char* rvalue; if (cexpr.getVariable (*myExpr, rvalue)) myExpr->compile (cexpr, indent, rvalue, vars); myExpr->getType ()->compileCast (cexpr, indent, *getType (), lvalue, rvalue); delete[] rvalue; } } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eStruct: case Expression::eVector: case Expression::eBuffer: case Expression::eVectorIndex: case Expression::eTypecast: case Expression::eUnop: case Expression::eNot: case Expression::eBufferUnop: case Expression::eTemporalUnop: return false; case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: assert (false); case Expression::eUnion: case Expression::eUnionType: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: case Expression::eSet: case Expression::eBinop: case Expression::eBooleanBinop: case Expression::eRelop: case Expression::eIfThenElse: case Expression::eTemporalBinop: case Expression::eCardinality: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: break; } return true; } void Typecast::display (const class Printer& printer) const { printer.printRaw ("is"); printer.delimiter (' '); if (const char* name = getType ()->getName ()) printer.print (name); else printer.print (getType ()->getSyntacticName ()); printer.delimiter (' '); if (::needParentheses (myExpr->getKind ())) { printer.delimiter ('(')++; myExpr->display (printer); --printer.delimiter (')'); } else myExpr->display (printer); } maria-1.3.5/Expression/Typecast.h0000644000175000017500000001061107722340370017066 0ustar msmakelamsmakela// Maria typecast expression -*- c++ -*- #ifndef TYPECAST_H_ # define TYPECAST_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file Typecast.h * Type conversion operation */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Type conversion expression */ class Typecast : public Expression { public: /** Constructor * @param type type reference * @param expr expression to be casted */ Typecast (const class Type& type, class Expression& expr); private: /** Copy constructor */ Typecast (const class Typecast& old); /** Assignment operator */ class Typecast& operator= (const class Typecast& old); protected: /** Destructor */ ~Typecast (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eTypecast; } /** Determine whether this is a basic expression */ bool isBasic () const { return myExpr->isBasic (); } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return myExpr->isTemporal (); } /** Equality comparison operator */ bool operator== (const class Typecast& other) const { return *myExpr == *other.myExpr; } /** Ordering comparison operator */ bool operator< (const class Typecast& other) const { return *myExpr < *other.myExpr; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Determine whether a type is castable * @param type type to be checked * @return true if the type is castable */ static bool isCastable (const class Type& type); # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The subexpression */ class Expression* myExpr; }; #endif // TYPECAST_H_ maria-1.3.5/Expression/Undefined.C0000644000175000017500000000420407722340370017127 0ustar msmakelamsmakela// undefined expression class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Undefined.h" #include "Printer.h" /** @file Undefined.C * Undefined literal */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Undefined::Undefined (enum Fatalness fatalness) : Expression (), myFatalness (fatalness) { } Undefined::~Undefined () { } class Value* Undefined::do_eval (const class Valuation& valuation) const { switch (myFatalness) { case fError: valuation.flag (errUndef, *this); return 0; case fFatalError: valuation.flag (errFatal, *this); return 0; } assert (false); return 0; } bool Undefined::depends (const class VariableSet&, bool) const { return false; } bool Undefined::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data); } #ifdef EXPR_COMPILE # include "CExpression.h" void Undefined::compile (class CExpression& cexpr, unsigned indent, const char*, const class VariableSet*) const { cexpr.compileError (indent, myFatalness == fError ? errUndef : errFatal); } #endif // EXPR_COMPILE void Undefined::display (const class Printer& printer) const { printer.printRaw (myFatalness == fFatalError ? "fatal" : "undefined"); } maria-1.3.5/Expression/Undefined.h0000644000175000017500000001040307722340370017172 0ustar msmakelamsmakela// undefined expression class -*- c++ -*- #ifndef UNDEFINED_H_ # define UNDEFINED_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file Undefined.h * Undefined literal */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Undefined expression */ class Undefined : public Expression { public: /** Fatalness levels */ enum Fatalness { /** issue an error message; do not fire the transition instance */ fError, /** issue a fatal error message; stop the graph generation */ fFatalError }; /** Constructor * @param fatalness Fatalness level */ explicit Undefined (enum Fatalness fatalness); private: /** Copy constructor */ explicit Undefined (const class Undefined& old); /** Assignment operator */ class Undefined& operator= (const class Undefined& old); protected: /** Destructor */ ~Undefined (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eUndefined; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class Undefined& other) const { return myFatalness == other.myFatalness; } /** Ordering comparison operator */ bool operator< (const class Undefined& other) const { return myFatalness < other.myFatalness; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation&, class Transition*, bool) { return copy (); } /** Substitute some variables in the expression with expressions * @return substituted expression */ class Expression* substitute (class Substitution&) { return copy (); } /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; /** Determine whether this is a fatal expression */ bool isFatal () const { return myFatalness == fFatalError; } private: /** Fatalness level */ enum Fatalness myFatalness; }; #endif // UNDEFINED_H_ maria-1.3.5/Expression/UnionComponent.C0000644000175000017500000001303207722340370020200 0ustar msmakelamsmakela// Maria union component reference expression class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "UnionComponent.h" #include "UnionType.h" #include "UnionValue.h" #include "Valuation.h" #include "Printer.h" /** @file UnionComponent.C * Union component reference */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ UnionComponent::UnionComponent (class Expression& expr, card_t i) : myExpr (&expr), myIndex (i) { assert (myExpr && myExpr->getType ()); assert (myExpr->getType ()->getKind () == Type::tUnion); const class UnionType* type = static_cast(myExpr->getType ()); assert (myExpr->isBasic ()); setType ((*type)[myIndex]); } UnionComponent::~UnionComponent () { myExpr->destroy (); } class Value* UnionComponent::do_eval (const class Valuation& valuation) const { class Value* v = myExpr->eval (valuation); if (!v) return NULL; assert (v->getKind () == Value::vUnion); class UnionValue* u = static_cast(v); if (u->getIndex () != myIndex) { valuation.flag (errUnion, *this); delete u; return NULL; } v = u->getValue ().copy (); delete u; return v; } class Expression* UnionComponent::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* e = myExpr->ground (valuation, transition, declare); if (!e) return NULL; assert (valuation.isOK ()); if (e == myExpr) { e->destroy (); return copy (); } else return static_cast (new class UnionComponent (*e, myIndex))->ground (valuation); } class Expression* UnionComponent::substitute (class Substitution& substitution) { class Expression* e = myExpr->substitute (substitution); if (e == myExpr) { e->destroy (); return copy (); } else return (new class UnionComponent (*e, myIndex))->cse (); } bool UnionComponent::depends (const class VariableSet& vars, bool complement) const { return myExpr->depends (vars, complement); } bool UnionComponent::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myExpr->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" void UnionComponent::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { char* rvalue = 0; class StringBuffer& out = cexpr.getOut (); if (cexpr.getVariable (*myExpr, rvalue)) myExpr->compile (cexpr, indent, rvalue, vars); out.indent (indent); out.append ("if ("); out.append (rvalue); out.append (".t!="); out.append (myIndex); out.append (")\n"); cexpr.compileError (indent + 2, errUnion); out.indent (indent); out.append (lvalue); out.append ("="); out.append (rvalue); out.append (".u.u"); out.append (myIndex); out.append (";\n"); delete[] rvalue; } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eVectorIndex: return false; case Expression::eCardinality: case Expression::eUnionType: case Expression::eUnion: case Expression::eVector: case Expression::eBinop: case Expression::eBooleanBinop: case Expression::eNot: case Expression::eRelop: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: case Expression::eVectorAssign: case Expression::eVectorShift: assert (false); case Expression::eUnop: case Expression::eConstant: case Expression::eStruct: case Expression::eStructAssign: case Expression::eIfThenElse: case Expression::eBufferUnop: case Expression::eTypecast: break; } return true; } void UnionComponent::display (const class Printer& printer) const { if (::needParentheses (myExpr->getKind ())) { printer.delimiter ('(')++; myExpr->display (printer); --printer.delimiter (')'); } else myExpr->display (printer); printer.delimiter ('.'); printer.print (static_cast(myExpr->getType ()) ->getComponentName (myIndex)); } maria-1.3.5/Expression/UnionComponent.h0000644000175000017500000001106207722340370020246 0ustar msmakelamsmakela// Maria union component reference expression class -*- c++ -*- #ifndef UNIONCOMPONENT_H_ # define UNIONCOMPONENT_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include "typedefs.h" /** @file UnionComponent.h * Union component reference */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Union component reference expression */ class UnionComponent : public Expression { public: /** Constructor * @param expr Expression evaluating to the union type * @param i Index of the referenced union component */ UnionComponent (class Expression& expr, card_t i); private: /** Copy constructor */ UnionComponent (const class UnionComponent& old); /** Assignment operator */ class UnionComponent& operator= (const class UnionComponent& old); protected: /** Destructor */ ~UnionComponent (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eUnionComponent; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class UnionComponent& other) const { return myIndex == other.myIndex && *myExpr == *other.myExpr; } /** Ordering comparison operator */ bool operator< (const class UnionComponent& other) const { if (myIndex < other.myIndex) return true; if (other.myIndex < myIndex) return false; return *myExpr < *other.myExpr; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The union-valued expression being referenced */ class Expression* myExpr; /** Index of the referenced union component */ card_t myIndex; }; #endif // UNIONCOMPONENT_H_ maria-1.3.5/Expression/UnionExpression.C0000644000175000017500000001351507722340370020403 0ustar msmakelamsmakela// Maria union expression class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "UnionExpression.h" #include "UnionType.h" #include "UnionValue.h" #include "Printer.h" /** @file UnionExpression.C * Union value constructor */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ UnionExpression::UnionExpression (const class Type& type, class Expression& expr, card_t i) : Expression (), myUnionType (&type), myExpr (&expr), myIndex (i) { assert (type.getKind () == Type::tUnion); assert (myExpr->getType ()->isAssignable (static_cast(type)[i])); assert (myExpr->isBasic ()); Expression::setType (type); } UnionExpression::~UnionExpression () { myExpr->destroy (); } class Value* UnionExpression::do_eval (const class Valuation& valuation) const { class Value* v = myExpr->eval (valuation); if (!v) return NULL; return new class UnionValue (*myUnionType, myIndex, *v); } class Expression* UnionExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* e = myExpr->ground (valuation, transition, declare); if (!e) return NULL; assert (valuation.isOK ()); if (e == myExpr) { e->destroy (); return copy (); } else return static_cast (new class UnionExpression (*myUnionType, *e, myIndex))->ground (valuation); } class Expression* UnionExpression::substitute (class Substitution& substitution) { class Expression* e = myExpr->substitute (substitution); if (e == myExpr) { e->destroy (); return copy (); } else return (new class UnionExpression (*myUnionType, *e, myIndex))->cse (); } bool UnionExpression::depends (const class VariableSet& vars, bool complement) const { return myExpr->depends (vars, complement); } bool UnionExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myExpr->forExpressions (operation, data); } bool UnionExpression::isCompatible (const class Value& value, const class Valuation& valuation) const { assert (value.getKind () == Value::vUnion && value.getType ().getKind () == Type::tUnion); const class UnionValue& uv = static_cast(value); return uv.getIndex () == myIndex && myExpr->isCompatible (uv.getValue (), valuation); } void UnionExpression::getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const { assert (value.getKind () == Value::vUnion); assert (&value.getType () == getType ()); const class UnionValue& uv = static_cast(value); if (uv.getIndex () == myIndex) myExpr->getLvalues (uv.getValue (), valuation, vars); } void UnionExpression::getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const { myExpr->getLvalues (rvalues, lvalues); } #ifdef EXPR_COMPILE # include "CExpression.h" # include void UnionExpression::compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const { assert (!!lvalue); const size_t len = strlen (lvalue); char* const newlvalue = new char[len + 25]; char* const suffix = newlvalue + len; memcpy (newlvalue, lvalue, len); snprintf (suffix, 25, ".u.u%u", myIndex); myExpr->compileLvalue (cexpr, indent, vars, newlvalue); delete[] newlvalue; } void UnionExpression::compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const { const size_t len = strlen (value); char* const val = new char[len + 25]; char* const suffix = val + len; memcpy (val, value, len); class StringBuffer& out = cexpr.getOut (); snprintf (suffix, 25, ".u.u%u", myIndex); out.indent (indent), out.append ("if ("); out.append (value); out.append (".t!="), out.append (suffix + 4); out.append (")\n"); cexpr.compileError (indent + 2, errComp); myExpr->compileCompatible (cexpr, indent, vars, val); delete[] val; } void UnionExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { size_t len = strlen (lvalue); char* const newlvalue = new char[len + 25]; char* const suffix = newlvalue + len; memcpy (newlvalue, lvalue, len); class StringBuffer& out = cexpr.getOut (); snprintf (suffix, 25, ".u.u%u", myIndex); out.indent (indent); out.append (lvalue); out.append (".t="); out.append (suffix + 4); out.append (";\n"); myExpr->compile (cexpr, indent, newlvalue, vars); delete[] newlvalue; compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE void UnionExpression::display (const class Printer& printer) const { printer.print (static_cast(myUnionType) ->getComponentName (myIndex)); printer.delimiter ('='); myExpr->display (printer); } maria-1.3.5/Expression/UnionExpression.h0000644000175000017500000001476107722340370020454 0ustar msmakelamsmakela// Maria union expression class -*- c++ -*- #ifndef UNIONEXPRESSION_H_ # define UNIONEXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include "typedefs.h" /** @file UnionExpression.h * Union value constructor */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Union expression */ class UnionExpression : public Expression { public: /** Constructor * @param type type of the union * @param expr expression to be assigned to the union * @param i index of the component */ UnionExpression (const class Type& type, class Expression& expr, card_t i); private: /** Copy constructor */ UnionExpression (const class UnionExpression& old); /** Assignment operator */ class UnionExpression& operator= (const class UnionExpression& old); protected: /** Destructor */ ~UnionExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eUnion; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class UnionExpression& other) const { return myUnionType == other.myUnionType && myIndex == other.myIndex && *myExpr == *other.myExpr; } /** Ordering comparison operator */ bool operator< (const class UnionExpression& other) const { if (myUnionType < other.myUnionType) return true; if (other.myUnionType < myUnionType) return false; if (myIndex < other.myIndex) return true; if (other.myIndex < myIndex) return false; return *myExpr < *other.myExpr; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Determine whether the expression is compatible with the specified value, * neglecting subexpressions that cannot be evaluated * @param value value the expression will be compared to * @param valuation variable substitutions * @return true if the expression is compatible with the value */ bool isCompatible (const class Value& value, const class Valuation& valuation) const; /** Unify variables from this expression * @param value the value the expression should evaluate to * @param valuation variable substitutions * @param vars the variables to unify */ void getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const; /** Determine which variables could be unified from this expression * @param rvalues variables unified so far * @param lvalues (output) variables that could be unified * @return variables that could be unified */ void getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const; # ifdef EXPR_COMPILE /** Generate lvalue gathering code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables * @param lvalue C expression referring to the value */ void compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const; /** Generate compatibility check code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables that have been unified * @param value C expression referring to the desired value */ void compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const; /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The union type */ const class Type* myUnionType; /** The expression being assigned to the union */ class Expression* myExpr; /** The union component number */ card_t myIndex; }; #endif // UNIONEXPRESSION_H_ maria-1.3.5/Expression/UnionTypeExpression.C0000644000175000017500000001266207722340370021247 0ustar msmakelamsmakela// Maria union type expression class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "UnionTypeExpression.h" #include "UnionType.h" #include "UnionValue.h" #include "BoolType.h" #include "LeafValue.h" #include "Net.h" #include "Printer.h" /** @file UnionTypeExpression.C * Union determinant */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ UnionTypeExpression::UnionTypeExpression (class Expression& expr, card_t i) : myExpr (&expr), myIndex (i) { assert (myExpr && myExpr->getType ()); assert (myExpr->getType ()->getKind () == Type::tUnion); assert (myExpr->isBasic ()); setType (Net::getBoolType ()); } UnionTypeExpression::~UnionTypeExpression () { myExpr->destroy (); } class Value* UnionTypeExpression::do_eval (const class Valuation& valuation) const { class Value* v = myExpr->eval (valuation); if (!v) return NULL; assert (v->getKind () == Value::vUnion); bool is = static_cast(v)->getIndex () == myIndex; delete v; return constrain (valuation, new class LeafValue (*getType (), is)); } class Expression* UnionTypeExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* e = myExpr->ground (valuation, transition, declare); if (!e) return NULL; assert (valuation.isOK ()); if (e == myExpr) { e->destroy (); return copy (); } else return static_cast (new class UnionTypeExpression (*e, myIndex))->ground (valuation); } class Expression* UnionTypeExpression::substitute (class Substitution& substitution) { class Expression* e = myExpr->substitute (substitution); if (e == myExpr) { e->destroy (); return copy (); } else return (new class UnionTypeExpression (*e, myIndex))->cse (); } bool UnionTypeExpression::depends (const class VariableSet& vars, bool complement) const { return myExpr->depends (vars, complement); } bool UnionTypeExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myExpr->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" void UnionTypeExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { char* rvalue = 0; class StringBuffer& out = cexpr.getOut (); if (cexpr.getVariable (*myExpr, rvalue)) myExpr->compile (cexpr, indent, rvalue, vars); out.indent (indent); out.append (lvalue); out.append ("="); out.append (rvalue); out.append (".t=="); out.append (myIndex); out.append (";\n"); delete[] rvalue; compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eVectorIndex: case Expression::eNot: case Expression::eTypecast: case Expression::eUnop: case Expression::eBufferUnop: case Expression::eCardinality: return false; case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eBooleanBinop: case Expression::eUnionType: case Expression::eBinop: case Expression::eRelop: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: assert (false); case Expression::eIfThenElse: case Expression::eStruct: case Expression::eUnion: case Expression::eVector: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: break; } return true; } void UnionTypeExpression::display (const class Printer& printer) const { if (::needParentheses (myExpr->getKind ())) { printer.delimiter ('(')++; myExpr->display (printer); --printer.delimiter (')'); } else myExpr->display (printer); printer.delimiter (' '); printer.printRaw ("is"); printer.delimiter (' '); printer.print (static_cast(myExpr->getType ()) ->getComponentName (myIndex)); } maria-1.3.5/Expression/UnionTypeExpression.h0000644000175000017500000001115407722340370021307 0ustar msmakelamsmakela// Maria union type expression class -*- c++ -*- #ifndef UNIONTYPEEXPRESSION_H_ # define UNIONTYPEEXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include "typedefs.h" /** @file UnionTypeExpression.h * Union determinant */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Union type expression: determine the type of a union expression */ class UnionTypeExpression : public Expression { public: /** Constructor * @param expr Expression evaluating to the union type * @param i Index of the union component */ UnionTypeExpression (class Expression& expr, card_t i); private: /** Copy constructor */ UnionTypeExpression (const class UnionTypeExpression& old); /** Assignment operator */ class UnionTypeExpression& operator= (const class UnionTypeExpression& old); protected: /** Destructor */ ~UnionTypeExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eUnionType; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class UnionTypeExpression& other) const { return myIndex == other.myIndex && *myExpr == *other.myExpr; } /** Ordering comparison operator */ bool operator< (const class UnionTypeExpression& other) const { if (myIndex < other.myIndex) return true; if (other.myIndex < myIndex) return false; return *myExpr < *other.myExpr; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The union-valued expression being referenced */ class Expression* myExpr; /** Index of the referenced union typeExpression */ card_t myIndex; }; #endif // UNIONTYPEEXPRESSION_H_ maria-1.3.5/Expression/UnopExpression.C0000644000175000017500000001663007722340370020235 0ustar msmakelamsmakela// unary operator class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "UnopExpression.h" #include "IntType.h" #include "CardType.h" #include "LeafValue.h" #include "Net.h" #include "Printer.h" /** @file UnopExpression.C * Unary operators for integer and other arithmetics */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ UnopExpression::UnopExpression (enum Op op, class Expression& expr) : Expression (), myOp (op), myExpr (&expr) { if (myOp == uNeg) setType (Net::getIntType ()); else setType (*expr.getType ()); assert (myOp == uSucc || myOp == uPred ? getType ()->isOrdered () : (getType ()->getKind () == Type::tInt || getType ()->getKind () == Type::tCard)); assert (myExpr->isBasic ()); } UnopExpression::~UnopExpression () { myExpr->destroy (); } class Value* UnopExpression::do_eval (const class Valuation& valuation) const { class Value* v = myExpr->eval (valuation); if (!v) return NULL; assert (v->getKind () == Value::vLeaf || myOp == uSucc || myOp == uPred); switch (myOp) { case uNeg: if (myExpr->getType ()->getKind () == Type::tInt) { if (int_t (static_cast(*v)) == INT_T_MIN) { valuation.flag (errOver, *this); delete v; return NULL; } static_cast(v)->setValue (-int_t (static_cast(*v))); static_cast(v)->setType (*getType ()); return constrain (valuation, v); } else { if (card_t (static_cast(*v)) > card_t (INT_T_MAX) + 1) { valuation.flag (errOver, *this); delete v; return NULL; } static_cast(v)->setValue (-card_t (static_cast(*v))); static_cast(v)->setType (*getType ()); return constrain (valuation, v); } case uNot: static_cast(v)->setValue (~card_t (static_cast(*v))); return constrain (valuation, v); case uSucc: v->increment (); return v; case uPred: v->decrement (); return v; } assert (false); delete v; return NULL; } class Expression* UnopExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* e = myExpr->ground (valuation, transition, declare); if (!e) return NULL; assert (valuation.isOK ()); if (e == myExpr) { e->destroy (); return copy (); } else { class Expression* expr = new class UnopExpression (myOp, *e); expr->setType (*getType ()); return expr->ground (valuation); } } class Expression* UnopExpression::substitute (class Substitution& substitution) { class Expression* e = myExpr->substitute (substitution); if (e == myExpr) { e->destroy (); return copy (); } else return (new class UnopExpression (myOp, *e))->cse (); } bool UnopExpression::depends (const class VariableSet& vars, bool complement) const { return myExpr->depends (vars, complement); } bool UnopExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myExpr->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" void UnopExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { char* rvalue; class StringBuffer& out = cexpr.getOut (); if (cexpr.getVariable (*myExpr, rvalue)) myExpr->compile (cexpr, indent, rvalue, vars); switch (myOp) { case uNeg: out.indent (indent); out.append ("if ("); out.append (rvalue); switch (getType ()->getKind ()) { case Type::tInt: out.append ("==INT_MIN"); break; case Type::tCard: out.append (">INT_MAX"); break; default: assert (false); } out.append (")\n"); cexpr.compileError (indent + 2, errOver); out.indent (indent); out.append (lvalue); out.append ("=-"); out.append (rvalue); out.append (";\n"); break; case uNot: out.indent (indent); out.append (lvalue); out.append ("=~"); out.append (rvalue); out.append (";\n"); break; case uSucc: getType ()->compileSuccessor (out, indent, lvalue, rvalue, NULL); break; case uPred: getType ()->compilePredecessor (out, indent, lvalue, rvalue, NULL); break; } delete[] rvalue; if (myOp != uSucc && myOp != uPred) compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE /** Convert an operator to a string * @param op the operator to convert * @return a string corresponding to the operator */ inline static const char* getOpString (enum UnopExpression::Op op) { switch (op) { case UnopExpression::uNeg: return "-"; case UnopExpression::uNot: return "~"; case UnopExpression::uSucc: return "+"; case UnopExpression::uPred: return "|"; } return "???"; } /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eConstant: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eVectorIndex: case Expression::eNot: case Expression::eTypecast: case Expression::eUnop: case Expression::eBufferUnop: case Expression::eCardinality: return false; case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: assert (false); case Expression::eBooleanBinop: case Expression::eUnionType: case Expression::eIfThenElse: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eStruct: case Expression::eUnion: case Expression::eVector: case Expression::eBinop: case Expression::eRelop: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: case Expression::eStructAssign: case Expression::eVectorAssign: case Expression::eVectorShift: break; } return true; } void UnopExpression::display (const class Printer& printer) const { printer.printRaw (::getOpString (myOp)); if (::needParentheses (myExpr->getKind ())) { printer.delimiter ('(')++; myExpr->display (printer); --printer.delimiter (')'); } else myExpr->display (printer); } maria-1.3.5/Expression/UnopExpression.h0000644000175000017500000001114107722340370020272 0ustar msmakelamsmakela// unary operator class -*- c++ -*- #ifndef UNOPEXPRESSION_H_ # define UNOPEXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file UnopExpression.h * Unary operators for integer and other arithmetics */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Unary operator expression */ class UnopExpression : public Expression { public: /** Unary operators */ enum Op { uNeg, ///< Integer negation (two's complement) uNot, ///< Bitwise negation (one's complement) uSucc, ///< Successor uPred ///< Predecessor }; /** Constructor * @param op Operator * @param expr Expression the operator is applied to */ UnopExpression (enum Op op, class Expression& expr); private: /** Copy constructor */ UnopExpression (const class UnopExpression& old); /** Assignment operator */ class UnopExpression& operator= (const class UnopExpression& old); protected: /** Destructor */ ~UnopExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eUnop; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class UnopExpression& other) const { return myOp == other.myOp && *myExpr == *other.myExpr; } /** Ordering comparison operator */ bool operator< (const class UnopExpression& other) const { if (myOp < other.myOp) return true; if (other.myOp < myOp) return false; return *myExpr < *other.myExpr; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The operator */ enum Op myOp; /** The subexpression */ class Expression* myExpr; }; #endif // UNOPEXPRESSION_H_ maria-1.3.5/Expression/Variable.C0000644000175000017500000001652707725066510016772 0ustar msmakelamsmakela// variable reference class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Variable.h" #include "Valuation.h" #include "Value.h" #include "VariableDefinition.h" #include "VariableSet.h" #include "Constant.h" #include "Substitution.h" #include "Printer.h" #include "Transition.h" #include "util.h" #include "Printer.h" #include /** @file Variable.C * Variable reference */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Variable::Variable (const class VariableDefinition& variable, bool pred) : Expression (), myVariable (&variable), myPred (pred) { setType (myVariable->getType ()); assert (!pred || myVariable->getFather ()); } Variable::~Variable () { } void Variable::setType (const class Type& type) { assert (myVariable->getType ().isAlwaysAssignable (type)); Expression::setType (type); } class Value* Variable::do_eval (const class Valuation& valuation) const { const class Value* v = valuation.getValue (*myVariable); myVariable->flagReferenced (true); assert (!v || v->getType ().isAssignable (*getType ())); if (v) return constrain (valuation, v->copy ()); else { valuation.flag (errVar, *this); return NULL; } } class Expression* Variable::ground (const class Valuation& valuation, class Transition* transition, bool declare) { if (myVariable->isAggregate ()) { const class Value* v = valuation.getValue (*myVariable); assert (!v || v->getType ().isAssignable (*getType ())); return v ? (new class Constant (*v->copy ()))->cse () : copy (); } else if (const class VariableDefinition* father = myVariable->getFather ()) { if (!transition) return 0; if (const class Value* v = valuation.getValue (*father)) { class StringBuffer buf; buf.append (myVariable->getName ()); buf.append ("["); class Printer printer; printer.setOutput (&buf); if (myPred) { class Value* vp = v->copy (); vp->decrement (); vp->display (printer); delete vp; } else v->display (printer); buf.append ("]"); const char* name = buf.getString (); if (const class VariableDefinition* var = transition->getVariable (name)) { if (&var->getType () != getType ()) return 0; return (new class Variable (*var))->cse (); } else if (declare) return (new class Variable (transition->addVariable (newString (name), *getType (), false, false)))->cse (); else return 0; } } return copy (); } class Expression* Variable::substitute (class Substitution& substitution) { class Expression* e = substitution.getExpr (*myVariable); assert (!e || e->isAssignable (*getType ())); return e ? e : copy (); } bool Variable::depends (const class VariableSet& vars, bool complement) const { return vars.contains (*myVariable) ? !complement : complement; } bool Variable::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data); } bool Variable::isCompatible (const class Value& value, const class Valuation& valuation) const { assert (&value.getType () == getType ()); if (const class Value* v = valuation.getValue (*myVariable)) return *v == value; else return true; } void Variable::getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const { assert (&value.getType () == getType ()); if (vars.contains (*myVariable) && !valuation.getValue (*myVariable)) valuation.setValue (*myVariable, *value.copy ()); } void Variable::getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const { if (!rvalues.contains (*myVariable)) { if (!lvalues) lvalues = new class VariableSet; lvalues->insert (*myVariable); } } #ifdef EXPR_COMPILE # include "CExpression.h" void Variable::compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const { assert (myVariable->getNumber () && lvalue); if (!vars.contains (*myVariable)) return; class StringBuffer& out = cexpr.getOut (); if (myVariable->isUndefined ()) { out.indent (indent); out.append ("ASSIGN (vars, "); out.append (myVariable->getNumber () - 1); out.append (");\n"); } char* name; cexpr.getVariable (*this, name); out.indent (indent); out.append (name); out.append ("="); out.append (lvalue); out.append (";\n"); delete[] name; } void Variable::compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const { if (!vars.contains (*myVariable)) return; class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append ("if ("); if (myVariable->isUndefined ()) { out.append ("ASSIGNED ("); out.append (cexpr.getValuation ()); out.append (", "); out.append (myVariable->getNumber () - 1); out.append (")&&\n"); } char* name; cexpr.getVariable (*this, name); if (!getType ()->compileEqual (out, indent + 4, name, value, false, !myVariable->isUndefined (), true, false)) out.append ("0"); out.append (")\n"); cexpr.compileError (indent + 2, errComp); delete[] name; } void Variable::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { class StringBuffer& out = cexpr.getOut (); char* rvalue = cexpr.isIterator (*myVariable); if (rvalue) goto gotName; assert (myVariable->getNumber ()); if (!vars || vars->contains (*myVariable)) { if (myVariable->isUndefined ()) { out.indent (indent); out.append ("if (!ASSIGNED ("); out.append (cexpr.getValuation ()); out.append (", "); out.append (myVariable->getNumber () - 1); out.append ("))\n"); cexpr.compileError (indent + 2, errVar); } cexpr.getVariable (*this, rvalue); gotName: if (strcmp (lvalue, rvalue)) { out.indent (indent); out.append (lvalue); out.append ("="); out.append (rvalue); out.append (";\n"); } delete[] rvalue; } else cexpr.compileError (indent, errVar); } #endif // EXPR_COMPILE void Variable::display (const class Printer& printer) const { if (const class VariableDefinition* father = myVariable->getFather ()) { printer.delimiter (myPred ? ':' : '.'); printer.print (myVariable->getName ()); printer.delimiter (' '); printer.print (father->getName ()); } else printer.print (myVariable->getName ()); } maria-1.3.5/Expression/Variable.h0000644000175000017500000001464307722340370017030 0ustar msmakelamsmakela// variable reference class -*- c++ -*- #ifndef VARIABLE_H_ # define VARIABLE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file Variable.h * Variable reference */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Variable reference */ class Variable : public Expression { public: /** Constructor * @param variable Identifies the variable * @param pred (for quantified variables) * flag: use a predecessor value of the quantifier */ Variable (const class VariableDefinition& variable, bool pred = false); private: /** Copy constructor */ Variable (const class Variable& old); /** Assignment operator */ class Variable& operator= (const class Variable& old); protected: /** Destructor */ ~Variable (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eVariable; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Determine the variable */ const class VariableDefinition& getVariable () const { return *myVariable; } /** Set the type of the expression and the variable */ void setType (const class Type& type); /** Equality comparison operator */ bool operator== (const class Variable& other) const { return myVariable == other.myVariable && myPred == other.myPred; } /** Ordering comparison operator */ bool operator< (const class Variable& other) const { if (myVariable < other.myVariable) return true; if (other.myVariable < myVariable) return false; return myPred < other.myPred; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute the variable with an expression, if possible * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Determine whether the expression is compatible with the specified value, * neglecting subexpressions that cannot be evaluated * @param value value the expression will be compared to * @param valuation variable substitutions * @return true if the expression is compatible with the value */ bool isCompatible (const class Value& value, const class Valuation& valuation) const; /** Unify variables from this expression * @param value the value the expression should evaluate to * @param valuation variable substitutions * @param vars the variables to unify */ void getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const; /** Determine which variables could be unified from this expression * @param rvalues variables unified so far * @param lvalues (output) variables that could be unified * @return variables that could be unified */ void getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const; # ifdef EXPR_COMPILE /** Generate lvalue gathering code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables * @param lvalue C expression referring to the value */ void compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const; /** Generate compatibility check code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables that have been unified * @param value C expression referring to the desired value */ void compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const; /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** Name of the variable */ const class VariableDefinition* myVariable; /** Flag: use a predecessor value of the quantifier */ bool myPred; }; #endif // VARIABLE_H_ maria-1.3.5/Expression/VariableSet.C0000644000175000017500000000254307643235733017443 0ustar msmakelamsmakela// set of variables -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "VariableSet.h" #include "VariableDefinition.h" /** @file VariableSet.C * Set of variables, a transient class used in preprocessing */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ bool VariableSet::contains (const class VariableDefinition& var) const { return mySet.find (&var) != const_cast(mySet).end (); } void VariableSet::insert (const class VariableDefinition& var) { mySet.insert (&var); } maria-1.3.5/Expression/VariableSet.h0000644000175000017500000000456107643235733017512 0ustar msmakelamsmakela// set of variables -*- c++ -*- #ifndef VARIABLESET_H_ # define VARIABLESET_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include /** @file VariableSet.h * Set of variables, a transient class used in preprocessing */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Set of variables */ class VariableSet { public: /** Variable set */ typedef std::set Set; /** Constant iterator to the variable set */ typedef Set::const_iterator const_iterator; /** Constructor */ VariableSet () : mySet () {} /** Copy constructor */ explicit VariableSet (const class VariableSet& old) : mySet (old.mySet) {} private: /** Assignment operator */ class VariableSet& operator= (const class VariableSet& old); public: /** Destructor */ ~VariableSet () {} /** Determine whether the set contains a variable * @param var variable to search * @return whether the set contains the variable */ bool contains (const class VariableDefinition& var) const; /** Insert a variable to the set * @param var variable to insert */ void insert (const class VariableDefinition& var); /** @name Accessors to the variable set */ /*@{*/ void clear () { mySet.clear (); } bool empty () const { return mySet.empty (); } size_t size () const { return mySet.size (); } const_iterator begin () const { return mySet.begin (); } const_iterator end () const { return mySet.end (); } /*@}*/ private: /** The set of variables */ Set mySet; }; #endif // VARIABLESET_H_ maria-1.3.5/Expression/VectorAssign.C0000644000175000017500000001656607722340370017653 0ustar msmakelamsmakela// Maria vector component assignment class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "VectorAssign.h" #include "VectorValue.h" #include "VectorType.h" #include "Printer.h" #include /** @file VectorAssign.C * Vector component assignment operation */ /* Copyright © 2001-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ VectorAssign::VectorAssign (class Expression& vect, class Expression& i, class Expression& item) : Expression (), myVector (vect), myIndex (i), myItem (item) { assert (myVector.getType () && myVector.getType ()->getKind () == Type::tVector); assert (myVector.isBasic () && myIndex.isBasic () && myItem.isBasic ()); const class VectorType& type = *static_cast(myVector.getType ()); assert (myItem.getType () && myItem.getType () == &type.getItemType ()); assert (myIndex.getType () && myIndex.getType () == &type.getIndexType ()); setType (type); } VectorAssign::~VectorAssign () { myVector.destroy (); myIndex.destroy (); myItem.destroy (); } class Value* VectorAssign::do_eval (const class Valuation& valuation) const { class Value* idx = myIndex.eval (valuation); if (!idx) return NULL; const class Type& indexType = static_cast(myVector.getType ())->getIndexType (); assert (idx->getType ().isAssignable (indexType)); assert (indexType.isConstrained (*idx)); card_t i = indexType.convert (*idx); assert (i < CARD_T_MAX && i < indexType.getNumValues ()); delete idx; class Value* vector = myVector.eval (valuation); if (!vector) return NULL; assert (&vector->getType () == myVector.getType ()); class Value*& v = static_cast(*vector)[i]; delete v; if (!(v = myItem.eval (valuation))) { delete vector; return NULL; } return constrain (valuation, vector); } class Expression* VectorAssign::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* vect = myVector.ground (valuation, transition, declare); if (!vect) return NULL; class Expression* i = myIndex.ground (valuation, transition, declare); if (!i) { vect->destroy (); return NULL; } class Expression* item = myItem.ground (valuation, transition, declare); if (!item) { vect->destroy (); i->destroy (); return NULL; } assert (valuation.isOK ()); if (vect == &myVector && i == &myIndex && item == &myItem) { vect->destroy (), i->destroy (), item->destroy (); return copy (); } else return static_cast (new class VectorAssign (*vect, *i, *item))->ground (valuation); } class Expression* VectorAssign::substitute (class Substitution& substitution) { class Expression* vect = myVector.substitute (substitution); class Expression* i = myIndex.substitute (substitution); class Expression* item = myItem.substitute (substitution); if (vect == &myVector && i == &myIndex && item == &myItem) { vect->destroy (), i->destroy (), item->destroy (); return copy (); } else return (new class VectorAssign (*vect, *i, *item))->cse (); } bool VectorAssign::depends (const class VariableSet& vars, bool complement) const { return myVector.depends (vars, complement) || myIndex.depends (vars, complement) || myItem.depends (vars, complement); } bool VectorAssign::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myVector.forExpressions (operation, data) && myIndex.forExpressions (operation, data) && myItem.forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" # include "Constant.h" void VectorAssign::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { myVector.compile (cexpr, indent, lvalue, vars); char* ixconv = 0; class StringBuffer& out = cexpr.getOut (); if (myIndex.getKind () != Expression::eConstant) { char* ixvalue = 0; if (cexpr.getVariable (myIndex, ixvalue)) myIndex.compile (cexpr, indent, ixvalue, vars); if (cexpr.getConverted (myIndex, ixconv)) myIndex.getType ()->compileConversion (out, indent, ixvalue, ixconv, false); delete[] ixvalue; } class StringBuffer item; item.append (lvalue); item.append (".a["); if (myIndex.getKind () == Expression::eConstant) item.append (myIndex.getType ()->convert (static_cast(myIndex).getValue ())); else item.append (ixconv); item.append ("]"); delete[] ixconv; myItem.compile (cexpr, indent, item.getString (), vars); compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE /** Determine whether an expression needs to be enclosed in parentheses * @param kind kind of the expression * @return whether parentheses are necessary */ inline static bool needParentheses (enum Expression::Kind kind) { switch (kind) { case Expression::eVariable: case Expression::eUndefined: case Expression::eStructComponent: case Expression::eUnionComponent: case Expression::eVectorIndex: case Expression::eVectorAssign: return false; case Expression::eCardinality: case Expression::eBuffer: case Expression::eBufferRemove: case Expression::eBufferWrite: case Expression::eBufferIndex: case Expression::eBinop: case Expression::eBooleanBinop: case Expression::eNot: case Expression::eRelop: case Expression::eSet: case Expression::eTemporalBinop: case Expression::eTemporalUnop: case Expression::eMarking: case Expression::eTransitionQualifier: case Expression::ePlaceContents: case Expression::eSubmarking: case Expression::eMapping: case Expression::eEmptySet: case Expression::eUnionType: case Expression::eUnion: case Expression::eStruct: case Expression::eStructAssign: assert (false); case Expression::eUnop: case Expression::eBufferUnop: case Expression::eConstant: case Expression::eIfThenElse: case Expression::eVector: case Expression::eVectorShift: case Expression::eTypecast: break; } return true; } void VectorAssign::display (const class Printer& printer) const { if (::needParentheses (myVector.getKind ())) { printer.delimiter ('(')++; myVector.display (printer); --printer.delimiter (')'); } else myVector.display (printer); printer.delimiter ('.'); printer.delimiter ('{')++; printer.delimiter ('[')++; myIndex.display (printer); --printer.delimiter (']'); myItem.display (printer); --printer.delimiter ('}'); } maria-1.3.5/Expression/VectorAssign.h0000644000175000017500000001131507722340370017703 0ustar msmakelamsmakela// Maria vector component assignment class -*- c++ -*- #ifndef VECTORASSIGN_H_ # define VECTORASSIGN_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file VectorAssign.h * Vector component assignment operation */ /* Copyright © 2001-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Vector component assignment */ class VectorAssign : public Expression { public: /** Constructor * @param vect the vector * @param i index of the item to be assigned to * @param item the replacement item */ VectorAssign (class Expression& vect, class Expression& i, class Expression& item); private: /** Copy constructor */ VectorAssign (const class VectorAssign& old); /** Assignment operator */ class VectorAssign& operator= (const class VectorAssign& old); protected: /** Destructor */ ~VectorAssign (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eVectorAssign; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class VectorAssign& other) const { return myVector == other.myVector && myIndex == other.myIndex && myItem == other.myItem; } /** Ordering comparison operator */ bool operator< (const class VectorAssign& other) const { if (myVector < other.myVector) return true; if (other.myVector < myVector) return false; if (myIndex < other.myIndex) return true; if (other.myIndex < myIndex) return false; return myItem < other.myItem; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The vector */ class Expression& myVector; /** Index of the item to be assigned to */ class Expression& myIndex; /** The replacement item */ class Expression& myItem; }; #endif // VECTORASSIGN_H_ maria-1.3.5/Expression/VectorExpression.C0000644000175000017500000002050707722340370020554 0ustar msmakelamsmakela// Maria vector expression class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "VectorExpression.h" #include "VectorValue.h" #include "Printer.h" #include /** @file VectorExpression.C * Vector constructor */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ VectorExpression::VectorExpression (const class VectorType& type) : Expression (), myComponents (NULL) { assert (type.getSize () > 0); myComponents = new class Expression*[type.getSize ()]; memset (myComponents, 0, type.getSize () * sizeof *myComponents); setType (type); } VectorExpression::~VectorExpression () { for (card_t i = static_cast(getType ())->getSize (); i--; ) myComponents[i]->destroy (); delete[] myComponents; } void VectorExpression::setType (const class Type& type) { assert (type.getKind () == Type::tVector); const class Type& itemType = static_cast(type).getItemType (); for (card_t i = static_cast(type).getSize (); i--; ) if (myComponents[i]) myComponents[i]->setType (itemType); Expression::setType (type); } class Value* VectorExpression::do_eval (const class Valuation& valuation) const { class VectorValue* vector = new class VectorValue (*getType ()); for (card_t i = static_cast(getType ())->getSize (); i--; ) { assert (!!myComponents[i]); if (class Value* v = myComponents[i]->eval (valuation)) { assert (&v->getType () == &static_cast (getType ())->getItemType ()); (*vector)[i] = v; } else { delete vector; return NULL; } } return constrain (valuation, vector); } class Expression* VectorExpression::ground (const class Valuation& valuation, class Transition* transition, bool declare) { bool same = true; const class VectorType* const type = static_cast(getType ()); class VectorExpression* expr = new class VectorExpression (*type); for (card_t i = static_cast(getType ())->getSize (); i--; ) { assert (!!myComponents[i]); class Expression* e = myComponents[i]->ground (valuation, transition, declare); if (!e) { expr->destroy (); return NULL; } assert (valuation.isOK ()); if (e != myComponents[i]) same = false; expr->myComponents[i] = e; } if (same) { expr->destroy (); return copy (); } return static_cast(expr)->ground (valuation); } class Expression* VectorExpression::substitute (class Substitution& substitution) { bool same = true; const class VectorType* const type = static_cast(getType ()); class VectorExpression* expr = new class VectorExpression (*type); for (card_t i = static_cast(getType ())->getSize (); i--; ) { assert (!!myComponents[i]); class Expression* e = myComponents[i]->substitute (substitution); if (e != myComponents[i]) same = false; expr->myComponents[i] = e; } if (same) { expr->destroy (); return copy (); } else return expr->cse (); } bool VectorExpression::depends (const class VariableSet& vars, bool complement) const { for (card_t i = static_cast(getType ())->getSize (); i--; ) { assert (!!myComponents[i]); if (myComponents[i]->depends (vars, complement)) return true; } return false; } bool VectorExpression::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { if (!(*operation) (*this, data)) return false; for (card_t i = static_cast(getType ())->getSize (); i--; ) { assert (!!myComponents[i]); if (!myComponents[i]->forExpressions (operation, data)) return false; } return true; } bool VectorExpression::isCompatible (const class Value& value, const class Valuation& valuation) const { assert (value.getKind () == Value::vVector && value.getType ().getKind () == Type::tVector); const class VectorValue& vv = static_cast(value); const class VectorType* vt = static_cast(getType ()); assert (vv.getSize () == static_cast(vv.getType ()).getSize ()); if (!vv.getType ().isAssignable (*getType ())) return false; for (card_t i = vt->getSize (); i--; ) if (!myComponents[i]->isCompatible (vv[i], valuation)) return false; return true; } void VectorExpression::getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const { assert (value.getKind () == Value::vVector); assert (&value.getType () == getType ()); const class VectorValue& vv = static_cast(value); for (card_t i = static_cast(getType ())->getSize (); i--; ) myComponents[i]->getLvalues (vv[i], valuation, vars); } void VectorExpression::getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const { for (card_t i = static_cast(getType ())->getSize (); i--; ) myComponents[i]->getLvalues (rvalues, lvalues); } #ifdef EXPR_COMPILE # include "CExpression.h" # include void VectorExpression::compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const { assert (!!lvalue); const size_t len = strlen (lvalue); char* const newlvalue = new char[len + 25]; char* const suffix = newlvalue + len; memcpy (newlvalue, lvalue, len); const card_t size = static_cast(getType ())->getSize (); for (card_t i = 0; i < size; i++) { snprintf (suffix, 25, ".a[%u]", i); myComponents[i]->compileLvalue (cexpr, indent, vars, newlvalue); } delete[] newlvalue; } void VectorExpression::compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const { const size_t len = strlen (value); char* const val = new char[len + 25]; char* const suffix = val + len; memcpy (val, value, len); const card_t size = static_cast(getType ())->getSize (); for (card_t i = 0; i < size; i++) { snprintf (suffix, 25, ".a[%u]", i); myComponents[i]->compileCompatible (cexpr, indent, vars, val); } delete[] val; } void VectorExpression::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { size_t len = strlen (lvalue); char* const newlvalue = new char[len + 25]; char* const suffix = newlvalue + len; memcpy (newlvalue, lvalue, len); for (card_t i = 0; i < static_cast(getType ())->getSize (); i++) { snprintf (suffix, 25, ".a[%u]", i); myComponents[i]->compile (cexpr, indent, newlvalue, vars); } delete[] newlvalue; compileConstraint (cexpr, indent, lvalue); } #endif // EXPR_COMPILE void VectorExpression::display (const class Printer& printer) const { const class VectorType* type = static_cast(getType ()); printer.delimiter ('{')++; for (card_t i = 0;;) { assert (!!myComponents[i]); myComponents[i]->display (printer); if (++i == type->getSize ()) break; printer.delimiter (','); } --printer.delimiter ('}'); } maria-1.3.5/Expression/VectorExpression.h0000644000175000017500000001711007722340370020615 0ustar msmakelamsmakela// Maria vector expression class -*- c++ -*- #ifndef VECTOREXPRESSION_H_ # define VECTOREXPRESSION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" # include "VectorType.h" # include /** @file VectorExpression.h * Vector constructor */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Vector initialization expression */ class VectorExpression : public Expression { public: /** Constructor * @param type Type of the expression */ VectorExpression (const class VectorType& type); private: /** Copy constructor */ VectorExpression (const class VectorExpression& old); /** Assignment operator */ class VectorExpression& operator= (const class VectorExpression& old); protected: /** Destructor */ ~VectorExpression (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eVector; } /** Set the type of the expression * @param type Type of the expression */ void setType (const class Type& type); /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Address a component by index */ const class Expression& operator[] (card_t i) const { return *myComponents[i]; } /** Assign to a component * @param i Index to the component * @param component The component expression */ void setComponent (card_t i, class Expression& component) { assert (!myComponents[i]); assert (component.isBasic ()); (myComponents[i] = &component)->setType (static_cast(getType ())->getItemType ()); } /** Equality comparison operator */ bool operator== (const class VectorExpression& other) const { const class VectorType* v = static_cast(getType ()); const class VectorType* u = static_cast(other.getType ()); if (v->getSize () != u->getSize ()) return false; for (card_t i = v->getSize (); i--; ) { assert (myComponents[i] && other.myComponents[i]); if (!(*(myComponents[i]) == *(other.myComponents[i]))) return false; } return true; } /** Ordering comparison operator */ bool operator< (const class VectorExpression& other) const { const class VectorType* v = static_cast(getType ()); const class VectorType* u = static_cast(other.getType ()); if (v->getSize () < u->getSize ()) return true; if (u->getSize () < v->getSize ()) return false; for (card_t i = v->getSize (); i--; ) { assert (myComponents[i] && other.myComponents[i]); if (*(myComponents[i]) < *(other.myComponents[i])) return true; else if (*(other.myComponents[i]) < *(myComponents[i])) return false; } return false; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; /** Determine whether the expression is compatible with the specified value, * neglecting subexpressions that cannot be evaluated * @param value value the expression will be compared to * @param valuation variable substitutions * @return true if the expression is compatible with the value */ bool isCompatible (const class Value& value, const class Valuation& valuation) const; /** Unify variables from this expression * @param value the value the expression should evaluate to * @param valuation variable substitutions * @param vars the variables to unify */ void getLvalues (const class Value& value, class Valuation& valuation, const class VariableSet& vars) const; /** Determine which variables could be unified from this expression * @param rvalues variables unified so far * @param lvalues (output) variables that could be unified * @return variables that could be unified */ void getLvalues (const class VariableSet& rvalues, class VariableSet*& lvalues) const; # ifdef EXPR_COMPILE /** Generate lvalue gathering code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables * @param lvalue C expression referring to the value */ void compileLvalue (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* lvalue) const; /** Generate compatibility check code * @param cexpr the compilation * @param indent level of indentation * @param vars the variables that have been unified * @param value C expression referring to the desired value */ void compileCompatible (class CExpression& cexpr, unsigned indent, const class VariableSet& vars, const char* value) const; /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The expressions for the vector components */ class Expression** myComponents; }; #endif // VECTOREXPRESSION_H_ maria-1.3.5/Expression/VectorIndex.C0000644000175000017500000001261507722340370017465 0ustar msmakelamsmakela// Maria vector indexing expression -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "VectorIndex.h" #include "VectorType.h" #include "VectorValue.h" #include "Valuation.h" #include "VariableDefinition.h" #include "Printer.h" /** @file VectorIndex.C * Vector indexing operation */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ VectorIndex::VectorIndex (class Expression& vector, class Expression& i) : Expression (), myVector (&vector), myIndex (&i) { assert (myVector && myVector->getType ()); assert (myVector->getType ()->getKind () == Type::tVector); assert (myIndex && myIndex->getType ()); assert (myIndex->getType ()->isAssignable (static_cast(myVector->getType ()) ->getIndexType ())); assert (myVector->isBasic () && myIndex->isBasic ()); setType (static_cast(myVector->getType ()) ->getItemType ()); } VectorIndex::~VectorIndex () { myVector->destroy (); myIndex->destroy (); } class Value* VectorIndex::do_eval (const class Valuation& valuation) const { class Value* idx = myIndex->eval (valuation); if (!idx) return NULL; const class Type& indexType = static_cast(myVector->getType ()) ->getIndexType (); assert (idx->getType ().isAssignable (indexType)); assert (indexType.isConstrained (*idx)); card_t i = indexType.convert (*idx); assert (i < CARD_T_MAX && i < indexType.getNumValues ()); delete idx; class Value* vector = myVector->eval (valuation); if (!vector) return NULL; assert (&vector->getType () == myVector->getType ()); if (const class Value* v = (*static_cast(vector))[i]) { class Value* w = v->copy (); delete vector; return w; } else { assert (false); delete vector; return NULL; } } class Expression* VectorIndex::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* vector = myVector->ground (valuation, transition, declare); if (!vector) return NULL; class Expression* i = myIndex->ground (valuation, transition, declare); if (!i) { vector->destroy (); return NULL; } assert (valuation.isOK ()); if (vector == myVector && i == myIndex) { vector->destroy (); i->destroy (); return copy (); } else return static_cast (new class VectorIndex (*vector, *i))->ground (valuation); } class Expression* VectorIndex::substitute (class Substitution& substitution) { class Expression* vector = myVector->substitute (substitution); class Expression* i = myIndex->substitute (substitution); if (vector == myVector && i == myIndex) { vector->destroy (); i->destroy (); return copy (); } else return (new class VectorIndex (*vector, *i))->cse (); } bool VectorIndex::depends (const class VariableSet& vars, bool complement) const { return myVector->depends (vars, complement) || myIndex->depends (vars, complement); } bool VectorIndex::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myVector->forExpressions (operation, data) && myIndex->forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" # include "Constant.h" void VectorIndex::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { char* vvalue = 0; if (cexpr.getVariable (*myVector, vvalue)) myVector->compile (cexpr, indent, vvalue, vars); char* ixconv = 0; class StringBuffer& out = cexpr.getOut (); if (myIndex->getKind () != Expression::eConstant) { char* ixvalue = 0; if (cexpr.getVariable (*myIndex, ixvalue)) myIndex->compile (cexpr, indent, ixvalue, vars); if (cexpr.getConverted (*myIndex, ixconv)) myIndex->getType ()->compileConversion (out, indent, ixvalue, ixconv, false); delete[] ixvalue; } out.indent (indent); out.append (lvalue); out.append ("="); out.append (vvalue); out.append (".a["); if (myIndex->getKind () == Expression::eConstant) out.append (myIndex->getType ()->convert (static_cast(*myIndex).getValue ())); else out.append (ixconv); out.append ("];\n"); delete[] vvalue; delete[] ixconv; } #endif // EXPR_COMPILE void VectorIndex::display (const class Printer& printer) const { myVector->display (printer); printer.delimiter ('[')++; myIndex->display (printer); --printer.delimiter (']'); } maria-1.3.5/Expression/VectorIndex.h0000644000175000017500000001066007722340370017530 0ustar msmakelamsmakela// Maria vector indexing expression -*- c++ -*- #ifndef VECTORINDEX_H_ # define VECTORINDEX_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file VectorIndex.h * Vector indexing operation */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Vector indexing expression */ class VectorIndex : public Expression { public: /** Constructor * @param vector vector to be indexed * @param i the index */ VectorIndex (class Expression& vector, class Expression& i); private: /** Copy constructor */ VectorIndex (const class VectorIndex& old); /** Assignment operator */ class VectorIndex& operator= (const class VectorIndex& old); protected: /** Destructor */ ~VectorIndex (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eVectorIndex; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class VectorIndex& other) const { return *myVector == *other.myVector && *myIndex == *other.myIndex; } /** Ordering comparison operator */ bool operator< (const class VectorIndex& other) const { if (*myVector < *other.myVector) return true; if (*other.myVector < *myVector) return false; return *myIndex < *other.myIndex; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The vector expression */ class Expression* myVector; /** The index expression */ class Expression* myIndex; }; #endif // VECTORINDEX_H_ maria-1.3.5/Expression/VectorShift.C0000644000175000017500000001444007722340370017471 0ustar msmakelamsmakela// Maria vector shifter class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "VectorShift.h" #include "VectorValue.h" #include "LeafValue.h" #include "VectorType.h" #include "Printer.h" #include /** @file VectorShift.C * Vector shift operation */ /* Copyright © 2001-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ VectorShift::VectorShift (class Expression& vect, class Expression& amount) : Expression (), myVector (vect), myAmount (amount) { assert (myVector.getType () && myVector.getType ()->getKind () == Type::tVector); assert (myVector.isBasic () && myAmount.isBasic ()); assert (myAmount.getType () && myAmount.getType ()->getKind () == Type::tCard); setType (*myVector.getType ()); } VectorShift::~VectorShift () { myVector.destroy (); myAmount.destroy (); } class Value* VectorShift::do_eval (const class Valuation& valuation) const { class Value* v = myAmount.eval (valuation); if (!v) return NULL; assert (v->getKind () == Value::vLeaf); card_t i = card_t (*static_cast(v)); delete v; card_t size = static_cast(getType ())->getSize (); v = myVector.eval (valuation); assert (!v || &v->getType () == getType ()); if (!v || !(i %= size)) return v; class VectorValue& vector = *static_cast(v); class Value** t = new class Value*[i]; card_t j; for (j = i; j--; t[j] = vector[j]); for (j = 0; j < size - i; j++) vector[j] = vector[i + j]; for (j = i; j--; vector[size - i + j] = t[j]); delete[] t; return constrain (valuation, &vector); } class Expression* VectorShift::ground (const class Valuation& valuation, class Transition* transition, bool declare) { class Expression* vect = myVector.ground (valuation, transition, declare); if (!vect) return NULL; class Expression* amount = myAmount.ground (valuation, transition, declare); if (!amount) { vect->destroy (); return NULL; } assert (valuation.isOK ()); if (vect == &myVector && amount == &myAmount) { vect->destroy (), amount->destroy (); return copy (); } else return static_cast (new class VectorShift (*vect, *amount))->ground (valuation); } class Expression* VectorShift::substitute (class Substitution& substitution) { class Expression* vect = myVector.substitute (substitution); class Expression* amount = myAmount.substitute (substitution); if (vect == &myVector && amount == &myAmount) { vect->destroy (), amount->destroy (); return copy (); } else return (new class VectorShift (*vect, *amount))->cse (); } bool VectorShift::depends (const class VariableSet& vars, bool complement) const { return myVector.depends (vars, complement) || myAmount.depends (vars, complement); } bool VectorShift::forExpressions (bool (*operation) (const class Expression&,void*), void* data) const { return (*operation) (*this, data) && myVector.forExpressions (operation, data) && myAmount.forExpressions (operation, data); } #ifdef EXPR_COMPILE # include "CExpression.h" # include "Constant.h" # include "Net.h" # include "CardType.h" void VectorShift::compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const { myVector.compile (cexpr, indent, lvalue, vars); class StringBuffer& out = cexpr.getOut (); class StringBuffer amount; size_t size = static_cast(getType ())->getSize (); if (myAmount.getKind () == Expression::eConstant) { const class Value& v = static_cast(myAmount).getValue (); assert (v.getKind () == Value::vLeaf); amount.append (card_t (static_cast(v))); } else { class LeafValue v (Net::getCardType (), card_t (size)); char* var = 0; if (cexpr.getVariable (myAmount, var)) myAmount.compile (cexpr, indent, var, vars); out.indent (indent); out.append ("if ("); v.compileOrder (out, indent + 4, var, true, false, true, true); out.append (")\n"); cexpr.compileError (indent + 2, errShift); amount.append (var); delete[] var; } out.indent (indent); out.append ("if ("); out.append (amount); if (myAmount.getKind () != Expression::eConstant) out.append (" %= "), out.append (unsigned (size)); out.append (") {\n"); out.indent (indent + 2); static_cast(getType ()) ->getItemType ().appendName (out); out.append (" t["), out.append (amount), out.append ("];\n"); out.indent (indent + 2); out.append ("memcpy (t, "); out.append (lvalue), out.append (".a, sizeof t);\n"); out.indent (indent + 2); out.append ("memmove ("); out.append (lvalue), out.append (".a, "); out.append (lvalue), out.append (".a + "), out.append (amount); out.append (", ("); out.append (unsigned (size)), out.append (" - "), out.append (amount); out.append (") * sizeof *t);\n"); out.indent (indent + 2); out.append ("memcpy ("); out.append (lvalue), out.append (".a + "), out.append (unsigned (size)); out.append (" - "), out.append (amount), out.append (", t, "); out.append (amount); out.append (" * sizeof * t);\n"); compileConstraint (cexpr, indent + 2, lvalue); out.indent (indent); out.append ("}\n"); } #endif // EXPR_COMPILE void VectorShift::display (const class Printer& printer) const { myVector.display (printer); printer.printRaw ("<<"); myAmount.display (printer); } maria-1.3.5/Expression/VectorShift.h0000644000175000017500000001065407722340370017541 0ustar msmakelamsmakela// Maria vector shifter class -*- c++ -*- #ifndef VECTORSHIFT_H_ # define VECTORSHIFT_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Expression.h" /** @file VectorShift.h * Vector shift operation */ /* Copyright © 2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Vector shift */ class VectorShift : public Expression { public: /** Constructor * @param vect the vector to be shifted * @param amount number of items to shift */ VectorShift (class Expression& vect, class Expression& amount); private: /** Copy constructor */ VectorShift (const class VectorShift& old); /** Assignment operator */ class VectorShift& operator= (const class VectorShift& old); protected: /** Destructor */ ~VectorShift (); public: /** Determine the type of the expression */ enum Expression::Kind getKind () const { return eVectorShift; } /** Determine whether this is a basic expression */ bool isBasic () const { return true; } /** Determine whether this is a temporal logic expression */ bool isTemporal () const { return false; } /** Equality comparison operator */ bool operator== (const class VectorShift& other) const { return myVector == other.myVector && myAmount == other.myAmount; } /** Ordering comparison operator */ bool operator< (const class VectorShift& other) const { if (myVector < other.myVector) return true; if (other.myVector < myVector) return false; return myAmount < other.myAmount; } /** Evaluate the expression * @param valuation Variable substitutions * @return Value of the expression, or NULL in case of error */ class Value* do_eval (const class Valuation& valuation) const; /** Partially evaluate the expression using a valuation * @param valuation Variable substitutions * @param transition Transition for registering quantified variables * @param declare flag: declare new variables if required * @return grounded expression, or NULL in case of error */ class Expression* ground (const class Valuation& valuation, class Transition* transition, bool declare); /** Substitute some variables in the expression with expressions * @param substitution Variable substitutions * @return substituted expression */ class Expression* substitute (class Substitution& substitution); /** Determine whether the expression depends on a set of variables * @param vars the set of variables * @param complement flag: treat the set as its complement */ bool depends (const class VariableSet& vars, bool complement) const; /** Perform an operation on all subexpressions of the expression * @param operation operation to be performed (return false on failure) * @param data parameters to be passed to the operation * @return true if all operations succeeded */ bool forExpressions (bool (*operation) (const class Expression&,void*), void* data) const; # ifdef EXPR_COMPILE /** Generate C code for evaluating the expression * @param cexpr the compilation * @param indent indentation level * @param lvalue C expression referring to the lvalue * @param vars the variables that have been assigned a value */ void compile (class CExpression& cexpr, unsigned indent, const char* lvalue, const class VariableSet* vars) const; # endif // EXPR_COMPILE /** Display the expression * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The vector */ class Expression& myVector; /** Amount of items to shift */ class Expression& myAmount; }; #endif // VECTORSHIFT_H_ maria-1.3.5/Expression/allExpressions.h0000644000175000017500000000361607643235733020324 0ustar msmakelamsmakela/** @file allExpressions.h * Header file that includes all classes derived from Expression */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include "Typecast.h" #include "Variable.h" #include "Constant.h" #include "Undefined.h" #include "StructExpression.h" #include "StructComponent.h" #include "StructAssign.h" #include "UnionExpression.h" #include "UnionComponent.h" #include "UnionTypeExpression.h" #include "VectorExpression.h" #include "VectorIndex.h" #include "VectorAssign.h" #include "VectorShift.h" #include "UnopExpression.h" #include "BinopExpression.h" #include "BufferExpression.h" #include "BufferUnop.h" #include "BufferRemove.h" #include "BufferWrite.h" #include "BufferIndex.h" #include "IfThenElse.h" #include "BooleanBinop.h" #include "NotExpression.h" #include "RelopExpression.h" #include "SetExpression.h" #include "TemporalUnop.h" #include "TemporalBinop.h" #include "CardinalityExpression.h" #include "Marking.h" #include "TransitionQualifier.h" #include "PlaceContents.h" #include "Submarking.h" #include "Mapping.h" #include "EmptySet.h" maria-1.3.5/Graph/0000755000175000017500000000000010272511403014013 5ustar msmakelamsmakelamaria-1.3.5/Graph/BitBuffer.C0000644000175000017500000001013207643247662016011 0ustar msmakelamsmakela// Buffer for packing bits and values -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BitBuffer.h" #include "StructValue.h" #include "StructType.h" #include "UnionValue.h" #include "UnionType.h" #include "VectorValue.h" #include "VectorType.h" #include "BufferValue.h" #include "BufferType.h" #include "LeafValue.h" /** @file BitBuffer.C * Encoding and decoding numbers and values in bit strings */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ void BitPacker::append (const class Value& value) { card_t numValues = value.getType ().getNumValues (); assert (numValues); if (numValues == 1) return; if (numValues < CARD_T_MAX) append (value.getType ().convert (value), log2 (numValues)); else { switch (value.getKind ()) { case Value::vStruct: { const class StructValue& s = static_cast(value); for (unsigned i = 0; i < s.getSize (); i++) append (s[i]); } break; case Value::vUnion: { const class UnionValue& u = static_cast(value); if (unsigned bits = log2 (static_cast (u.getType ()).getSize ())) append (u.getIndex (), bits); append (u.getValue ()); } break; case Value::vVector: { const class VectorValue& v = static_cast(value); for (unsigned i = 0; i < v.getSize (); i++) append (v[i]); } break; case Value::vBuffer: { const class BufferValue& b = static_cast(value); card_t i = b.getCapacity (); append (i, log2 (static_cast(b.getType ()) .getSize () + 1)); while (i--) append (*b[i]); } break; case Value::vLeaf: append (card_t (static_cast(value)), CARD_T_BIT); break; } } } class Value* BitUnpacker::extract (const class Type& type) { card_t numValues = type.getNumValues (); assert (numValues); if (numValues == 1) return type.convert (card_t (0)); if (numValues < CARD_T_MAX) return type.convert (extract (log2 (numValues))); else { switch (type.getKind ()) { case Type::tStruct: { const class StructType& s = static_cast(type); class StructValue* sv = new class StructValue (type); for (unsigned i = 0; i < s.getSize (); i++) (*sv)[i] = extract (s[i]); return sv; } case Type::tUnion: { const class UnionType& u = static_cast(type); card_t i = u.getSize () > 1 ? extract (log2 (u.getSize ())) : 0; return new class UnionValue (type, i, *extract (u[i])); } case Type::tVector: { const class VectorType& v = static_cast(type); class VectorValue* vv = new class VectorValue (type); for (unsigned i = 0; i < v.getSize (); i++) (*vv)[i] = extract (v.getItemType ()); return vv; } case Type::tBuffer: { const class BufferType& b = static_cast(type); class BufferValue* bv = new class BufferValue (type); for (card_t i = extract (log2 (b.getSize () + 1)); i--; ) (*bv)[i] = extract (b.getItemType ()); return bv; } default: return new class LeafValue (type, extract (CARD_T_BIT)); } } } maria-1.3.5/Graph/BTree.C0000644000175000017500000003405507643247662015154 0ustar msmakelamsmakela// B-tree map of numbers to numbers -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BTree.h" #include #include #include /** @file BTree.C * B-tree map of numbers to numbers */ /* Copyright © 2000-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Size of a b-tree page, in bytes */ #define BTREE_PAGE_SIZE (sizeof (BTree::item_t) * BTREE_SIZE) /** Flag for leaf items */ #define BTREE_LEAF ~((~0u) >> 1) /** Determine the amount of keys in a B-tree node */ inline static unsigned keys (const BTree::item_t item) { return item & ~BTREE_LEAF; } /** Determine whether a B-tree node is a leaf node */ inline static bool isLeaf (const BTree::item_t item) { return item & BTREE_LEAF; } #ifdef USE_MMAP # define myRoot reinterpret_cast(myFile.addr) # define myNumPages (myFile.len / BTREE_PAGE_SIZE) /** Map a page from the file * @param f the file * @param page page number * @return the address of the page */ inline static BTree::item_t* mapPage (const file_t& f, unsigned page) { assert (page < f.len / BTREE_PAGE_SIZE); return reinterpret_cast(f.addr) + page * BTREE_SIZE; } #endif // USE_MMAP /** Read a page from the file * @param f the file * @param page page number * @param buf (output) the page buffer */ inline static void readPage (const file_t& f, unsigned page, BTree::item_t* buf) { #ifdef USE_MMAP assert (page < f.len / BTREE_PAGE_SIZE); memcpy (buf, static_cast(f.addr) + page * BTREE_PAGE_SIZE, BTREE_PAGE_SIZE); #else // USE_MMAP fseek (f, page * BTREE_PAGE_SIZE, SEEK_SET); fread (buf, BTREE_PAGE_SIZE, 1, f); #endif // USE_MMAP } /** Write a page without extending the file * @param f the file * @param page page number * @param buf the page buffer */ inline static void writePage (const file_t& f, unsigned page, const BTree::item_t* buf) { #ifdef USE_MMAP assert (page < f.len / BTREE_PAGE_SIZE); memcpy (static_cast(f.addr) + page * BTREE_PAGE_SIZE, buf, BTREE_PAGE_SIZE); #else // USE_MMAP fseek (f, page * BTREE_PAGE_SIZE, SEEK_SET); fwrite (buf, BTREE_PAGE_SIZE, 1, f); #endif } /** Write a page, extending the file if needed * @param f the file * @param page page number * @param buf the page buffer */ inline static void extendPage (file_t& f, unsigned page, const BTree::item_t* buf) { #ifdef USE_MMAP long offset = page * BTREE_PAGE_SIZE; assert (offset <= f.len); if (offset == f.len) { f.len += BTREE_PAGE_SIZE; if (f.len > f.alloc) { # ifdef NO_MMAP f.alloc *= 2; if (!(f.addr = realloc (f.addr, f.alloc))) { perror ("BTree: realloc"); abort (); } # else // NO_MMAP if (f.addr) munmap (f.addr, f.alloc); if (ftruncate (f.fd, f.alloc *= 2)) { perror ("BTree: ftruncate"); abort (); } if ((f.addr = # ifdef __sun (caddr_t) # endif // __sun mmap (0, f.alloc, PROT_READ | PROT_WRITE, MAP_SHARED, f.fd, 0)) == reinterpret_cast(MAP_FAILED)) { perror ("BTree: mmap"); abort (); } # endif // NO_MMAP } } memcpy (static_cast(f.addr) + page * BTREE_PAGE_SIZE, buf, BTREE_PAGE_SIZE); #else // USE_MMAP fseek (f, page * BTREE_PAGE_SIZE, SEEK_SET); if (1 != fwrite (buf, BTREE_PAGE_SIZE, 1, f)) { perror ("fwrite"); abort (); } #endif } /** Get the lower and upper bound for indexes containing a key * @param page a B-tree node * @param key the key to be sought * @param low (output) the lower bound, inclusive * @param high (output) the upper bound, inclusive * @return true if the key was found */ static bool searchBounds (const BTree::item_t* page, BTree::item_t key, unsigned& low, unsigned& high) { low = 1; high = keys (*page); if (!high) return false; assert (high >= low && high < BTREE_SIZE); // apply binary search to find coarse low and high bounds for the key for (;;) { const unsigned i = (low + high) >> 1; const BTree::item_t p = page[i]; if (p == key) { // set the lower bound for (low = i; --low >= 1 && page[low] == key; ); low++; // set the upper bound for (high = i; ++high <= keys (*page) && page[high] == key; ); high--; return true; } if (p < key) low = i + 1; else high = i - 1; if (high < low) return false; } } /** Search a leaf node * @param page a leaf node * @param key the key to be sought * @return the values (item 0: amount of the values) */ static BTree::item_t* searchLeaf (const BTree::item_t* page, BTree::item_t key) { assert (isLeaf (*page)); unsigned low, high; if (!searchBounds (page, key, low, high)) return 0; // compose the result BTree::item_t* result; high -= low - 1; *(result = new BTree::item_t[1 + high]) = high; memcpy (result + 1, &page[BTREE_SIZE / 2 + low], high * sizeof *result); return result; } #ifndef USE_MMAP /** Search the tree * @param page node to start the search from * @param key the key to be sought * @param file the B-tree file * @return the values (item 0: amount of the values) */ static BTree::item_t* search (BTree::item_t* page, BTree::item_t key, const file_t& file) { for (;;) { if (isLeaf (*page)) return searchLeaf (page, key); unsigned low, high; if (!searchBounds (page, key, low, high)) { assert (low <= keys (*page) + 1); assert (page[(BTREE_SIZE / 2 - 1) + low] > 0); readPage (file, page[(BTREE_SIZE / 2 - 1) + low], page); continue; } BTree::item_t* result = 0; for (; high >= low; high--) { BTree::item_t p[BTREE_SIZE]; readPage (file, page[(BTREE_SIZE / 2 - 1) + high], p); BTree::item_t* r = search (p, key, file); if (r) { if (!result) result = r; else { BTree::item_t* r2 = new BTree::item_t[*result + *r + 1]; *r2 = *result + *r; memcpy (r2 + 1, result + 1, *result * sizeof *result); memcpy (r2 + 1 + *result, r + 1, *r * sizeof *r); delete[] result; delete[] r; result = r2; } } } return result; } } #endif // !USE_MMAP /** Search the tree * @param page node to start the search from * @param key the key to be sought * @param file the B-tree file * @return the values (item 0: amount of the values) */ static BTree::item_t* search (const BTree::item_t* page, BTree::item_t key, const file_t& file) { #ifndef USE_MMAP BTree::item_t p[BTREE_SIZE], p2[BTREE_SIZE]; #endif // !USE_MMAP for (;;) { if (isLeaf (*page)) return searchLeaf (page, key); unsigned low, high; if (!searchBounds (page, key, low, high)) { assert (low <= keys (*page) + 1); assert (page[(BTREE_SIZE / 2 - 1) + low] > 0); #ifdef USE_MMAP page = mapPage (file, page[(BTREE_SIZE / 2 - 1) + low]); #else // USE_MMAP readPage (file, page[(BTREE_SIZE / 2 - 1) + low], p); page = p; #endif // USE_MMAP continue; } BTree::item_t* result = 0; for (high++; high >= low; high--) { #ifdef USE_MMAP BTree::item_t* r = search (mapPage (file, page[(BTREE_SIZE / 2 - 1) + high]), key, file); #else // USE_MMAP readPage (file, page[(BTREE_SIZE / 2 - 1) + high], p2); BTree::item_t* r = search (p2, key, file); #endif // USE_MMAP if (r) { if (!result) result = r; else { BTree::item_t* r2 = new BTree::item_t[*result + *r + 1]; *r2 = *result + *r; memcpy (r2 + 1, result + 1, *result * sizeof *result); memcpy (r2 + 1 + *result, r + 1, *r * sizeof *r); delete[] result; delete[] r; result = r2; } } } return result; } } /** Split a child node * @param parent the parent node * @param child the child node * @param i index of the child node in the parent node * @param parentpage page number of the parent node * @param childpage page number of the child node * @param numpages number of pages in the B-tree * @param file the B-tree file */ static void split (BTree::item_t* parent, BTree::item_t* child, unsigned i, #ifndef USE_MMAP unsigned parentpage, unsigned childpage, unsigned& numpages, #endif // !USE_MMAP file_t& file) { assert (keys (*child) == BTREE_SIZE / 2 - 1 && i && i - 1 <= keys (*parent)); BTree::item_t child2[BTREE_SIZE]; memset (child2, 0, BTREE_PAGE_SIZE); memcpy (child2 + 1, child + (BTREE_SIZE / 4 + 1), (BTREE_SIZE / 4 - 1) * sizeof *child); memcpy (child2 + BTREE_SIZE / 2, child + (BTREE_SIZE * 3 / 4), (BTREE_SIZE / 4) * sizeof *child); if (isLeaf (*child)) { child[0] = (BTREE_SIZE / 4) | BTREE_LEAF; child2[0] = (BTREE_SIZE / 4 - 1) | BTREE_LEAF; } else child2[0] = child[0] = BTREE_SIZE / 4 - 1; if (i <= keys (*parent)) { memmove (parent + i + (BTREE_SIZE / 2 + 1), parent + i + BTREE_SIZE / 2, (keys (*parent) + 1 - i) * sizeof *parent); memmove (parent + i + 1, parent + i, (keys (*parent) + 1 - i) * sizeof *parent); } parent[i] = child[BTREE_SIZE / 4]; parent[0]++; memset (child + (BTREE_SIZE / 4 + 1), 0, (BTREE_SIZE / 4 - 1) * sizeof *child); if (isLeaf (*child)) memset (child + (BTREE_SIZE * 3 / 4 + 1), 0, (BTREE_SIZE / 4 - 1) * sizeof *child); else memset (child + (BTREE_SIZE * 3 / 4), 0, (BTREE_SIZE / 4) * sizeof *child); #ifdef USE_MMAP extendPage (file, parent[BTREE_SIZE / 2 + i] = file.len / BTREE_PAGE_SIZE, child2); #else // USE_MMAP extendPage (file, childpage, child); extendPage (file, parent[BTREE_SIZE / 2 + i] = numpages++, child2); writePage (file, parentpage, parent); #endif // USE_MMAP } /** Insert to a non-full node * @param pagenbr page number of the node to insert to * @param key the key * @param value the value * @param root the root page * @param numpages number of pages in the B-tree * @param file the B-tree file */ static void insert (unsigned pagenbr, BTree::item_t key, BTree::item_t value, #ifndef USE_MMAP BTree::item_t* root, unsigned& numpages, #endif // !USE_MMAP file_t& file) { for (;;) { #ifdef USE_MMAP BTree::item_t* page = mapPage (file, pagenbr); #else // USE_MMAP BTree::item_t page[BTREE_SIZE]; if (!pagenbr) memcpy (page, root, BTREE_PAGE_SIZE); else readPage (file, pagenbr, page); #endif // USE_MMAP unsigned i = keys (*page); assert (i < BTREE_SIZE / 2 - 1); if (isLeaf (*page)) { // to do: apply binary search while (i && key <= page[i]) { page[i + 1] = page[i]; page[i + (BTREE_SIZE / 2 + 1)] = page[i + (BTREE_SIZE / 2)]; i--; } page[i + 1] = key; page[i + (BTREE_SIZE / 2 + 1)] = value; page[0]++; #ifndef USE_MMAP writePage (file, pagenbr, page); if (!pagenbr) memcpy (root, page, BTREE_PAGE_SIZE); #endif // USE_MMAP return; } // to do: apply binary search while (i && key <= page[i]) i--; unsigned childpagenbr = page[(BTREE_SIZE / 2) + i++]; assert (childpagenbr > 0); #ifdef USE_MMAP BTree::item_t* child = mapPage (file, childpagenbr); #else // USE_MMAP BTree::item_t child[BTREE_SIZE]; readPage (file, childpagenbr, child); #endif // USE_MMAP if (keys (*child) == (BTREE_SIZE / 2 - 1)) { split (page, child, i, #ifndef USE_MMAP pagenbr, childpagenbr, numpages, #endif // !USE_MMAP file); #ifdef USE_MMAP page = mapPage (file, pagenbr); #else // USE_MMAP if (!pagenbr) memcpy (root, page, BTREE_PAGE_SIZE); #endif // USE_MMAP if (key > page[i]) i++; pagenbr = page[(BTREE_SIZE / 2 - 1) + i]; assert (pagenbr > 0); } else pagenbr = childpagenbr; } } BTree::BTree (file_t file) : myFile (file) #ifndef USE_MMAP , myNumPages (1) #endif // USE_MMAP { #ifdef USE_MMAP if (myFile.len < long (BTREE_PAGE_SIZE)) { item_t root[BTREE_SIZE]; memset (root, 0, sizeof root); root[0] = BTREE_LEAF; extendPage (myFile, 0, root); } #else // USE_MMAP if (1 != fread (myRoot, BTREE_PAGE_SIZE, 1, myFile)) { memset (myRoot, 0, BTREE_PAGE_SIZE); myRoot[0] = BTREE_LEAF; extendPage (myFile, 0, myRoot); } #endif // USE_MMAP } BTree::~BTree () { #ifdef USE_MMAP # ifdef NO_MMAP if (myFile.addr) free (myFile.addr); # else // NO_MMAP if (myFile.addr) munmap (myFile.addr, myFile.alloc); if (myFile.fd != -1) { ftruncate (myFile.fd, myFile.len); close (myFile.fd); } # endif // NO_MMAP #else // USE_MMAP fclose (myFile); #endif // USE_MMAP } BTree::item_t* BTree::search (item_t key) const { return ::search (myRoot, key, myFile); } void BTree::insert (item_t key, item_t value) { if (keys (*myRoot) == BTREE_SIZE / 2 - 1) { item_t page[BTREE_SIZE]; memcpy (page, myRoot, BTREE_PAGE_SIZE); memset (myRoot, 0, BTREE_PAGE_SIZE); myRoot[0] = 0; #ifdef USE_MMAP unsigned last = myNumPages; extendPage (myFile, myRoot[BTREE_SIZE / 2] = last, page); ::split (myRoot, mapPage (myFile, last), 1, myFile); #else // USE_MMAP myRoot[BTREE_SIZE / 2] = myNumPages++; ::split (myRoot, page, 1, 0, myNumPages - 1, myNumPages, myFile); #endif // USE_MMAP } ::insert (0, key, value, #ifndef USE_MMAP myRoot, myNumPages, #endif // !USE_MMAP myFile); } void BTree::clear () { memset (myRoot, 0, sizeof (BTREE_PAGE_SIZE * sizeof *myRoot)); myRoot[0] = BTREE_LEAF; #ifdef USE_MMAP assert (myFile.len >= long (BTREE_PAGE_SIZE)); myFile.len = BTREE_PAGE_SIZE; #else // USE_MMAP myNumPages = 1; ::extendPage (myFile, 0, myRoot); #endif // USE_MMAP } maria-1.3.5/Graph/BTree.h0000644000175000017500000000505407643247662015216 0ustar msmakelamsmakela// B-tree map of numbers to numbers -*- c++ -*- #ifndef BTREE_H_ # define BTREE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "file.h" /** @file BTree.h * B-tree map of numbers to numbers */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Size of the b-tree nodes (must be at least 8 and divisible by 4) */ # define BTREE_SIZE 512 /** B-tree map of numbers to numbers */ class BTree { public: /** Type of the numbers to be stored */ typedef unsigned item_t; /** Constructor * @param file Disk file containing the B-tree */ explicit BTree (file_t file); private: /** Copy constructor */ BTree (const class BTree& old); /** Assignment operator */ class BTree& operator= (const class BTree& old); public: /** Destructor */ ~BTree (); /** Search a tree * @param key the key to be sought * @return the values (item 0: amount of the values) */ item_t* search (item_t key) const; /** Insert an item to the tree * @param key the key * @param value the value */ void insert (item_t key, item_t value); # ifdef USE_MMAP /** Close the file without truncating it */ void cleanup () { # ifdef NO_MMAP if (myFile.addr) free (myFile.addr); myFile.addr = 0; # else // NO_MMAP if (myFile.addr) munmap (myFile.addr, myFile.alloc); close (myFile.fd); myFile.addr = 0, myFile.fd = -1; # endif // NO_MMAP } # endif // USE_MMAP /** Truncate the file */ void clear (); private: /** The disk file containing the B-tree */ file_t myFile; # ifndef USE_MMAP /** Number of pages in the B-tree */ unsigned myNumPages; /** Copy of the root node of the B-tree */ item_t myRoot[BTREE_SIZE]; # endif // USE_MMAP }; #endif // BTREE_H_ maria-1.3.5/Graph/BitBuffer.h0000644000175000017500000002222407643247662016063 0ustar msmakelamsmakela// Buffer for packing bits and values -*- c++ -*- #ifndef BITBUFFER_H_ # define BITBUFFER_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ /** @file BitBuffer.h * Encoding and decoding numbers and values in bit strings */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ # include "typedefs.h" # include # include # if defined (__linux__) # include # if !defined BYTE_ORDER # define BYTE_ORDER __BYTE_ORDER # define LITTLE_ENDIAN __LITTLE_ENDIAN # define BIG_ENDIAN __BIG_ENDIAN # endif /* !defined BYTE_ORDER */ # elif defined (_AIX) # include # elif defined (__alpha) # include # elif defined (__sun) || defined (__hpux) # include # if !defined (BYTE_ORDER) # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # if !defined (_LITTLE_ENDIAN) && !defined (_BIG_ENDIAN) # ifdef ntohl # define _LITTLE_ENDIAN # else # define _BIG_ENDIAN # endif # endif # if defined (_LITTLE_ENDIAN) # define BYTE_ORDER LITTLE_ENDIAN # elif defined (_BIG_ENDIAN) # define BYTE_ORDER BIG_ENDIAN # endif // little/big endian # endif // !defined(BYTE_ORDER) # elif defined (__sgi) # include # include # elif !defined BYTE_ORDER # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # if defined __i386 # define BYTE_ORDER LITTLE_ENDIAN # else # error "cannot determine the byte order" # endif # endif /** Machine word */ # if (BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN) typedef unsigned long word_t; # else // middle-endian typedef unsigned char word_t; # endif // BYTE_ORDER /** Length of the machine word in bits */ # define WORD_T_BIT (CHAR_BIT * sizeof (word_t)) /** Buffer for packing bits */ class BitPacker { public: /** Constructor * @param increment Buffer allocation granularity (in WORD_T_BITs) */ explicit BitPacker (card_t increment = 16) : myBuf (0), myAllocated (0), myLength (0), myIncrement (increment) {} private: /** Copy constructor */ explicit BitPacker (const class BitPacker& old); /** Assignment operator */ class BitPacker& operator= (const class BitPacker& old); public: /** Destructor */ ~BitPacker () { delete[] myBuf; } /** Append data to the buffer * @param data Data to be appended * @param bits Length of data in bits */ void append (card_t data, unsigned bits) { assert (myIncrement); assert (bits && bits <= CARD_T_BIT); assert (bits == CARD_T_BIT || !(data >> bits)); // enlarge the buffer if necessary if (myLength + bits > myAllocated * WORD_T_BIT) { do myAllocated += myIncrement; while (myLength + bits > myAllocated * WORD_T_BIT); word_t* buf = new word_t[myAllocated]; size_t offset = (myLength + WORD_T_BIT - 1) / WORD_T_BIT; memcpy (buf, myBuf, offset * sizeof *buf); memset (buf + offset, 0, (myAllocated - offset) * sizeof *buf); delete[] myBuf; myBuf = buf; } // append the data to the buffer unsigned wordpos = myLength / WORD_T_BIT, bitpos = myLength % WORD_T_BIT; assert (!(myBuf[wordpos] >> bitpos)); myLength += bits; myBuf[wordpos] |= word_t (data) << bitpos; if (bitpos + bits > WORD_T_BIT) { bitpos = WORD_T_BIT - bitpos; myBuf[++wordpos] = data >>= bitpos; # if !(BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN) for (bits -= bitpos; bits > WORD_T_BIT; bits -= WORD_T_BIT) myBuf[++wordpos] = data >>= WORD_T_BIT; # endif } } /** Remove data from the buffer * @param bits number of bits to remove */ void remove (unsigned bits) { assert (myLength >= bits); myLength -= bits; // calculate the word and bit offsets unsigned wordpos = myLength / WORD_T_BIT, bitpos = myLength % WORD_T_BIT; // clear the remaining bits of the last word if (bitpos) myBuf[wordpos] &= (word_t (1) << bitpos) - 1; // clear the remaining whole words memset (myBuf + wordpos, 0, ((myLength + bits) / WORD_T_BIT - wordpos) * sizeof *myBuf); } /** Append a value to the buffer * @param value Value to be appended */ void append (const class Value& value); /** Clear the buffer */ void clear () { myLength = 0; memset (myBuf, 0, myAllocated * sizeof *myBuf); } /** Determine whether the buffer is empty */ bool empty () const { return myLength == 0; } /** Determine the length of the encoded data in bits */ unsigned getLength () const { return myLength; } /** Determine the length of the encoded data in blocks of bits * @param size the block size in bits * @return number of blocks */ unsigned getNumBlocks (unsigned size) const { return (myLength + size - 1) / size; } /** Determine the length of the encoded data in bytes */ unsigned getNumBytes () const { return getNumBlocks (CHAR_T_BIT); } /** Determine the length of the encoded data in words */ unsigned getNumWords () const { return getNumBlocks (WORD_T_BIT); } /** Get the buffer contents */ const word_t* getBuf () const { return myBuf; } /** Remove leading zero bytes from the last word */ void deflate () { # if BYTE_ORDER == BIG_ENDIAN if (myLength % WORD_T_BIT) deflate (myBuf[myLength / WORD_T_BIT], unsigned (-getNumBytes ()) % sizeof (word_t)); # endif // big endian } /** Restore leading zero bytes to the last word */ void inflate () { # if BYTE_ORDER == BIG_ENDIAN if (myLength % WORD_T_BIT) inflate (myBuf[myLength / WORD_T_BIT], unsigned (-getNumBytes ()) % sizeof (word_t)); # endif // big endian } /** Remove leading zero bytes from a word * @param word word to be deflated * @param bytes number of zero bytes to remove */ inline static void deflate (word_t& word, unsigned bytes) { assert (bytes < sizeof (word_t)); assert (!bytes || !(word & ~((word_t (1) << (WORD_T_BIT - CHAR_BIT * bytes)) - 1))); # if BYTE_ORDER == BIG_ENDIAN word <<= CHAR_BIT * bytes; # endif // big endian } /** Pad a deflated word with leading zero bytes * @param word word to be inflated * @param bytes number of zero bytes to add */ inline static void inflate (word_t& word, unsigned bytes) { assert (bytes < sizeof (word_t)); # if BYTE_ORDER == LITTLE_ENDIAN if (bytes) word &= (word_t (1) << (WORD_T_BIT - CHAR_BIT * bytes)) - 1; # elif BYTE_ORDER == BIG_ENDIAN word >>= CHAR_BIT * bytes; # endif } private: /** The buffer */ word_t* myBuf; /** Actual size of the buffer in WORD_T_BITs */ unsigned myAllocated; /** Number of bits used of the buffer */ unsigned myLength; /** Amount of WORD_T_BITs to allocate when more memory is needed */ unsigned myIncrement; }; /** Class for unpacking bits from a read-only buffer */ class BitUnpacker { public: /** Constructor for read-only access * @param buf a previously encoded string (read-only) */ explicit BitUnpacker (const word_t* buf) : myBuf (buf), myOffset (0) {} private: /** Copy constructor */ explicit BitUnpacker (const class BitUnpacker& old); /** Assignment operator */ class BitUnpacker& operator= (const class BitUnpacker& old); public: /** Destructor */ ~BitUnpacker () {} /** Read the number of decoded bits */ unsigned getNumBits () const { return myOffset; } /** Extract data from the encoded string * @param bits length of data in bits * @return the data */ card_t extract (unsigned bits) { assert (bits && bits <= CARD_T_BIT); unsigned wordpos = myOffset / WORD_T_BIT, bitpos = myOffset % WORD_T_BIT; myOffset += bits; const card_t mask = bits < CARD_T_BIT ? (card_t (1) << bits) - 1 : card_t (-1); card_t data = (myBuf[wordpos] >> bitpos) & mask; if (bitpos + bits > WORD_T_BIT) { bitpos = WORD_T_BIT - bitpos; data |= (card_t (myBuf[++wordpos]) << bitpos) & mask; # if !(BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN) for (bits -= bitpos, bitpos = WORD_T_BIT; bits > WORD_T_BIT; bits -= WORD_T_BIT, bitpos += WORD_T_BIT) data |= (card_t (myBuf[++wordpos]) << bitpos) & mask; # endif } return data; } /** Extract a value from the encoded string * @param type type of the value * @return the value */ class Value* extract (const class Type& type); private: /** the encoded bit string */ const word_t* const myBuf; /** offset to the encoded string */ unsigned myOffset; }; #endif // BITBUFFER_H_ maria-1.3.5/Graph/ByteBuffer.C0000644000175000017500000000214307643247662016201 0ustar msmakelamsmakela// Buffer for packing data in byte-aligned way -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "ByteBuffer.h" /** @file ByteBuffer.C * Encoding and decoding data in byte strings */ /* Copyright © 2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ maria-1.3.5/Graph/ByteBuffer.h0000644000175000017500000001615507643247662016256 0ustar msmakelamsmakela// Buffer for packing data in byte-aligned way -*- c++ -*- #ifndef BYTEBUFFER_H_ # define BYTEBUFFER_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ /** @file ByteBuffer.h * Encoding and decoding data in byte strings */ /* Copyright © 2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ # include # include /** Buffer for packing bytes */ class BytePacker { public: /** Constructor */ BytePacker () : myBuf (0), myLength (0), myAllocated (0) {} private: /** Copy constructor */ explicit BytePacker (const class BytePacker& old); /** Assignment operator */ class BytePacker& operator= (const class BytePacker& old); public: /** Destructor */ ~BytePacker () { delete[] myBuf; } /** Get the buffer */ const unsigned char* getBuf () const { return myBuf; } /** Get the buffer */ unsigned char* getBuf () { return myBuf; } /** Get the length of the buffer in bytes */ unsigned getLength () const { return myLength; } /** Set the length of the buffer in bytes */ void setLength (unsigned length) { assert (length <= myAllocated); myLength = length; } /** Get the allocated length of the buffer in bytes */ unsigned getAllocated () const { return myAllocated; } /** Empty the buffer */ void clear () { myLength = 0; } /** Determine how many bytes storage a number takes * @param num Number to be encoded * @return number of bytes required for encoding num */ static unsigned size (unsigned num) { if (num < 128) return 1; else if ((num -= 128) < (1 << 14)) return 2; else if ((num -= (1 << 14)) < (1 << 30)) return 4; else return assert (false), 0; } /** Append an unsigned integer to the buffer * @param num Number to be appended */ void append (unsigned num) { // variable-length code: // 0..127 0xxxxxxx // 128..16511 10xxxxxxxxxxxxxx // 16512..1073758335 11xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx unsigned char* s; if (num < 128) *extend (1) = num; else if ((num -= 128) < (1 << 14)) *(s = extend (2)) = 0x80 | (num >> 8), s[1] = num; else if ((num -= (1 << 14)) < (1 << 30)) { s = extend (4); s[3] = num; s[2] = num >>= 8; s[1] = num >>= 8; s[0] = (num >> 8) | 0xc0; } else assert (false); } /** Append a string of bytes to the buffer * @param buf the byte string * @param len length of the string in bytes */ void append (const void* buf, unsigned len) { memcpy (extend (len), buf, len); } /** Extend the allocation of the buffer, so that the unused space * is at least as long as specified * @param len minimum length of unused space */ void allocate (unsigned len) { if (myLength + len < myAllocated) return; if (!myAllocated) { assert (!myBuf && !myLength); for (myAllocated = 1; myAllocated < len; myAllocated <<= 1); myBuf = new unsigned char[myAllocated]; } else { assert (myAllocated && myBuf); for (; myAllocated < myLength + len; myAllocated <<= 1); unsigned char* buf = new unsigned char[myAllocated]; memcpy (buf, myBuf, myLength); delete[] myBuf; myBuf = buf; } } /** Extend the buffer by the specified number of bytes * @param len length to be added to the buffer * @return pointer to the beginning of the added area */ unsigned char* extend (unsigned len) { allocate (len); unsigned char* s = myBuf + myLength; myLength += len; return s; } private: /** The buffer */ unsigned char* myBuf; /** Length of the buffer in bytes */ unsigned myLength; /** Allocated length of the buffer in bytes */ unsigned myAllocated; }; /** Buffer for unpacking bytes from a read-only buffer */ class ByteUnpacker { public: /** Constructor for read-only access * @param buffer a previously encoded string (read-only) */ explicit ByteUnpacker (const void* buffer) : buf (static_cast(buffer)) {} private: /** Copy constructor */ explicit ByteUnpacker (const class ByteUnpacker& old); /** Assignment operator */ class ByteUnpacker& operator= (const class ByteUnpacker& old); public: /** Destructor */ ~ByteUnpacker () {} /** Extract an unsigned integer from the buffer */ unsigned extract () { const unsigned char* s = buf; switch (*s & 0xc0) { default: // 0..127 buf++; return *s; case 0x80: // 128..16511 buf += 2; return 128 + (((unsigned (*s) & 0x3f) << 8) | s[1]); case 0xc0: // 16512..1073758335 buf += 4; return 16512 + ((unsigned (*s & 0x3f) << 24) | (unsigned (s[1]) << 16) | (unsigned (s[2]) << 8) | s[3]); } } /** Extract an unsigned integer from a bounded buffer * @param p the buffer whose cursor this is * @param i (output) the extracted unsigned integer * @return true if enough data was available; false at EOF */ bool extract (const class BytePacker& p, unsigned& i) { if (!ensureData (p, 1)) return false; switch (*buf & 0xc0) { default: // 0..127 i = *buf++; return true; case 0x80: // 128..16511 if (!ensureData (p, 2)) return false; i = 128 + (((unsigned (*buf) & 0x3f) << 8) | buf[1]); buf += 2; return true; case 0xc0: // 16512..1073758335 if (!ensureData (p, 4)) return false; i = 16512 + ((unsigned (*buf & 0x3f) << 24) | (unsigned (buf[1]) << 16) | (unsigned (buf[2]) << 8) | buf[3]); buf += 4; return true; } } /** Ensure that enough data is available to be extracted * @param p the buffer whose cursor this is * @param numBytes number of bytes needed to extract * @return true if the data is available; false otherwise */ bool ensureData (const class BytePacker& p, unsigned numBytes) const { assert (buf >= p.getBuf ()); assert (buf <= p.getBuf () + p.getLength ()); return buf + numBytes <= p.getBuf () + p.getLength (); } /** Extract a string of bytes from the buffer * @param b (output) the byte string, previously allocated * @param len length of the string in bytes */ void extract (void* b, unsigned len) { memcpy (b, buf, len); buf += len; } /** The extraction buffer */ const unsigned char* buf; }; #endif // BYTEBUFFER_H_ maria-1.3.5/Graph/CompactSet.C0000644000175000017500000002750607643247662016220 0ustar msmakelamsmakela// Hash compacted storage of a reachable state set -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "CompactSet.h" #include "ByteBuffer.h" #include #include #include /** @file CompactSet.C * Transient, hash compacted reachability set storage */ /* Copyright © 2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Number of bits size_t holds */ #define SIZE_T_BIT (sizeof (size_t) * CHAR_BIT) /** primes[x] == prime closest to 32 << x */ static const unsigned primes[] = { 0x1f, 0x3d, 0x7f, 0x101, 0x1fd, 0x3fd, 0x805, 0xffd, 0x1fff, 0x3ffd, 0x8003, 0xfff1, 0x1ffff, 0x3fffb, 0x7ffff, 0xffffd, 0x1ffff7, 0x3ffffd, 0x7ffff1, 0xfffffd, 0x2000023, 0x3fffffb, 0x800001d, 0x10000003, 0x1ffffffd, 0x40000003, 0x7fffffff, 0xfffffffb }; // Begin imported code /* The following code is imported from utils/md5.c from dpkg-1.6.15. * This implementation of the MD5 algorithm was originally written by * Colin Plumb in 1993 and updated by Ian Jackson . * The original code is in the public domain. */ /** @name The four core functions - F1 is optimized somewhat */ /*@{*/ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /*@}*/ /** This is the central step in the MD5 algorithm. */ #define MD5STEP(f,w,x,y,z,in,s) \ (w += f(x,y,z) + in, w = (w<>(32-s)) + x) /** * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. * @param buf (input/output) the buffer for the hash value * @param in the data to be added to the hash value */ static void MD5Transform (unsigned buf[4], const unsigned in[16]) { register unsigned a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } // End imported code /** Compute an MD5 hash value, ignoring endianness * @param buf the data to be hashed * @param size the length of the data, in bytes * @param hash (output) the hash value (word-aligned) */ static void md5hash (const unsigned* buf, size_t size, unsigned hash[4]) { // initialize the hash value with the magic constants hash[0] = 0x67452301; hash[1] = 0xefcdab89; hash[2] = 0x98badcfe; hash[3] = 0x10325476; if (const unsigned blocks = size / (16 * sizeof (unsigned))) { // first transform the whole blocks for (const unsigned* const end = buf + blocks * 16; buf < end; buf += 16) MD5Transform (hash, buf); // subtract the transformed blocks from the size size %= 16 * sizeof (unsigned); } // pad the last block with a pattern consisting of 0x80 0x00 0x00 ... static unsigned lastbuf[16]; memcpy (lastbuf, buf, size); reinterpret_cast(lastbuf)[size] = 0x80; memset (reinterpret_cast(lastbuf) + size + 1, 0, (sizeof lastbuf) - (size + 1)); MD5Transform (hash, lastbuf); } CompactSet::CompactSet (unsigned size, unsigned width) : StateSet (), myNumCollisions (0), myHashSize (0), myHashWidth (width), myMajorHash (0), myMinorHash (0) { assert (size > 0); assert (width > 0 && width <= 16); /* round the hash table size to the closest prime in our table */ unsigned s; for (s = 0; s < ((sizeof primes) / sizeof *primes) - 1; s++) if (primes[s] >= size) break; const_cast(myHashSize) = primes[s]; } CompactSet::~CompactSet () { if (myMajorHash) free (myMajorHash); if (myMinorHash) free (myMinorHash); } bool CompactSet::init () { // nothing must have been initialized before assert (!myMajorHash && !myMinorHash && !getNumStates ()); // the major hash data type must be 1<<(1<(calloc (major * myHashSize, 1)))) return false; if (major == myHashWidth || (myMinorHash = static_cast (calloc ((myHashWidth - major) * myHashSize, 1)))) return true; if (myMajorHash) free (myMajorHash), myMajorHash = 0; return false; } bool CompactSet::do_add (const void* buf, size_t size) { if (myHashSize <= getNumStates ()) return false; // the hash table is full already /** The MD5 hash value of the data */ unsigned hash[4]; md5hash (static_cast(buf), size, hash); /** initial hash index */ unsigned h = hash[0] % myHashSize; /** the increment in the linear hash probing sequence */ const unsigned h2 = hash[1] % (myHashSize - 1) + 1; /** width of a hash entry in the major table, in bytes */ const unsigned major = myHashWidth & ~((sizeof *myMajorHash) - 1); for (unsigned probe = 0; probe < myHashSize; probe++, myNumCollisions++, h = (h + h2) % myHashSize) { if (major) { unsigned words = major / sizeof *myMajorHash; const unsigned* const m = &myMajorHash[h * words]; while (words--) { if (m[words]) { if (memcmp (reinterpret_cast(myMajorHash) + (h * major), hash, major)) goto noMatch; // no match in the major part if (myHashWidth - major && memcmp (myMinorHash + (h * (myHashWidth - major)), hash + major, myHashWidth - major)) goto noMatch; // no match in the minor part return false; // the state was already stored } } // the major part is empty, but is the minor part? if (unsigned minor = myHashWidth - major) for (const unsigned char* const m = &myMinorHash[h * minor]; minor--; ) if (m[minor]) goto noMatch; // both parts of the hash table entry are empty -> this is a new state // initialize the major part of the hash table entry at h memcpy (reinterpret_cast(myMajorHash) + (h * major), hash, major); } else { // there is no major part; compare the minor part only const unsigned char* const m = &myMinorHash[h * myHashWidth]; for (unsigned bytes = myHashWidth; bytes--; ) { if (m[bytes]) { if (memcmp (m, hash, myHashWidth)) goto noMatch; // no match -> probe again return false; // the state was already stored } } // the hash table entry is empty -> this is a new state } // initialize the hash table entry at h memcpy (myMinorHash + (h * (myHashWidth - major)), hash + major, myHashWidth - major); // update the statistics, the search list and the trace information newState (); assert (myPathFileLength == ftell (myPathFile)); assert (!myOffset || myOffset < myPathFileLength); mySearch.push (buf, size, myPathFileLength); { class BytePacker p; p.append (myOffset), p.append (size); fwrite (p.getBuf (), 1, p.getLength (), myPathFile); myPathFileLength += p.getLength () + size; } fwrite (buf, 1, size, myPathFile); return true; noMatch: continue; } /* the hash table is full */ return false; } word_t* CompactSet::getState (long pos, size_t* size) const { unsigned char rbuf[8]; class ByteUnpacker u (rbuf); assert (pos < myPathFileLength); fseek (myPathFile, pos, SEEK_SET); fread (rbuf, sizeof rbuf, 1, myPathFile); unsigned offset = u.extract (); unsigned len = u.extract (); u.buf = rbuf; word_t* state = new word_t[len + (sizeof (word_t) - 1) / sizeof (word_t)]; fseek (myPathFile, pos + BytePacker::size (offset) + BytePacker::size (len), SEEK_SET); fread (state, 1, len, myPathFile); *size = len; return state; } word_t* CompactSet::pop (bool tail, size_t& size) { if (mySearch.empty ()) return 0; return mySearch.pop (tail, myOffset, &size); } maria-1.3.5/Graph/CompactSet.h0000644000175000017500000000641007643247662016254 0ustar msmakelamsmakela// Hash compacted storage of a reachable state set -*- c++ -*- #ifndef COMPACTSET_H_ # define COMPACTSET_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "StateSet.h" /** @file CompactSet.h * Transient, hash compacted reachability set storage */ /* Copyright © 2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Hash compacted storage of a set of reachable states */ class CompactSet : public StateSet { public: /** Constructor * @param size number of elements in the hash table * @param width length of the compacted hash values in bytes */ CompactSet (unsigned size, unsigned width); private: /** Copy constructor */ CompactSet (const class CompactSet& old); /** Assignment operator */ class CompactSet& operator= (const class CompactSet& old); public: /** Destructor */ ~CompactSet (); /** Initialize the hash tables * @return true if the initialization succeeded */ bool init (); /** Get the number of hash collisions */ unsigned getNumCollisions () const { return myNumCollisions; } /** Get the size of the hash table */ unsigned getHashSize () const { return myHashSize; } private: /** Add a state to the graph * @param state the encoded state * @param size length of the encoded state, in bytes * @return true if the state was enqueued to mySearch */ bool do_add (const void* state, size_t size); protected: /** Get a deflated state from myPathFile * @param pos file offset to the state * @param size (output) length of the encoded state */ word_t* getState (long pos, size_t* size) const; public: /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @param size (output) length of the encoded stream * @return the encoded state */ word_t* pop (bool tail, size_t& size); private: /** Fetch a state from a counterexample path * @param u cursor to the counterexample path * @return the encoded state, inflated */ word_t* getState (class ByteUnpacker& u) const; /** Number of hash collisions */ unsigned myNumCollisions; /** Number of elements in the hash tables (a prime close to a power of 2) */ const unsigned myHashSize; /** Length of the compacted hash values in bytes */ const unsigned myHashWidth; /** The word-aligned part of hash table */ unsigned* myMajorHash; /** The octet-aligned part of the hash table */ unsigned char* myMinorHash; }; #endif // COMPACTSET_H_ maria-1.3.5/Graph/ComponentGraph.C0000644000175000017500000006345110232532245017057 0ustar msmakelamsmakela// Graph of strongly connected components -*- c++ -*- #ifdef __GNUC__ # pragma implementation # ifdef __sgi # define _XOPEN_SOURCE 1 # define _XOPEN_SOURCE_EXTENDED 1 # endif // __sgi #endif // __GNUC__ #include "ComponentGraph.h" #include "Graph.h" #include "BitVector.h" #include #include #include #include #if defined __digital__ # define fileno(f) ((f)->_file) #endif // __digital__ #if defined __CYGWIN__ # define fileno(f) __sfileno(f) #endif // __CYGWIN__ /** @file ComponentGraph.C * Graph of strongly connected components */ /* Copyright © 2000-2002,2005 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Tarjan state */ struct tarjan { /** reachability graph state */ card_t state; /** number of unprocessed successors */ unsigned numSucc; }; /** Stack for Tarjan's algorithm */ typedef std::list TarjanStack; /** Component directory entry */ struct compdirent { /** Number of states in the component */ card_t numStates; /** Offset to the state numbers of the component (or FPOS_NONE) */ Graph::fpos_t statePos; /** Offset to the successor arcs of the component (or FPOS_NONE) */ Graph::fpos_t succPos; /** Offset to the first predecessor arc record (or FPOS_NONE) */ Graph::fpos_t predPos; }; /** Predecessor arc entry */ struct predent { /** Offset to the next predecessor position (or FPOS_NONE) */ Graph::fpos_t nextPos; /** Number of the predecessor component */ card_t comp; }; #ifdef NO_MMAP /** an empty file structure */ # define NULL_F { 0, 0, 0 } /** pretend that mmapped files are always open */ # define isOpen(file) true #else // NO_MMAP # ifdef USE_MMAP /** an empty file structure */ # define NULL_F { -1, 0, 0, 0 } # else // USE_MMAP /** an empty file structure */ # define NULL_F 0 # endif // USE_MMAP /** Check if a file is open * @param file the file * @return true if the file has been opened */ static bool isOpen (const file_t& file) { # ifdef USE_MMAP return file.fd >= 0; # else // USE_MMAP return bool (file); # endif // USE_MMAP } #endif // NO_MMAP /** an empty file pointer */ static const file_t nofile = NULL_F; #ifdef USE_MMAP # ifndef NO_MMAP /** Open a temporary file * @param size desired length of the file in bytes * @return an opened file, or something on which isOpen() does not hold */ static file_t tempFile (size_t size) { FILE* file = tmpfile (); if (!file) { perror ("tmpfile"); return nofile; } file_t f; f.fd = dup (fileno (file)); fclose (file); if (f.fd < 0) { perror ("tempFile: dup"); return nofile; } f.len = 0; f.alloc = size; if (ftruncate (f.fd, f.alloc)) { perror ("tempFile: ftruncate"); close (f.fd); return nofile; } f.addr = # ifdef __sun (caddr_t) # endif // __sun mmap (0, f.alloc, PROT_READ | PROT_WRITE, MAP_SHARED, f.fd, 0); if (f.addr == reinterpret_cast(MAP_FAILED)) { close (f.fd); perror ("tempFile: mmap"); return nofile; } return f; } # endif // !NO_MMAP /** Extend a file * @param file the file */ static void extend (file_t& file) { assert (isOpen (file) && file.addr); if (file.len < file.alloc) return; # ifndef NO_MMAP if (file.addr) munmap (file.addr, file.alloc); # endif // !NO_MMAP while (file.alloc < file.len) { if (!(file.alloc *= 2)) { fputs ("extend: file size overflow\n", stderr); abort (); } } # ifdef NO_MMAP if (!(file.addr = realloc (file.addr, file.alloc))) { perror ("extend: realloc"); abort (); } # else // NO_MMAP if (ftruncate (file.fd, file.alloc)) { perror ("extend: ftruncate"); abort (); } file.addr = # ifdef __sun (caddr_t) # endif // __sun mmap (0, file.alloc, PROT_READ | PROT_WRITE, MAP_SHARED, file.fd, 0); if (file.addr == reinterpret_cast(MAP_FAILED)) { perror ("extend: mmap"); abort (); } # endif // NO_MMAP } #endif // USE_MMAP /** Close a temporary file * @param f the file to be closed */ static void closeFile (file_t& f) { #ifdef USE_MMAP # ifdef NO_MMAP if (f.addr) free (f.addr); # else // NO_MMAP munmap (f.addr, f.alloc); close (f.fd); # endif // NO_MMAP #else // USE_MMAP fclose (f); #endif // USE_MMAP } ComponentGraph::ComponentGraph (const class Graph& graph) : myGraph (graph), myNumComponents (0), myNumTerminals (0), myStateComponents (nofile), myComponentDirectory (nofile), myComponentStates (0), mySuccComponents (0), myPredComponents (0) { } ComponentGraph::~ComponentGraph () { if (isOpen (myStateComponents)) { assert (isOpen (myComponentDirectory)); assert (myComponentStates && mySuccComponents && myPredComponents); closeFile (myStateComponents); closeFile (myComponentDirectory); fclose (myComponentStates); fclose (mySuccComponents); fclose (myPredComponents); } } inline bool ComponentGraph::openFiles () { assert (!myNumComponents); assert (!isOpen (myStateComponents)); assert (!isOpen (myComponentDirectory)); assert (!myComponentStates); assert (!mySuccComponents); assert (!myPredComponents); #ifdef USE_MMAP if (!isOpen (myStateComponents = tempFile (myGraph.getNumStates () * sizeof (card_t)))); else if (!isOpen (myComponentDirectory = tempFile (getpagesize ()))) closeFile (myStateComponents), myStateComponents = nofile; #else // USE_MMAP if (!(myStateComponents = tmpfile ())) perror ("tmpfile"); else if (!(myComponentDirectory = tmpfile ())) perror ("tmpfile"), closeFile (myStateComponents), myStateComponents = nofile; #endif // USE_MMAP else if (!(myComponentStates = tmpfile ())) perror ("tmpfile"), closeFile (myStateComponents), closeFile (myComponentDirectory), myStateComponents = myComponentDirectory = nofile; else if (!(mySuccComponents = tmpfile ())) perror ("tmpfile"), closeFile (myStateComponents), closeFile (myComponentDirectory), fclose (myComponentStates), myStateComponents = myComponentDirectory = nofile, myComponentStates = 0; else if (!(myPredComponents = tmpfile ())) perror ("tmpfile"), closeFile (myStateComponents), closeFile (myComponentDirectory), fclose (myComponentStates), fclose (mySuccComponents), myStateComponents = myComponentDirectory = nofile, myComponentStates = mySuccComponents = 0; else return true; return false; } inline void ComponentGraph::setComponent (card_t state, card_t comp) { #ifdef USE_MMAP assert (size_t (myStateComponents.alloc) >= (state + 1) * sizeof state); reinterpret_cast(myStateComponents.addr)[state] = ++comp; #else // USE_MMAP fseek (myStateComponents, state * sizeof state, SEEK_SET); fwrite (&++comp, sizeof comp, 1, myStateComponents); #endif // USE_MMAP } /** Flag: has the analysis been interrupted? */ extern volatile bool interrupted; inline void ComponentGraph::computeArcs () { assert (myNumComponents); assert (!ftell (mySuccComponents) && !ftell (myPredComponents)); /** successor and predecessor components */ std::set succComp, predComp; for (unsigned comp = 0; comp < myNumComponents; comp++) { card_t* states = getStates (comp); assert (states && *states); for (; *states; (*states)--) { card_t s; for (Graph::fpos_t pos = myGraph.getPredecessors (states[*states]); pos != FPOS_NONE;) { s = getComponent (myGraph.getPredecessor (pos)); if (s != CARD_T_MAX && s != comp) predComp.insert (s); } if (card_t* succ = myGraph.getSuccessors (states[*states])) { for (assert (*succ > 0); *succ; (*succ)--) { s = getComponent (succ[*succ]); if (s != CARD_T_MAX && s != comp) succComp.insert (s); } delete[] succ; } } delete[] states; if (succComp.empty ()) myNumTerminals++; #ifdef USE_MMAP struct compdirent& ent = reinterpret_cast(myComponentDirectory.addr)[comp]; assert (size_t (myComponentDirectory.len) >= (comp + 1) * sizeof ent); #else // USE_MMAP struct compdirent ent; fseek (myComponentDirectory, comp * sizeof ent, SEEK_SET); if (1 != fread (&ent, sizeof ent, 1, myComponentDirectory)) return; #endif // USE_MMAP assert (ent.numStates && ent.statePos != FPOS_NONE && ent.succPos == FPOS_NONE && ent.predPos == FPOS_NONE); std::set::const_iterator i; ent.succPos = ftell (mySuccComponents); for (i = succComp.begin (); i != succComp.end (); i++) fwrite (&*i, sizeof *i, 1, mySuccComponents); ent.predPos = ftell (myPredComponents); for (i = predComp.begin (); i != predComp.end (); i++) fwrite (&*i, sizeof *i, 1, myPredComponents); #ifndef USE_MMAP fseek (myComponentDirectory, -sizeof ent, SEEK_CUR); fwrite (&ent, sizeof ent, 1, myComponentDirectory); #endif // !USE_MMAP succComp.clear (); predComp.clear (); } } #ifndef USE_MMAP /** Write a strongly connected component * @param compDirectory stronly connected component directory * @param compStates file containing the component state numbers * @param stateComps map from state numbers to component numbers * @param visited states that have been visited * @param processed states that have been processed * @param st the search stack * @param stsize size of the search stack * @param root number of the root state of the component * @param num number of the component * @return new size of the search stack */ inline unsigned writeComponent (FILE* compDirectory, FILE* compStates, FILE* stateComps, class BitVector& visited, class BitVector& processed, const card_t* st, unsigned stsize, card_t root, unsigned num) { struct compdirent c = { 0, // number of states ftell (compStates), // offset to state numbers FPOS_NONE, // offset to successor component numbers FPOS_NONE // offset to predecessor component numbers }; assert (stsize > 0); assert (card_t (ftell (compDirectory)) == num * sizeof c); assert (!processed[root] || !visited[root]); num++; unsigned i = stsize; while (i--) { card_t state = st[i]; assert (!processed[state] || !visited[state]); fseek (stateComps, state * sizeof state, SEEK_SET); fwrite (&num, sizeof num, 1, stateComps); processed.assign (state, true); visited.assign (state, true); c.numStates++; if (state == root) break; assert (i > 0); } fwrite (st + i, sizeof *st, stsize - i, compStates); fwrite (&c, sizeof c, 1, compDirectory); return i; } #endif // !USE_MMAP /** Write a strongly connected component * @param compDirectory stronly connected component directory * @param compStates file containing the component state numbers * @param stateComps memory-based map from state to component numbers * @param visited states that have been visited * @param processed states that have been processed * @param st the search stack * @param stsize size of the search stack * @param root number of the root state of the component * @param num number of the component * @return new size of the search stack */ inline unsigned writeComponent (file_t& compDirectory, FILE* compStates, card_t* stateComps, class BitVector& visited, class BitVector& processed, const card_t* st, unsigned stsize, card_t root, unsigned num) { #ifdef USE_MMAP assert (card_t (compDirectory.len) == num * sizeof (struct compdirent)); compDirectory.len += sizeof (struct compdirent); extend (compDirectory); struct compdirent& c = reinterpret_cast(compDirectory.addr)[num]; #else // USE_MMAP struct compdirent c; assert (card_t (ftell (compDirectory)) == num * sizeof c); #endif // USE_MMAP c.numStates = 0; c.statePos = ftell (compStates); c.succPos = c.predPos = FPOS_NONE; assert (stsize > 0); assert (!processed[root] || !visited[root]); num++; unsigned i = stsize; while (i--) { card_t state = st[i]; assert (!processed[state] || !visited[state]); stateComps[state] = num; processed.assign (state, true); visited.assign (state, true); c.numStates++; if (state == root) break; assert (i > 0); } fwrite (st + i, sizeof *st, stsize - i, compStates); #ifndef USE_MMAP fwrite (&c, sizeof c, 1, compDirectory); #endif // !USE_MMAP return i; } unsigned ComponentGraph::compute (card_t state, const class Expression* cond) { assert (!myNumComponents); if (!myGraph.eval (state, cond) || !openFiles ()) return 0; /** Current and allocated length of the component stack */ unsigned cstsize = 0, cstalloc = 128; /** Component stack */ card_t* cst = new card_t[cstalloc]; TarjanStack st; /** Visited states */ class BitVector visited (myGraph.getNumStates ()); /** States belonging to a component */ class BitVector processed (myGraph.getNumStates ()); // Combinations for visited[state] and processed[state]: // initially 0 0 // visited in the search 1 0 // visited; depth adjusted 0 1 // processed component 1 1 #ifdef USE_MMAP /** Search depth numbers or component numbers */ card_t* const depths = reinterpret_cast(myStateComponents.addr); #else // USE_MMAP /** Search depth numbers (if insufficient memory, use get/setComponent) */ card_t* depths = reinterpret_cast(calloc (myGraph.getNumStates (), sizeof *depths)); #endif // USE_MMAP /** Search depth */ card_t depth = 1; /** Successor state numbers */ card_t* succ; while (!interrupted) { // compute a strongly connected component while (!interrupted) { assert (!processed[state] || !visited[state]); if (processed[state] || visited.tset (state)) break; // push the state on the component stack if (cstsize == cstalloc) { if (card_t* ncst = new card_t[cstalloc <<= 1]) { memcpy (ncst, cst, cstsize * sizeof *cst); delete[] cst; cst = ncst; } else { delete[] cst; #ifndef USE_MMAP free (depths); #endif // !USE_MMAP interrupted = true; return myNumComponents; } } cst[cstsize++] = state; // determine the successors of the state succ = myGraph.getSuccessors (state); #ifndef USE_MMAP if (depths) #endif // !USE_MMAP depths[state] = ++depth; #ifndef USE_MMAP else setComponent (state, depth++); #endif // !USE_MMAP struct tarjan t = { state, succ ? *succ : 0 }; for (; t.numSucc; t.numSucc--) { card_t s = succ[t.numSucc]; if (!(processed[s] && visited[s]) && myGraph.eval (s, cond)) { state = s; break; } } delete[] succ; st.push_front (t); } // backtrack while (!interrupted) { if (st.empty ()) { #ifndef USE_MMAP if (depths) { #endif // !USE_MMAP if (cstsize && ::writeComponent (myComponentDirectory, myComponentStates, depths, visited, processed, cst, cstsize, *cst, myNumComponents++)) assert (false); #ifndef USE_MMAP fseek (myStateComponents, 0, SEEK_SET); fwrite (depths, sizeof depths, myGraph.getNumStates (), myStateComponents); free (depths); } else if (cstsize && ::writeComponent (myComponentDirectory, myComponentStates, myStateComponents, visited, processed, cst, cstsize, *cst, myNumComponents++)) assert (false); #endif // !USE_MMAP delete[] cst; computeArcs (); return myNumComponents; } /** Minimum search depth in the state */ const card_t minDepth = processed[state] && visited[state] ? CARD_T_MAX #ifdef USE_MMAP : depths[state] - 1; #else // USE_MMAP : (depths ? (depths[state] - 1) : getComponent (state)); #endif // USE_MMAP struct tarjan& t = *st.begin (); state = t.state; #ifndef USE_MMAP if (depths) { #endif // !USE_MMAP if ((depths[state] - 1) > minDepth) { depths[state] = minDepth + 1; if (processed.tset (state)) assert (!visited[state]); else assert (visited[state]), visited.assign (state, false); } #ifndef USE_MMAP } else { if (getComponent (state) > minDepth) { setComponent (state, minDepth); if (processed.tset (state)) assert (!visited[state]); else assert (visited[state]), visited.assign (state, false); } } #endif // !USE_MMAP if (t.numSucc-- > 1) { succ = myGraph.getSuccessors (state); assert (succ && *succ > t.numSucc); for (; t.numSucc; t.numSucc--) { card_t s = succ[t.numSucc]; if (!(processed[s] && visited[s]) && myGraph.eval (s, cond)) { state = s; break; } } delete[] succ; if (t.numSucc) break; } st.pop_front (); if (processed[state]) continue; #ifdef USE_MMAP cstsize = ::writeComponent (myComponentDirectory, myComponentStates, depths, visited, processed, cst, cstsize, state, myNumComponents++); #else // USE_MMAP cstsize = depths ? ::writeComponent (myComponentDirectory, myComponentStates, depths, visited, processed, cst, cstsize, state, myNumComponents++) : ::writeComponent (myComponentDirectory, myComponentStates, myStateComponents, visited, processed, cst, cstsize, state, myNumComponents++); #endif // USE_MMAP } } delete[] cst; #ifndef USE_MMAP free (depths); #endif // !USE_MMAP return myNumComponents; } card_t ComponentGraph::getComponent (card_t state) const { #ifdef USE_MMAP assert (size_t (myStateComponents.alloc) >= (state + 1) * sizeof state); return reinterpret_cast(myStateComponents.addr)[state] - 1; #else // USE_MMAP fseek (myStateComponents, state * sizeof state, SEEK_SET); return 1 == fread (&state, sizeof state, 1, myStateComponents) ? --state : CARD_T_MAX; #endif // USE_MMAP } card_t* ComponentGraph::getStates (card_t comp) const { assert (comp < myNumComponents); #ifdef USE_MMAP struct compdirent& c = reinterpret_cast(myComponentDirectory.addr)[comp]; if (size_t (myComponentDirectory.len) < (comp + 1) * sizeof c || c.statePos == FPOS_NONE) return 0; #else // USE_MMAP struct compdirent c; fseek (myComponentDirectory, comp * sizeof c, SEEK_SET); if (1 != fread (&c, sizeof c, 1, myComponentDirectory) || c.statePos == FPOS_NONE) return 0; #endif // USE_MMAP assert (c.numStates && c.numStates <= myGraph.getNumStates ()); card_t* states = new card_t[c.numStates + 1]; fseek (myComponentStates, c.statePos, SEEK_SET); if (c.numStates != fread (states + 1, sizeof *states, c.numStates, myComponentStates)) { delete[] states; return 0; } *states = c.numStates; return states; } card_t ComponentGraph::getNumSucc (card_t comp) const { assert (comp < myNumComponents); #ifdef USE_MMAP const struct compdirent* c = reinterpret_cast(myComponentDirectory.addr) + comp; if (size_t (myComponentDirectory.len) < (comp + 1) * sizeof *c) return 0; if (c[0].succPos == FPOS_NONE) return CARD_T_MAX; if (size_t (myComponentDirectory.len) < (comp + 2) * sizeof *c) { fseek (mySuccComponents, 0, SEEK_END); return (ftell (mySuccComponents) - c[0].succPos) / sizeof (card_t); } #else // USE_MMAP struct compdirent c[2]; fseek (myComponentDirectory, comp * sizeof *c, SEEK_SET); switch (fread (c, sizeof *c, 2, myComponentDirectory)) { case 0: return 0; case 1: fseek (mySuccComponents, 0, SEEK_END); c[1].succPos = ftell (mySuccComponents); // fall through case 2: if (c[0].succPos == FPOS_NONE) return CARD_T_MAX; } #endif // USE_MMAP assert (c[0].succPos <= c[1].succPos); return (c[1].succPos - c[0].succPos) / sizeof (card_t); } card_t ComponentGraph::getNumPred (card_t comp) const { assert (comp < myNumComponents); #ifdef USE_MMAP const struct compdirent* c = reinterpret_cast(myComponentDirectory.addr) + comp; if (size_t (myComponentDirectory.len) < (comp + 1) * sizeof *c) return 0; if (c[0].predPos == FPOS_NONE) return CARD_T_MAX; if (size_t (myComponentDirectory.len) < (comp + 2) * sizeof *c) { fseek (myPredComponents, 0, SEEK_END); return (ftell (myPredComponents) - c[0].predPos) / sizeof (card_t); } #else // USE_MMAP struct compdirent c[2]; fseek (myComponentDirectory, comp * sizeof *c, SEEK_SET); switch (fread (c, sizeof *c, 2, myComponentDirectory)) { case 0: return 0; case 1: fseek (myPredComponents, 0, SEEK_END); c[1].predPos = ftell (myPredComponents); // fall through case 2: if (c[0].predPos == FPOS_NONE) return CARD_T_MAX; } #endif // USE_MMAP assert (c[0].predPos <= c[1].predPos); return (c[1].predPos - c[0].predPos) / sizeof (card_t); } card_t* ComponentGraph::getSucc (card_t comp) const { assert (comp < myNumComponents); Graph::fpos_t pos; #ifdef USE_MMAP const struct compdirent* c = reinterpret_cast(myComponentDirectory.addr) + comp; if (size_t (myComponentDirectory.len) < (comp + 1) * sizeof *c || c[0].succPos == FPOS_NONE) return 0; if (size_t (myComponentDirectory.len) < (comp + 2) * sizeof *c) { fseek (mySuccComponents, 0, SEEK_END); pos = ftell (mySuccComponents); } else pos = c[1].succPos; #else // USE_MMAP struct compdirent c[2]; fseek (myComponentDirectory, comp * sizeof *c, SEEK_SET); switch (fread (c, sizeof *c, 2, myComponentDirectory)) { case 0: return 0; case 1: fseek (mySuccComponents, 0, SEEK_END); c[1].succPos = ftell (mySuccComponents); // fall through case 2: if (c[0].succPos == FPOS_NONE) return 0; } pos = c[1].succPos; #endif // USE_MMAP assert (c[0].succPos <= pos); if (card_t numSucc = (pos - c[0].succPos) / sizeof (card_t)) { card_t* comps = new card_t[numSucc + 1]; fseek (mySuccComponents, c[0].succPos, SEEK_SET); if (numSucc != fread (comps + 1, sizeof *comps, numSucc, mySuccComponents)) { delete[] comps; return 0; } *comps = numSucc; return comps; } return 0; } card_t* ComponentGraph::getPred (card_t comp) const { assert (comp < myNumComponents); Graph::fpos_t pos; #ifdef USE_MMAP const struct compdirent* c = reinterpret_cast(myComponentDirectory.addr) + comp; if (size_t (myComponentDirectory.len) < (comp + 1) * sizeof *c || c[0].predPos == FPOS_NONE) return 0; if (size_t (myComponentDirectory.len) < (comp + 2) * sizeof *c) { fseek (myPredComponents, 0, SEEK_END); pos = ftell (myPredComponents); } else pos = c[1].predPos; #else // USE_MMAP struct compdirent c[2]; fseek (myComponentDirectory, comp * sizeof *c, SEEK_SET); switch (fread (c, sizeof *c, 2, myComponentDirectory)) { case 0: return 0; case 1: fseek (myPredComponents, 0, SEEK_END); c[1].predPos = ftell (myPredComponents); // fall through case 2: if (c[0].predPos == FPOS_NONE) return 0; } pos = c[1].predPos; #endif // USE_MMAP assert (c[0].predPos <= pos); if (card_t numPred = (pos - c[0].predPos) / sizeof (card_t)) { card_t* comps = new card_t[numPred + 1]; fseek (myPredComponents, c[0].predPos, SEEK_SET); if (numPred != fread (comps + 1, sizeof *comps, numPred, myPredComponents)) { delete[] comps; return 0; } *comps = numPred; return comps; } return 0; } card_t* ComponentGraph::path (card_t state, card_t comp, const class Expression* pathc) const { if (!myGraph.eval (state, pathc)) return 0; /** Visited states */ class BitVector visited (myGraph.getNumStates ()); visited.assign (state, true); /** Search queue */ std::list sq; sq.push_front (CARD_T_MAX); /* mark for the next level */ sq.push_back (state); /** Arcs in the explored graph (target, source) */ Graph::PathMap p; for (;;) { if ((state = *sq.begin ()) == CARD_T_MAX) { sq.pop_front (); if (sq.empty ()) return 0; sq.push_back (CARD_T_MAX); state = *sq.begin (); } sq.pop_front (); assert (!sq.empty ()); assert (visited[state]); if (getComponent (state) == comp) return Graph::toPath (p, state); if (card_t* succ = myGraph.getSuccessors (state)) { for (assert (*succ > 0); *succ; (*succ)--) { card_t s = succ[*succ]; if (!visited.tset (s) && myGraph.eval (s, pathc)) { sq.push_back (s); p.insert (Graph::PathMap::value_type (s, state)); } } delete[] succ; } } } card_t* ComponentGraph::rpath (card_t state, card_t comp, const class Expression* pathc) const { if (!myGraph.eval (state, pathc)) return 0; /** Visited states */ class BitVector visited (myGraph.getNumStates ()); visited.assign (state, true); /** Search queue */ std::list sq; sq.push_front (CARD_T_MAX); /* mark for the next level */ sq.push_back (state); /** Arcs in the explored graph (target, source) */ Graph::PathMap p; for (;;) { if ((state = *sq.begin ()) == CARD_T_MAX) { sq.pop_front (); if (sq.empty ()) return 0; sq.push_back (CARD_T_MAX); state = *sq.begin (); } sq.pop_front (); assert (!sq.empty ()); assert (visited[state]); if (getComponent (state) == comp) return Graph::toPath (p, state); for (Graph::fpos_t pos = myGraph.getPredecessors (state); pos != FPOS_NONE;) { card_t s = myGraph.getPredecessor (pos); if (!visited.tset (s) && myGraph.eval (s, pathc)) { sq.push_back (s); p.insert (Graph::PathMap::value_type (s, state)); } } } } maria-1.3.5/Graph/ComponentGraph.h0000644000175000017500000001202107643247662017131 0ustar msmakelamsmakela// Graph of strongly connected components -*- c++ -*- #ifndef COMPONENTGRAPH_H_ # define COMPONENTGRAPH_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "typedefs.h" # include "file.h" /** @file ComponentGraph.h * Graph of strongly connected components */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Graph of strongly connected components */ class ComponentGraph { public: /** Constructor * @param graph the underlying graph */ explicit ComponentGraph (const class Graph& graph); private: /** Copy constructor */ ComponentGraph (const class ComponentGraph& old); /** Assignment operator */ class ComponentGraph& operator= (const class ComponentGraph& old); public: /** Destructor */ ~ComponentGraph (); private: /** Open the component graph files with temporary names * @return true if everything succeeded */ inline bool openFiles (); /** Set the component number of a state * @param state the state * @param comp the component */ inline void setComponent (card_t state, card_t comp); /** Compute the arcs of the component graph */ inline void computeArcs (); public: /** Compute the strongly connected components * @param state start state of the search * @param cond condition for exploring states (NULL=true) * @return number of strongly connected components (0=fail) */ unsigned compute (card_t state, const class Expression* cond); /** Determine the number of strongly connected components in the graph */ unsigned size () const { return myNumComponents; } /** Determine the number of terminal components in the component graph */ unsigned getNumTerminals () const { return myNumTerminals; } /** Determine the component a state belongs to * @param state the state number * @return the corresponding component, or CARD_T_MAX if none */ card_t getComponent (card_t state) const; /** Determine the states a component consists of * @param comp the component number * @return the amount and numbers of the contained states */ card_t* getStates (card_t comp) const; /** Determine the number of successors of a component * @param comp the component number * @return the number of successors */ card_t getNumSucc (card_t comp) const; /** Determine the number of predecessors of a component * @param comp the component number * @return the number of predecessors */ card_t getNumPred (card_t comp) const; /** Determine the successors of a component * @param comp the component number * @return the amount and numbers of the successor components */ card_t* getSucc (card_t comp) const; /** Determine the predecessors of a component * @param comp the component number * @return the amount and numbers of the predecessor components */ card_t* getPred (card_t comp) const; /** Determine the shortest path from a state to a component * @param state the state number * @param comp the component number * @param pathc condition that must hold in every state on the path * @return the amount and numbers of the states on the path */ card_t* path (card_t state, card_t comp, const class Expression* pathc) const; /** Determine the shortest path to a state from a component * @param state the state number * @param comp the component number * @param pathc condition that must hold in every state on the path * @return the amount and numbers of the states on the path */ card_t* rpath (card_t state, card_t comp, const class Expression* pathc) const; private: /** The underlying graph */ const class Graph& myGraph; /** Number of components in the graph (0=not computed) */ card_t myNumComponents; /** Number of terminal components in the graph (0=not computed) */ card_t myNumTerminals; /** Mapping from state numbers to component numbers */ file_t myStateComponents; /** Component directory */ file_t myComponentDirectory; /** Mapping from component numbers to state numbers */ FILE* myComponentStates; /** Successor components of a component (forward arcs) */ FILE* mySuccComponents; /** Predecessor components of a component (backward arcs) */ FILE* myPredComponents; }; #endif // COMPONENTGRAPH_H_ maria-1.3.5/Graph/DummyReporter.C0000644000175000017500000000353407643247662016767 0ustar msmakelamsmakela// Dummy reporter of successor states in unfolding -*- c++ -*- /** @file DummyReporter.C * Interface for reporting successor states in unfolding */ /* Copyright © 2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "DummyReporter.h" bool DummyReporter::do_addState (const void*, size_t) { return false; } word_t* DummyReporter::do_popState (bool, size_t&) { return 0; } class GlobalMarking* DummyReporter::pop (bool) { return 0; } #ifdef EXPR_COMPILE bool DummyReporter::popCompiled (bool) { assert (!!myCompilation); return false; } #endif // EXPR_COMPILE bool DummyReporter::report (const class Transition&, const class Valuation&, const class GlobalMarking&, bool) { return true; } void DummyReporter::reportError (bool) { } #ifdef EXPR_COMPILE bool DummyReporter::report (const void*, size_t, bool, bool) { return true; } #endif // EXPR_COMPILE void DummyReporter::reject () { } maria-1.3.5/Graph/DummyReporter.h0000644000175000017500000001012707643247662017030 0ustar msmakelamsmakela// Dummy reporter of successor states in unfolding -*- c++ -*- #ifndef DUMMYREPORTER_H_ # define DUMMYREPORTER_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "StateReporter.h" # include "Search.h" /** @file DummyReporter.h * Interface for reporting successor states in unfolding */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Dummy reporter of successor states in unfolding */ class DummyReporter : public StateReporter { public: /** Constructor * @param net_ the net that is being analysed * @param printer_ printer object for diagnostic output * @param maxerrors maximum number of allowed errors (0=infinity) */ DummyReporter (const class Net& net_, const class Printer& printer_, unsigned maxerrors) : StateReporter ( # ifdef EXPR_COMPILE 0, # endif // EXPR_COMPILE net_, printer_, maxerrors, false, false, true) {} private: /** Copy constructor */ DummyReporter (const class DummyReporter& old); /** Assignment operator */ class DummyReporter& operator= (const class DummyReportert& other); public: /** Destructor */ ~DummyReporter () {} private: /** Add an encoded state to the state space * @param state the encoded state * @param size length of the encoded state in bytes * @return true if the state was new */ bool do_addState (const void* state, size_t size); /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @param size (output) length of the encoded stream * @return the encoded state, or NULL if none available */ word_t* do_popState (bool tail, size_t& size); /** Dequeue an unprocessed state * @param breadth true=dequeue (FIFO, queue), false=pop (LIFO, stack) * @return an unprocessed state, or NULL if all processed */ class GlobalMarking* pop (bool breadth); # ifdef EXPR_COMPILE /** Dequeue an unprocessed state * @param breadth true=dequeue (FIFO, queue), false=pop (LIFO, stack) * @return true if a state was found, or false if all processed */ bool popCompiled (bool breadth); # endif // EXPR_COMPILE /** Report a successor state * @param transition the transition fired * @param valuation the binding of the transition * @param marking the resulting marking * @param rejected flag: is the state rejected? * @return true if analysis should proceed; false on fatal error */ bool report (const class Transition& transition, const class Valuation& valuation, const class GlobalMarking& marking, bool rejected); /** Report a deadlock or an error in the current state * @param deadlock flag: is this a deadlock? */ void reportError (bool deadlock); public: # ifdef EXPR_COMPILE /** Report a successor state * @param state the resulting encoded deflated state (mandatory) * @param size length of the encoded state, in bytes * @param rejected flag: is the state rejected? * @param hidden flag: is the transition to the state hidden? * @return true if analysis should proceed; false on error */ bool report (const void* state, size_t size, bool rejected, bool hidden); # endif // EXPR_COMPILE private: /** Report an inconsistent successor state */ void reject (); }; #endif // DUMMYREPORTER_H_ maria-1.3.5/Graph/FullSet.C0000644000175000017500000002302607643247662015525 0ustar msmakelamsmakela// Lossless reachability set storage -*- c++ -*- /** @file FullSet.C * Transient, lossless reachability set storage */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifdef __GNUC__ # pragma implementation # ifdef __sgi # define _XOPEN_SOURCE 1 # define _XOPEN_SOURCE_EXTENDED 1 # endif // __sgi #endif // __GNUC__ #include "FullSet.h" #include "BTree.h" #include "ByteBuffer.h" #include // abort(3) #if defined __digital__ # define fileno(f) ((f)->_file) #endif // __digital__ #if defined __CYGWIN__ # define fileno(f) __sfileno(f) #endif // __CYGWIN__ #ifdef NO_MMAP /** an empty file structure */ # define NULL_F { 0, 0, 0 } #else // NO_MMAP # ifdef USE_MMAP /** an empty file structure */ # define NULL_F { -1, 0, 0, 0 } # else // USE_MMAP /** an empty file structure */ # define NULL_F 0 # endif // USE_MMAP #endif // NO_MMAP /** Check if a file is open * @param file the file * @return true if the file has been opened */ static bool isOpen (const file_t& file) { #ifdef USE_MMAP #ifdef NO_MMAP return bool (file.addr); # else // NO_MMAP return file.fd >= 0; # endif // NO_MMAP #else // USE_MMAP return bool (file); #endif // USE_MMAP } /** an unopened file */ static const file_t nofile = NULL_F; /** Open a temporary file * @return an opened file, or something on which isOpen() does not hold */ static file_t tempFile (void) { #ifdef USE_MMAP # ifdef NO_MMAP file_t f = { 0, 16384, malloc (16384) }; if (!f.addr) { perror ("malloc"); abort (); } # else // NO_MMAP FILE* file = tmpfile (); if (!file) { perror ("FullSet: tmpfile"); return nofile; } file_t f; f.fd = dup (fileno (file)); fclose (file); if (f.fd < 0) { perror ("FullSet: dup"); return nofile; } f.len = 0; f.alloc = 16384; if (ftruncate (f.fd, f.alloc)) { perror ("FullSet: ftruncate"); close (f.fd); return nofile; } f.addr = mmap (0, f.alloc, PROT_READ | PROT_WRITE, MAP_SHARED, f.fd, 0); if (f.addr == reinterpret_cast(MAP_FAILED)) { close (f.fd); perror ("FullSet: mmap"); return nofile; } # endif // NO_MMAP return f; #else // USE_MMAP FILE* file = tmpfile (); if (!file) { perror ("FullSet: tmpfile"); return nofile; } return file; #endif // USE_MMAP } #ifdef USE_MMAP /** Extend a file * @param file the file */ static void extend (file_t& file) { assert (isOpen (file) && file.addr); if (file.len < file.alloc) return; # ifndef NO_MMAP if (file.addr) munmap (file.addr, file.alloc); # endif // !NO_MMAP while (file.alloc < file.len) { if (!(file.alloc *= 2)) { fputs ("FullSet: extend: file size overflow\n", stderr); abort (); } } # ifdef NO_MMAP if (!(file.addr = realloc (file.addr, file.alloc))) { perror ("extend: realloc"); abort (); } # else // NO_MMAP if (ftruncate (file.fd, file.alloc)) { perror ("FullSet: extend: ftruncate"); abort (); } file.addr = # ifdef __sun (caddr_t) # endif // __sun mmap (0, file.alloc, PROT_READ | PROT_WRITE, MAP_SHARED, file.fd, 0); if (file.addr == reinterpret_cast(MAP_FAILED)) { perror ("FullSet: extend: mmap"); abort (); } # endif // NO_MMAP } #endif // USE_MMAP /** Close a temporary file * @param f the file to be closed */ static void closeFile (file_t& f) { #ifdef USE_MMAP # ifdef NO_MMAP if (f.addr) free (f.addr); # else // NO_MMAP munmap (f.addr, f.alloc); close (f.fd); # endif // NO_MMAP #else // USE_MMAP fclose (f); #endif // USE_MMAP } FullSet::FullSet () : StateSet (), myHash (0), myStates (nofile) { } FullSet::~FullSet () { #ifdef USE_MMAP myHash->cleanup (); #endif // USE_MMAP delete myHash; if (isOpen (myStates)) closeFile (myStates); mySearch.clear_allocated (); } bool FullSet::init (bool path) { #ifndef NO_MMAP assert (!isOpen (myStates)); #endif // !NO_MMAP if (path && !openFile ()) return false; file_t f; if (!isOpen (myStates = tempFile ()) || !isOpen (f = tempFile ())) { if (isOpen (myStates)) closeFile (myStates); return false; } myHash = new class BTree (f); return true; } void FullSet::clear () { assert (isOpen (myStates)); assert (!!myHash); myHash->clear (); #ifdef USE_MMAP myStates.len = 0; #else // USE_MMAP fclose (myStates); myStates = tempFile (); #endif // USE_MMAP mySearch.clear_allocated (); if (myPathFile) fseek (myPathFile, myPathFileLength = myOffset = 0, SEEK_SET); } /** Compute a hash value for a sequence of bytes * @param buf the sequence * @param bytes number of bytes in the sequence */ inline static size_t getHashValue (const unsigned char* buf, size_t bytes) { size_t h = 0; while (bytes--) h ^= (h << 3 | h >> (CHAR_BIT - 3)) ^ buf[bytes]; return h; } /** Read an encoded state from the file * @param f the state storage file * @param offset offset to the file (bytes from the start of the file) * @param len number of bytes to read */ static word_t* getState (const file_t& f, long offset, unsigned len) { word_t* state = new word_t[(len + (sizeof (word_t) - 1)) / sizeof (word_t)]; #ifdef USE_MMAP assert (!len || ssize_t (offset + len) <= f.len); memcpy (state, static_cast(f.addr) + offset, len); #else // USE_MMAP if (fseek (f, offset, SEEK_SET)) { perror ("FullSet: fseek"); abort (); } if (fread (state, 1, len, f) != len) { perror ("FullSet: fread"); abort (); } #endif // USE_MMAP return state; } /** Find an encoded state in the set * @param f the state file * @param offset offset to the state file * @param buf compare this state against the one at offset * @param tmp work storage for encoded states * @param bytes length of the encoded state in bytes * @return whether buf matches the state */ static bool cmpfetch (const file_t& f, unsigned offset, const void* buf, #ifndef USE_MMAP void* tmp, #endif // !USE_MMAP size_t bytes) { #ifdef USE_MMAP return !bytes || (ssize_t (offset + bytes) <= f.len && !memcmp (static_cast(f.addr) + offset, buf, bytes)); #else // USE_MMAP if (fseek (f, offset, SEEK_SET)) { perror ("FullSet: fseek"); abort (); } return fread (tmp, 1, bytes, f) == bytes && !memcmp (tmp, buf, bytes); #endif // USE_MMAP } bool FullSet::do_add (const void* buf, size_t size) { size_t h = getHashValue (reinterpret_cast(buf), size); if (unsigned* offsets = myHash->search (h)) { #ifndef USE_MMAP word_t* tmp = new word_t[(size + (sizeof (word_t) - 1)) / sizeof (word_t)]; #endif // !USE_MMAP for (unsigned i = *offsets; i; i--) { if (::cmpfetch (myStates, offsets[i], buf, #ifndef USE_MMAP tmp, #endif // !USE_MMAP size)) { #ifndef USE_MMAP delete[] tmp; #endif // !USE_MMAP delete[] offsets; return false; } } #ifndef USE_MMAP delete[] tmp; #endif // !USE_MMAP delete[] offsets; } // a new state: add it to disk #ifdef USE_MMAP const long len = myStates.len; myStates.len += size; extend (myStates); memcpy (static_cast(myStates.addr) + len, buf, size); #else // USE_MMAP if (fseek (myStates, 0, SEEK_END)) { perror ("FullSet: fseek"); abort (); } const long len = ftell (myStates); if (fwrite (buf, 1, size, myStates) != size) { perror ("FullSet: fwrite"); abort (); } #endif // USE_MMAP myHash->insert (h, len); newState (); assert (!myPathFile || myPathFileLength == ftell (myPathFile)); assert (!myOffset || myOffset < myPathFileLength); mySearch.push_allocated (reinterpret_cast(len), size, myPathFileLength); if (myPathFile) { class BytePacker p; p.append (myOffset), p.append (len), p.append (size); fwrite (p.getBuf (), 1, p.getLength (), myPathFile); myPathFileLength += p.getLength (); } return true; } word_t* FullSet::getState (long pos, size_t* size) const { unsigned char rbuf[12]; class ByteUnpacker u (rbuf); assert (!!myPathFile); assert (pos < myPathFileLength); fseek (myPathFile, pos, SEEK_SET); fread (rbuf, sizeof rbuf, 1, myPathFile); u.extract (); unsigned offset = u.extract (), len = u.extract (); word_t* state = new word_t[len + (sizeof (word_t) - 1) / sizeof (word_t)]; #ifdef USE_MMAP assert (!len || ssize_t (offset + len) <= myStates.len); memcpy (state, static_cast(myStates.addr) + offset, len); #else // USE_MMAP if (fseek (myStates, offset, SEEK_SET)) { perror ("FullSet: fseek"); abort (); } fread (state, 1, len, myStates); #endif // USE_MMAP *size = len; return state; } word_t* FullSet::pop (bool tail, size_t& size) { if (mySearch.empty ()) return 0; else { unsigned long ofs = reinterpret_cast (mySearch.pop (tail, myOffset, &size)); return ::getState (myStates, ofs, size); } } maria-1.3.5/Graph/FullSet.h0000644000175000017500000000474007643247662015574 0ustar msmakelamsmakela// Lossless reachability set storage -*- c++ -*- #ifndef FULLSET_H_ # define FULLSET_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "StateSet.h" # include "file.h" /** @file FullSet.h * Transient, lossless reachability set storage */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Lossless reachability set storage */ class FullSet : public StateSet { public: /** Constructor */ FullSet (); private: /** Copy constructor */ FullSet (const class FullSet& old); /** Assignment operator */ class FullSet& operator= (const class FullSet& old); public: /** Destructor */ ~FullSet (); /** Set up the storage * @param path flag: open the counterexample path file? * @return true if the initialization succeeded */ bool init (bool path); /** Clear the storage */ void clear (); private: /** Add a state to the graph * @param state the encoded state * @param size length of the encoded state, in bytes * @return true if the state was enqueued to mySearch */ bool do_add (const void* state, size_t size); protected: /** Get a deflated state from myPathFile * @param pos file offset to the state * @param size (output) length of the encoded state */ word_t* getState (long pos, size_t* size) const; public: /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @param size (output) length of the encoded stream * @return the encoded state */ word_t* pop (bool tail, size_t& size); private: /** The state hash */ class BTree* myHash; /** The state storage */ file_t myStates; }; #endif // FULLSET_H_ maria-1.3.5/Graph/Graph.C0000644000175000017500000010717610232532226015176 0ustar msmakelamsmakela// Persistent reachability graph storage -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Graph.h" #include "LSTS.h" #include "BTree.h" #include "Net.h" #include "Place.h" #include "GlobalMarking.h" #include "BitVector.h" #include "util.h" #include // abort(3) #ifndef __WIN32 # include #endif // !__WIN32 #include #include #ifdef USE_MMAP # include # ifdef __DECCXX /** A qualifier for pointers to unaligned data */ # define UNALIGNED __unaligned # else // __DECCXX /** A qualifier for pointers to unaligned data */ # define UNALIGNED /*nothing*/ # endif // __DECCXX # if defined __digital__ # define fileno(f) ((f)->_file) # endif // __digital__ # ifdef NO_MMAP /** an empty file structure */ # define NULL_F { 0, 0, 0 } # else // NO_MMAP /** an empty file structure */ # define NULL_F { -1, 0, 0, 0 } # endif // NO_MMAP /** an empty file pointer */ static const file_t nofile = NULL_F; /** empty file pointers */ static const struct Graph::files nofiles = { NULL_F, NULL_F, 0, NULL_F }; #else // USE_MMAP # define UNALIGNED /*nothing*/ /** an empty file pointer */ static const file_t nofile = 0; /** empty file pointers */ static const struct Graph::files nofiles = { 0, 0, 0, 0 }; #endif // USE_MMAP /** @file Graph.C * Persistent, lossless reachability graph storage */ /* Copyright © 1999-2003,2005 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** file offset to state directory slot * @param s number of the state * @return file offset of the corresponding directory slot */ #ifdef USE_MMAP # define DIRSLOT1(s) \ (reinterpret_cast \ (static_cast(myFiles.directory.addr) + \ myDirectoryOffset) + 3 * (s)) #else // USE_MMAP # define DIRSLOT1(s) (myDirectoryOffset + (s) * (3 * sizeof (Graph::fpos_t))) #endif // USE_MMAP /** file offset to the second component of a state directory slot * @param s number of the state * @return file offset to the second component of the slot */ #ifdef USE_MMAP # define DIRSLOT2(s) (&DIRSLOT1 (s)[1]) #else // USE_MMAP # define DIRSLOT2(s) (DIRSLOT1 (s) + sizeof (Graph::fpos_t)) #endif // USE_MMAP /** file offset to the third component of a state directory slot * @param s number of the state * @return file offset to the second component of the slot */ #ifdef USE_MMAP # define DIRSLOT3(s) (&DIRSLOT1 (s)[2]) #else // USE_MMAP # define DIRSLOT3(s) (DIRSLOT1 (s) + 2 * sizeof (Graph::fpos_t)) #endif // USE_MMAP #ifdef USE_MMAP /** number of states */ # define myNumStates \ (reinterpret_cast \ (static_cast(myFiles.directory.addr) + myDirectoryOffset)[-2]) /** number of arcs */ # define myNumArcs \ (reinterpret_cast \ (static_cast(myFiles.directory.addr) + myDirectoryOffset)[-1]) #endif // USE_MMAP /** File offset flag */ #define OFFSET_FLAG LONG_MIN /** Determine whether an offset has been flagged * @param offset offset to be checked * @return whether the offset has the error bit set */ inline static bool isFlagged (Graph::fpos_t offset) { return offset & OFFSET_FLAG && true; } /** Flag an offset * @param state offset to be flagged */ inline static void flag (UNALIGNED Graph::fpos_t& offset) { assert (!::isFlagged (offset)); offset |= OFFSET_FLAG; } inline static Graph::fpos_t getOffset (Graph::fpos_t offset) { return offset & ~OFFSET_FLAG; } #undef OFFSET_FLAG #ifdef NO_MMAP /** pretend that mmapped files are always open */ # define isOpen(file) true /** pretend to open a file */ # define openFile(name, cr) nofile #else /** Check if a file is open * @param file the file * @return true if the file has been opened */ static bool isOpen (const file_t& file) { # ifdef USE_MMAP return file.fd >= 0; # else // USE_MMAP return bool (file); # endif // USE_MMAP } /** Open a file * @param name the file name (optional) * @param cr flag: create or truncate the file * @return an opened file, or something on which isOpen() does not hold */ static file_t openFile (const char* name, bool cr) { # ifdef USE_MMAP file_t f = nofile; if (name) f.fd = open (name, cr ? O_RDWR | O_CREAT | O_TRUNC : O_RDWR, 0666); else { FILE* file = tmpfile (); if (!file) { perror ("tmpfile"); return nofile; } f.fd = dup (fileno (file)); fclose (file); name = "(temporary)"; } if (f.fd >= 0) { f.len = lseek (f.fd, 0, SEEK_END); for (f.alloc = 4096; f.alloc < f.len; ) { if (!(f.alloc *= 2)) { fputs (name, stderr), fputs (": file size overflow\n", stderr); abort (); } } if (ftruncate (f.fd, f.alloc)) { fputs (name, stderr), perror (": ftruncate"); abort (); } f.addr = # ifdef __sun (caddr_t) # endif // __sun mmap (0, f.alloc, PROT_READ | PROT_WRITE, MAP_SHARED, f.fd, 0); if (f.addr == reinterpret_cast(MAP_FAILED)) { fputs (name, stderr), perror (": mmap"); close (f.fd); return nofile; } } return f; # else // USE_MMAP return name ? fopen (name, cr ? "wb+" : "rb+") : tmpfile (); # endif // USE_MMAP } #endif // NO_MMAP #ifdef USE_MMAP size_t Graph::getNumStates () const { return myNumStates; } unsigned Graph::getNumArcs () const { return myNumArcs; } #endif // USE_MMAP /** Close a file * @param file the file */ static void closeFile (file_t& file) { assert (isOpen (file)); #ifdef USE_MMAP # ifdef NO_MMAP if (file.addr) free (file.addr); # else // NO_MMAP if (file.addr) munmap (file.addr, file.alloc); ftruncate (file.fd, file.len); close (file.fd); # endif // NO_MMAP #else // USE_MMAP fclose (file); #endif // USE_MMAP } #ifdef USE_MMAP /** Extend a file * @param file the file */ static void extend (file_t& file) { assert (isOpen (file) && file.addr); if (file.len < file.alloc) return; # ifndef NO_MMAP if (file.addr) munmap (file.addr, file.alloc); # endif // !NO_MMAP while (file.alloc < file.len) { if (!(file.alloc *= 2)) { fputs ("extend: file size overflow\n", stderr); abort (); } } # ifdef NO_MMAP if (!(file.addr = realloc (file.addr, file.alloc))) { perror ("extend: realloc"); abort (); } # else // NO_MMAP if (ftruncate (file.fd, file.alloc)) { perror ("extend: ftruncate"); abort (); } file.addr = # ifdef __sun (caddr_t) # endif // __sun mmap (0, file.alloc, PROT_READ | PROT_WRITE, MAP_SHARED, file.fd, 0); if (file.addr == reinterpret_cast(MAP_FAILED)) { perror ("extend: mmap"); abort (); } # endif // NO_MMAP } #endif // USE_MMAP /** Find and update an encoded state in the graph * @param myFiles the graph files * @param myDirectoryOffset offset to the state directory * @param buf the encoded state to find or update * @param tmp work storage for encoded states * @param bytes length of the encoded state in bytes * @param number number of the state to be searched * @return whether the state was found */ static bool update (const struct Graph::files& myFiles, Graph::fpos_t myDirectoryOffset, const void* buf, #ifndef USE_MMAP void* tmp, #endif // !USE_MMAP size_t bytes, card_t number) { Graph::fpos_t num; #ifdef USE_MMAP num = *DIRSLOT1 (number); assert (!bytes || getOffset (num) < myFiles.states.len); return !bytes || (getOffset (num) + Graph::fpos_t (bytes) <= myFiles.states.len && !memcmp (static_cast(myFiles.states.addr) + getOffset (num), buf, bytes)); #else // USE_MMAP fseek (myFiles.directory, DIRSLOT1 (number), SEEK_SET); if (fread (&num, sizeof num, 1, myFiles.directory) != 1) assert (false); if (fseek (myFiles.states, getOffset (num), SEEK_SET)) { perror ("update (): fseek"); abort (); } return fread (tmp, 1, bytes, myFiles.states) == bytes && !memcmp (tmp, buf, bytes); #endif // USE_MMAP } Graph::Graph (const class Net& net) : myNet (net), mySucc (new card_t[1]), #ifndef USE_MMAP myNumArcs (0), myNumStates (0), #endif // !USE_MMAP myStates (0), myFiles (nofiles), myDirectoryOffset (0), myFilename (0), myFilebase (0), myLSTS (0) { *mySucc = 0; } Graph::Graph (const class Net& net, const char* filename, const char* filebase) : myNet (net), mySucc (new card_t[1]), #ifndef USE_MMAP myNumArcs (0), myNumStates (0), #endif // !USE_MMAP myStates (0), myFiles (nofiles), myDirectoryOffset (0), myFilename (0), myFilebase (0), myLSTS (0) { *mySucc = 0; unsigned i; assert (filename || filebase); if (filename) myFilename = newString (filename); if (filebase) myFilebase = newString (filebase); else { // remove directory component for (i = 0; filename[i]; i++); while (i > 0 && filename[i - 1] != '/') i--; filebase = filename + i; // remove the last suffix starting with '.' for (i = 0; filebase[i]; i++); while (i > 0 && filebase[i] != '.') i--; if (!i) // no suffix for (i = 0; filebase[i]; i++); char* name = new char[i + 1]; memcpy (name, filebase, i); name[i] = 0; myFilebase = name; } } Graph::~Graph () { if (isOpen (myFiles.directory)) { closeFile (myFiles.directory); closeFile (myFiles.states); fclose (myFiles.arcs); closeFile (myFiles.preds); } delete myStates; delete[] mySucc; delete[] myFilename; delete[] myFilebase; delete myLSTS; } bool Graph::openFiles (bool regenerate) { assert (!isOpen (myFiles.directory) && !isOpen (myFiles.states) && !myFiles.arcs && !isOpen (myFiles.preds)); unsigned i = 0; if (myFilebase) while (myFilebase[i]) i++; /** flag: create or truncate the graph files */ bool cr = !myFilebase || regenerate; { char* base = i ? new char[i + 5] : 0; memcpy (base, myFilebase, i); if (i) memcpy (base + i, ".rgh", 5); file_t f = openFile (base, cr); #ifndef NO_MMAP if (isOpen (f)) myStates = new class BTree (f); else if (!cr && myFilename && errno == ENOENT) { f = openFile (base, cr = true); if (isOpen (f)) goto failRGH; myStates = new class BTree (f); } else { failRGH: perror (base); delete[] base; return false; } #endif // !NO_MMAP if (i) memcpy (base + i, ".rgd", 5); myFiles.directory = openFile (base, cr); if (!isOpen (myFiles.directory)) { perror (base); delete myStates; myStates = 0; delete[] base; return false; } if (i) memcpy (base + i, ".rgs", 5); myFiles.states = openFile (base, cr); if (!isOpen (myFiles.states)) { perror (base); delete myStates; myStates = 0; closeFile (myFiles.directory); myFiles.directory = nofile; delete[] base; return false; } if (i) memcpy (base + i, ".rga", 5); if (!(myFiles.arcs = i ? fopen (base, cr ? "wb+" : "rb+") : tmpfile ())) { perror (base); delete myStates; myStates = 0; closeFile (myFiles.directory); myFiles.directory = nofile; closeFile (myFiles.states); myFiles.states = nofile; delete[] base; return false; } if (i) memcpy (base + i, ".rgp", 5); myFiles.preds = openFile (base, cr); if (!isOpen (myFiles.preds)) { perror (base); delete myStates; myStates = 0; closeFile (myFiles.directory); myFiles.directory = nofile; closeFile (myFiles.states); myFiles.states = nofile; fclose (myFiles.arcs); myFiles.arcs = 0; delete[] base; return false; } delete[] base; } static const char magic[] = "Maria-generated Reachability Graph of "; const size_t magiclen = (sizeof magic) - 1; if (!cr) { // check the magic cookie #ifdef USE_MMAP if (myFiles.directory.len < fpos_t (magiclen)) { wrongFormatEOF: fprintf (stderr, "%s: premature EOF of graph directory\n", myFilebase); goto wrongFormatNoEOF; } if (memcmp (myFiles.directory.addr, magic, magiclen)) { wrongFormatNoEOF: delete myStates; myStates = 0; closeFile (myFiles.directory); myFiles.directory = nofile; closeFile (myFiles.states); myFiles.states = nofile; fclose (myFiles.arcs); myFiles.arcs = 0; closeFile (myFiles.preds); myFiles.preds = nofile; return false; } #else // USE_MMAP const size_t capacity = 4096; char* buf = new char[capacity]; assert (capacity >= magiclen); if ((fread (buf, 1, magiclen, myFiles.directory) != magiclen) || memcmp (buf, magic, magiclen)) { fprintf (stderr, "%s: graph: wrong magic cookie\n", myFilebase); wrongFormat: if (feof (myFiles.directory)) fprintf (stderr, "%s: premature EOF of graph directory\n", myFilebase); wrongFormatNoEOF: delete myStates; myStates = 0; closeFile (myFiles.directory); myFiles.directory = nofile; closeFile (myFiles.states); myFiles.states = nofile; fclose (myFiles.arcs); myFiles.arcs = 0; closeFile (myFiles.preds); myFiles.preds = nofile; delete[] buf; return false; } #endif // USE_MMAP #ifdef USE_MMAP size_t got = myFiles.directory.len - magiclen; const char* buf = static_cast(myFiles.directory.addr) + magiclen; #else // USE_MMAP size_t got = fread (buf, 1, capacity, myFiles.directory); #endif // USE_MMAP size_t len; for (len = 0; len < got && buf[len]; len++); if (!len) { fprintf (stderr, "%s: graph: empty model name\n", myFilebase); argError: goto wrongFormatNoEOF; } else if (len == got) { fprintf (stderr, "%s: graph: model name is too long\n", myFilebase); goto argError; } #ifndef USE_MMAP if (fseek (myFiles.directory, fpos_t (len) - got + 1, SEEK_CUR)) { fprintf (stderr, "%s: ", myFilebase); perror ("fseek"); goto wrongFormatNoEOF; } #endif // !USE_MMAP if (myFilename) { if (strcmp (buf, myFilename)) { fprintf (stderr, "%s: model names differ: \"%s\" \"%s\"\n", myFilebase, buf, myFilename); goto argError; } } else myFilename = newString (buf); #ifndef USE_MMAP delete[] buf; buf = 0; #endif // !USE_MMAP #ifdef USE_MMAP myDirectoryOffset = len + (magiclen + sizeof (fpos_t)); #else // USE_MMAP myDirectoryOffset = ftell (myFiles.directory) + (sizeof (fpos_t) - 1); #endif // USE_MMAP myDirectoryOffset /= sizeof (fpos_t); myDirectoryOffset *= sizeof (fpos_t); #ifdef USE_MMAP myDirectoryOffset += (sizeof myNumStates) + (sizeof myNumArcs); if (myDirectoryOffset >= myFiles.directory.len) goto wrongFormatEOF; fpos_t endpos = myFiles.directory.len; #else // USE_MMAP fseek (myFiles.directory, myDirectoryOffset, SEEK_SET); myDirectoryOffset += (sizeof myNumStates) + (sizeof myNumArcs); if (fread (&myNumStates, sizeof myNumStates, 1, myFiles.directory) != 1 || fread (&myNumArcs, sizeof myNumArcs, 1, myFiles.directory) != 1) goto wrongFormat; fseek (myFiles.directory, 0, SEEK_END); fpos_t endpos = ftell (myFiles.directory); #endif // USE_MMAP if ((endpos - myDirectoryOffset) % (3 * sizeof (fpos_t)) || (endpos - myDirectoryOffset) / (3 * sizeof (fpos_t)) != myNumStates) { fprintf (stderr, "%s.rgd: trying to ignore extra bytes at end of file\n", myFilebase); #ifdef USE_MMAP myFiles.directory.len = myDirectoryOffset + 3 * sizeof (fpos_t) * myNumStates; #endif // USE_MMAP } if (!myNumStates) { fprintf (stderr, "%s.rgd: no states\n", myFilebase); goto wrongFormatNoEOF; } } else { // create the directory afresh #ifdef USE_MMAP assert (myFiles.directory.len == 0); const size_t len = i ? strlen (myFilename) + 1 : 0; myDirectoryOffset = len + (magiclen + sizeof (fpos_t) - 1 + (sizeof myNumStates) + (sizeof myNumArcs)); myDirectoryOffset /= sizeof (fpos_t); myDirectoryOffset *= sizeof (fpos_t); myFiles.directory.len = myDirectoryOffset; extend (myFiles.directory); memcpy (myFiles.directory.addr, magic, magiclen); memcpy (static_cast(myFiles.directory.addr) + magiclen, myFilename, len); myNumStates = 0; myNumArcs = 0; #else // USE_MMAP // magic cookie fwrite (magic, magiclen, 1, myFiles.directory); fwrite (myFilename, 1, i ? 1 + strlen (myFilename) : 0, myFiles.directory); myDirectoryOffset = ftell (myFiles.directory) + (sizeof (fpos_t) - 1); myDirectoryOffset /= sizeof (fpos_t); myDirectoryOffset *= sizeof (fpos_t); fseek (myFiles.directory, myDirectoryOffset, SEEK_SET); myDirectoryOffset += sizeof myNumStates; fwrite (&myNumStates, sizeof myNumStates, 1, myFiles.directory); myDirectoryOffset += sizeof myNumArcs; fwrite (&myNumArcs, sizeof myNumArcs, 1, myFiles.directory); assert (myDirectoryOffset == ftell (myFiles.directory)); fflush (myFiles.directory); #endif // USE_MMAP } return true; } void Graph::setLSTS (class LSTS* lsts) { delete myLSTS; myLSTS = lsts; } /** Compute a hash value for a sequence of bytes * @param buf the sequence * @param bytes number of bytes in the sequence */ inline static size_t getHashValue (const unsigned char* buf, size_t bytes) { size_t h = 0; while (bytes--) h ^= (h << 3 | h >> (CHAR_BIT - 3)) ^ buf[bytes]; return h; } const class Graph::AddStatus Graph::add (const void* buf, size_t bytes) { size_t h = getHashValue (reinterpret_cast(buf), bytes); if (card_t* states = myStates->search (h)) { #ifndef USE_MMAP word_t* tmp = new word_t[(bytes + (sizeof (word_t) - 1)) / sizeof (word_t)]; #endif // !USE_MMAP for (card_t s = *states; s; s--) { if (::update (myFiles, myDirectoryOffset, buf, #ifndef USE_MMAP tmp, #endif // !USE_MMAP bytes, states[s])) { s = states[s]; #ifndef USE_MMAP delete[] tmp; #endif // !USE_MMAP delete[] states; return AddStatus (false, s); } } #ifndef USE_MMAP delete[] tmp; #endif // !USE_MMAP delete[] states; } // a new state: add it to disk #ifdef USE_MMAP myFiles.directory.len += 3 * sizeof (fpos_t); extend (myFiles.directory); UNALIGNED fpos_t* const num = DIRSLOT1 (myNumStates); const fpos_t len = myFiles.states.len; num[0] = len; num[1] = num[2] = FPOS_NONE; myFiles.states.len += bytes; extend (myFiles.states); memcpy (static_cast(myFiles.states.addr) + len, buf, bytes); myStates->insert (h, myNumStates); return AddStatus (true, myNumStates++); #else // USE_MMAP { fseek (myFiles.directory, DIRSLOT1 (myNumStates), SEEK_SET); if (fseek (myFiles.states, 0, SEEK_END)) assert (false); fpos_t num[3]; num[0] = ftell (myFiles.states); num[1] = num[2] = FPOS_NONE; if ((fwrite (num, sizeof num, 1, myFiles.directory) != 1) || (fwrite (buf, 1, bytes, myFiles.states) != bytes)) { error: perror ("Graph::add (state): fwrite"); abort (); } myStates->insert (h, myNumStates++); fseek (myFiles.directory, myDirectoryOffset - (sizeof (myNumStates) + sizeof (myNumArcs)), SEEK_SET); if (1 != fwrite (&myNumStates, sizeof myNumStates, 1, myFiles.directory)) goto error; return AddStatus (true, myNumStates - 1); } #endif // USE_MMAP } card_t Graph::lookup (const void* buf, size_t bytes) const { size_t h = getHashValue (reinterpret_cast(buf), bytes); if (card_t* states = myStates->search (h)) { #ifndef USE_MMAP word_t* tmp = new word_t[(bytes + (sizeof (word_t) - 1)) / sizeof (word_t)]; #endif // !USE_MMAP for (card_t s = *states; s; s--) { if (::update (myFiles, myDirectoryOffset, buf, #ifndef USE_MMAP tmp, #endif // !USE_MMAP bytes, states[s])) { s = states[s]; #ifndef USE_MMAP delete[] tmp; #endif // !USE_MMAP delete[] states; return s; } } #ifndef USE_MMAP delete[] tmp; #endif // !USE_MMAP delete[] states; } return CARD_T_MAX; } void Graph::add (card_t source, card_t target) { assert (!!mySucc); assert (source != CARD_T_MAX); assert (target != CARD_T_MAX); if (!(*mySucc & (*mySucc + 1))) { card_t* succ = new card_t[(*mySucc + 1) << 1]; memcpy (succ, mySucc, (*mySucc + 1) * sizeof *succ); delete[] mySucc; mySucc = succ; } mySucc[++(*mySucc)] = target; addReverse (source, target); } /** Encode a number to a file using a variable-length code * @param file the output file * @param num the number to be encoded * @return true if the operation succeeded */ static bool encodeNumber (FILE* file, card_t num) { char buf[4]; unsigned len; // variable-length code: // 0..127 0xxxxxxx // 128..16511 10xxxxxxxxxxxxxx // 16512..1073758335 11xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx if (num < 128) buf[0] = num, len = 1; else if ((num -= 128) < (1 << 14)) buf[0] = 0x80 | (num >> 8), buf[1] = num, len = 2; else if ((num -= (1 << 14)) < (1 << 30)) { buf[3] = num; buf[2] = num >>= 8; buf[1] = num >>= 8; buf[0] = (num >> 8) | 0xc0; len = 4; } else return false; return len == fwrite (buf, 1, len, file); } /** Decode a number from a file using a variable-length code * @param file the output file * @return the decoded number */ static card_t decodeNumber (FILE* file) { unsigned char buf[4]; if (1 != fread (buf, 1, 1, file)) { err: perror ("decodeNumber: fread"); assert (false); return 0; } switch (*buf & 0xc0) { default: // 0..127 return *buf; case 0x80: // 128..16511 if (1 != fread (buf + 1, 1, 1, file)) goto err; return 128 + ((static_cast(*buf & 0x3f) << 8) | buf[1]); case 0xc0: // 16512..1073758335 if (3 != fread (buf + 1, 1, 3, file)) goto err; return 16512 + ((static_cast(*buf & 0x3f) << 24) | (static_cast(buf[1]) << 16) | (static_cast(buf[2]) << 8) | buf[3]); } } void Graph::addEvents (card_t source, const void* buf, size_t bytes) { assert (!isProcessed (source) && mySucc); #ifdef USE_MMAP /** offset to the arc file */ UNALIGNED fpos_t& arcoffset = *DIRSLOT2 (source); assert (arcoffset == FPOS_NONE); #else // USE_MMAP /** offset to the arc file */ fpos_t arcoffset; #endif // USE_MMAP if (*mySucc) { if (myLSTS) { word_t* data = const_cast(static_cast(buf)); BitPacker::inflate (data[(bytes - 1) / sizeof (word_t)], (-bytes) % sizeof (word_t)); myLSTS->outputArcs (*this, source, mySucc, data); BitPacker::deflate (data[(bytes - 1) / sizeof (word_t)], (-bytes) % sizeof (word_t)); } fseek (myFiles.arcs, 0, SEEK_END); arcoffset = ftell (myFiles.arcs); if (!encodeNumber (myFiles.arcs, bytes) || !encodeNumber (myFiles.arcs, *mySucc) || (*mySucc != fwrite (mySucc + 1, sizeof *mySucc, *mySucc, myFiles.arcs)) || (bytes != fwrite (buf, 1, bytes, myFiles.arcs))) { perror ("Graph::add (event): fwrite"); abort (); } *mySucc = 0; } else arcoffset = FPOS_DEAD; // update the directory file #ifndef USE_MMAP fseek (myFiles.directory, DIRSLOT2 (source), SEEK_SET); # ifndef NDEBUG { fpos_t arcpos; assert (1 == fread (&arcpos, sizeof arcpos, 1, myFiles.directory) && arcpos == FPOS_NONE); fseek (myFiles.directory, DIRSLOT2 (source), SEEK_SET); } # endif // !NDEBUG fwrite (&arcoffset, sizeof arcoffset, 1, myFiles.directory); fseek (myFiles.directory, myDirectoryOffset - sizeof myNumArcs, SEEK_SET); fwrite (&myNumArcs, sizeof myNumArcs, 1, myFiles.directory); #endif // !USE_MMAP } word_t* Graph::fetchState (card_t number, size_t& length, bool* erroneous) const { assert (number < myNumStates); #ifdef USE_MMAP fpos_t num = *DIRSLOT1 (number); #else // USE_MMAP fseek (myFiles.directory, DIRSLOT1 (number), SEEK_SET); fpos_t num; if (fread (&num, sizeof num, 1, myFiles.directory) != 1) { readError: perror ("Graph::fetchState (): fread"); return 0; } #endif // USE_MMAP if (erroneous) *erroneous = ::isFlagged (num); num = ::getOffset (num); #ifdef USE_MMAP length = (number == myNumStates - 1 ? myFiles.states.len : ::getOffset (*DIRSLOT1 (number + 1))) - num; #else // USE_MMAP if (number == myNumStates - 1) { fseek (myFiles.states, 0, SEEK_END); length = ftell (myFiles.states) - num; } else { fpos_t pos; fseek (myFiles.directory, DIRSLOT1 (number + 1), SEEK_SET); if (fread (&pos, sizeof pos, 1, myFiles.directory) != 1) goto readError; length = ::getOffset (pos) - num; } if (fseek (myFiles.states, num, SEEK_SET)) { perror ("Graph::fetchState (): fseek"); return 0; } #endif // USE_MMAP unsigned numWords = (length + sizeof (word_t) - 1) / sizeof (word_t); word_t* buf = new word_t[numWords]; #ifdef USE_MMAP memcpy (buf, static_cast(myFiles.states.addr) + num, length); #else // USE_MMAP if (fread (buf, 1, length, myFiles.states) != length) { delete[] buf; goto readError; } #endif // USE_MMAP return buf; } class GlobalMarking* Graph::fetchState (card_t number) const { size_t length; bool erroneous; word_t* buf = fetchState (number, length, &erroneous); if (!buf) return 0; BitPacker::inflate (buf[(length - 1) / sizeof (word_t)], (-length) % sizeof (word_t)); // Decode the marking class GlobalMarking* marking = new class GlobalMarking (myNet); marking->decode (*myNet.getInitMarking (), buf); // Set the error bit if (erroneous) marking->flagErroneous (); delete[] buf; return marking; } card_t Graph::getNumPredecessors (card_t state) const { card_t num = 0; for (fpos_t pos = getPredecessors (state); pos != FPOS_NONE; getPredecessor (pos)) num++; return num; } Graph::fpos_t Graph::getPredecessors (card_t state) const { assert (state < myNumStates); #ifdef USE_MMAP return *DIRSLOT3 (state); #else // USE_MMAP fseek (myFiles.directory, DIRSLOT3 (state), SEEK_SET); fpos_t pos; if (fread (&pos, sizeof pos, 1, myFiles.directory) != 1) { assert (false); return FPOS_NONE; } return pos; #endif // USE_MMAP } card_t Graph::getPredecessor (Graph::fpos_t& pos) const { card_t state; assert (pos != FPOS_NONE); #ifdef USE_MMAP assert (pos >= 0); assert (pos + fpos_t ((sizeof state) + (sizeof pos)) <= myFiles.preds.len); const char* buf = static_cast(myFiles.preds.addr); state = *reinterpret_cast(buf + pos); pos = *reinterpret_cast(buf + pos + sizeof state); #else // USE_MMAP fseek (myFiles.preds, pos, SEEK_SET); if (fread (&state, sizeof state, 1, myFiles.preds) != 1 || fread (&pos, sizeof pos, 1, myFiles.preds) != 1) { assert (false); pos = FPOS_NONE; return CARD_T_MAX; } #endif // USE_MMAP assert (state < myNumStates); return state; } card_t* Graph::getSuccessors (card_t state, word_t** data) const { fpos_t pos; assert (state < myNumStates); #ifdef USE_MMAP pos = *DIRSLOT2 (state); #else // USE_MMAP fseek (myFiles.directory, DIRSLOT2 (state), SEEK_SET); if (fread (&pos, sizeof pos, 1, myFiles.directory) != 1) { assert (false); return 0; } #endif // USE_MMAP if (pos == FPOS_DEAD || pos == FPOS_NONE) return 0; fseek (myFiles.arcs, pos, SEEK_SET); /** length of the encoded data */ const size_t length = decodeNumber (myFiles.arcs); /** number of successor states */ const card_t numSucc = decodeNumber (myFiles.arcs); assert (numSucc > 0); card_t* succ = new card_t[numSucc + 1]; *succ = numSucc; if (fread (succ + 1, sizeof *succ, *succ, myFiles.arcs) != *succ) { assert (false); delete[] succ; return 0; } if (data) { if (!length) *data = 0; else { const unsigned numWords = (length + sizeof (word_t) - 1) / sizeof (word_t); word_t* buf = new word_t[numWords]; if (fread (buf, 1, length, myFiles.arcs) != length) { assert (false); delete[] succ; delete[] buf; return 0; } BitPacker::inflate (buf[numWords - 1], (-length) % sizeof (word_t)); *data = buf; } } return succ; } bool Graph::eval (card_t state, const class Expression* cond) const { if (!cond) return true; class GlobalMarking* m = fetchState (state); bool accept = m->eval (*cond); delete m; return accept; } card_t* Graph::toPath (const PathMap& tree, card_t dest) { card_t* p = new card_t[1]; *p = 0; for (;;) { card_t* np = new card_t[++(*p) + 1]; memcpy (np, p, *p * sizeof *p); delete[] p; p = np; p[*p] = dest; PathMap::const_iterator i = tree.find (dest); if (i == tree.end ()) break; dest = i->second; } return p; } card_t* Graph::path (card_t state, card_t target, const class Expression* pathc) const { if (!eval (state, pathc) || !eval (target, pathc)) return 0; /** Visited states */ class BitVector visited (myNumStates); visited.assign (state, true); /** Search queue */ std::list sq; sq.push_front (CARD_T_MAX); /* mark for the next level */ sq.push_back (state); /** Arcs in the explored graph (target, source) */ PathMap p; for (;;) { if ((state = *sq.begin ()) == CARD_T_MAX) { sq.pop_front (); if (sq.empty ()) return 0; sq.push_back (CARD_T_MAX); state = *sq.begin (); } sq.pop_front (); assert (!sq.empty ()); assert (visited[state]); if (state == target) return toPath (p, target); if (card_t* succ = getSuccessors (state)) { for (assert (*succ > 0); *succ; (*succ)--) { card_t s = succ[*succ]; if (!visited.tset (s) && eval (s, pathc)) { sq.push_back (s); p.insert (PathMap::value_type (s, state)); } } delete[] succ; } } } card_t* Graph::path (card_t state, const class Expression& cond, const class Expression* pathc) const { if (!eval (state, pathc)) return 0; /** Visited states */ class BitVector visited (myNumStates); visited.assign (state, true); /** Search queue */ std::list sq; sq.push_front (CARD_T_MAX); /* mark for the next level */ sq.push_back (state); /** Arcs in the explored graph (target, source) */ PathMap p; for (;;) { if ((state = *sq.begin ()) == CARD_T_MAX) { sq.pop_front (); if (sq.empty ()) return 0; sq.push_back (CARD_T_MAX); state = *sq.begin (); } sq.pop_front (); assert (!sq.empty ()); assert (visited[state]); if (eval (state, &cond)) return toPath (p, state); if (card_t* succ = getSuccessors (state)) { for (assert (*succ > 0); *succ; (*succ)--) { card_t s = succ[*succ]; if (!visited.tset (s) && eval (s, pathc)) { sq.push_back (s); p.insert (PathMap::value_type (s, state)); } } delete[] succ; } } } card_t* Graph::rpath (card_t state, const class Expression& cond, const class Expression* pathc) const { if (!eval (state, pathc)) return 0; /** Visited states */ class BitVector visited (myNumStates); visited.assign (state, true); /** Search queue */ std::list sq; sq.push_front (CARD_T_MAX); /* mark for the next level */ sq.push_back (state); /** Arcs in the explored graph (target, source) */ PathMap p; for (;;) { if ((state = *sq.begin ()) == CARD_T_MAX) { sq.pop_front (); if (sq.empty ()) return 0; sq.push_back (CARD_T_MAX); state = *sq.begin (); } sq.pop_front (); assert (!sq.empty ()); assert (visited[state]); if (eval (state, &cond)) return toPath (p, state); for (fpos_t pos = getPredecessors (state); pos != FPOS_NONE;) { card_t s = getPredecessor (pos); if (!visited.tset (s) && eval (s, pathc)) { sq.push_back (s); p.insert (PathMap::value_type (s, state)); } } } } card_t* Graph::path (card_t state, const card_t* loop, const class Expression* pathc) const { if (!eval (state, pathc)) return 0; /** Visited states */ class BitVector visited (myNumStates); visited.assign (state, true); /** Search queue */ std::list sq; sq.push_front (CARD_T_MAX); /* mark for the next level */ sq.push_back (state); /** Arcs in the explored graph (target, source) */ PathMap p; for (;;) { if ((state = *sq.begin ()) == CARD_T_MAX) { sq.pop_front (); if (sq.empty ()) return 0; sq.push_back (CARD_T_MAX); state = *sq.begin (); } sq.pop_front (); assert (!sq.empty ()); assert (visited[state]); for (const card_t* l = loop + *loop; l > loop; l--) { if (state == *l) { card_t* q = toPath (p, state); // append the loop to the p card_t* r = new card_t[*q + *loop]; *r = *q + *loop - 1; memcpy (r + *loop, q + 1, *q * sizeof *q); delete[] q; q = r + *loop; const card_t* k = l; for (; l++ < loop + *loop; *--q = *l); for (l = loop + 1; l++ < k; *--q = *l); assert (q == r + 1); return r; } } if (card_t* succ = getSuccessors (state)) { for (assert (*succ > 0); *succ; (*succ)--) { card_t s = succ[*succ]; if (!visited.tset (s) && eval (s, pathc)) { sq.push_back (s); p.insert (PathMap::value_type (s, state)); } } delete[] succ; } } } bool Graph::flagErroneous (card_t number) { assert (number < myNumStates); #ifdef USE_MMAP UNALIGNED fpos_t& num = *DIRSLOT1 (number); #else // USE_MMAP fseek (myFiles.directory, DIRSLOT1 (number), SEEK_SET); fpos_t num; if (fread (&num, sizeof num, 1, myFiles.directory) != 1) assert (false); #endif // USE_MMAP if (::isFlagged (num)) return true; ::flag (num); #ifndef USE_MMAP fseek (myFiles.directory, -sizeof num, SEEK_CUR); if (fwrite (&num, sizeof num, 1, myFiles.directory) != 1) assert (false); #endif // !USE_MMAP return false; } bool Graph::isErroneous (card_t number) const { assert (number < myNumStates); #ifdef USE_MMAP return ::isFlagged (*DIRSLOT1 (number)); #else // USE_MMAP fseek (myFiles.directory, DIRSLOT1 (number), SEEK_SET); fpos_t num; if (fread (&num, sizeof num, 1, myFiles.directory) != 1) assert (false); return ::isFlagged (num); #endif // USE_MMAP } bool Graph::isProcessed (card_t number) const { fpos_t num; assert (number < myNumStates); #ifdef USE_MMAP num = *DIRSLOT2 (number); #else // USE_MMAP fseek (myFiles.directory, DIRSLOT2 (number), SEEK_SET); if (fread (&num, sizeof num, 1, myFiles.directory) != 1) assert (false); #endif // USE_MMAP return num != FPOS_NONE; } void Graph::addReverse (card_t source, card_t target) { myNumArcs++; #ifdef USE_MMAP UNALIGNED fpos_t& arcend = *DIRSLOT3 (target); const fpos_t arcoffset = arcend; const fpos_t len = myFiles.preds.len; arcend = myFiles.preds.len; myFiles.preds.len += (sizeof arcoffset) + (sizeof source); extend (myFiles.preds); char* buf = static_cast(myFiles.preds.addr) + len; *reinterpret_cast(buf) = source; *reinterpret_cast(buf + sizeof source) = arcoffset; #else // USE_MMAP fpos_t arcoffset; fseek (myFiles.directory, DIRSLOT3 (target), SEEK_SET); if (1 != fread (&arcoffset, sizeof arcoffset, 1, myFiles.directory)) { perror ("Graph::addReverse (): fread"); abort (); } fseek (myFiles.directory, -sizeof arcoffset, SEEK_CUR); fseek (myFiles.preds, 0, SEEK_END); fpos_t arcend = ftell (myFiles.preds); fwrite (&arcend, sizeof arcend, 1, myFiles.directory); fwrite (&source, sizeof source, 1, myFiles.preds); fwrite (&arcoffset, sizeof arcoffset, 1, myFiles.preds); #endif // USE_MMAP } maria-1.3.5/Graph/Graph.h0000644000175000017500000002355307643247662015262 0ustar msmakelamsmakela// Persistent reachability graph storage -*- c++ -*- #ifndef GRAPH_H_ # define GRAPH_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "BitBuffer.h" # include # include # include "file.h" /** @file Graph.h * Persistent, lossless reachability graph storage */ /* Copyright © 1999-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Persistent reachability graph storage */ class Graph { public: /** File offset */ typedef long fpos_t; /** nonexistent file offset */ # define FPOS_NONE (Graph::fpos_t (-1)) /** special offset indicating a deadlock state */ # define FPOS_DEAD (Graph::fpos_t (-2)) /** Graph files */ struct files { /** Directory */ file_t directory; /** State storage */ file_t states; /** Arc storage */ FILE* arcs; /** Predecessor state storage */ file_t preds; }; /** Addition status */ class AddStatus { public: /** Constructor * @param isNew_ flag: was the state just added to the graph? * @param number_ the state number */ AddStatus (bool isNew_, card_t number_) : isNew (isNew_), number (number_) { } /** Copy constructor */ AddStatus (const class AddStatus& old) : isNew (old.isNew), number (old.number) { } /** Assignment operator */ class AddStatus& operator= (const class AddStatus& old) { isNew = old.isNew, number = old.number; return *this; } /** Destructor */ ~AddStatus () {} /** flag: was the state just added to the graph? */ bool isNew; /** the state number */ card_t number; }; /** Constructor * @param net the net whose reachability graph this is */ explicit Graph (const class Net& net); /** Constructor * @param net the net whose reachability graph this is * @param filename name of the Petri Net file (NULL=read from graph file) * @param filebase base name for the graph files (generated if NULL) */ explicit Graph (const class Net& net, const char* filename, const char* filebase); private: /** Copy constructor */ explicit Graph (const class Graph& old); /** Assignment operator */ class Graph& operator= (const class Graph& old); public: /** Destructor */ ~Graph (); /** Determine the net whose reachability graph this is */ const class Net& getNet () const { return myNet; } /** Determine the number of arcs generated */ unsigned getNumArcs () const # ifdef USE_MMAP ; # else // USE_MMAP { return myNumArcs; } # endif // USE_MMAP /** Determine the name of the Petri Net */ const char* getFilename () const { return myFilename; } /** Determine the base name for the graph files */ const char* getFilebase () const { return myFilebase; } /** Open the reachability graph files * @param regenerate flag: true=ignore existing graph files * @return true if the files could be opened; false on error */ bool openFiles (bool regenerate); /** Set the LSTS output handler * @param lsts the output handler (NULL=none) */ void setLSTS (class LSTS* lsts); /** Get the LSTS output handler */ class LSTS* getLSTS () const { return myLSTS; } /** Add an encoded state to the graph * @param buf the encoded state * @param bytes size of the encoded state in bytes * @return {false,number} if the state already exists * {true,number} if the state was added */ const class AddStatus add (const void* buf, size_t bytes); /** Look up a state in the graph * @param buf the encoded state * @param bytes size of the encoded state in bytes * @return the state number, or CARD_T_MAX if not found */ card_t lookup (const void* buf, size_t bytes) const; /** Add an event to the graph * @param source the source state number * @param target the target state number */ void add (card_t source, card_t target); /** Update added events to the arc file and flag the source state processed * @param source the source state number * @param buf the encoded events * @param bytes size of the encoded events in bytes */ void addEvents (card_t source, const void* buf, size_t bytes); /** Get the number of states in the reachability graph */ size_t getNumStates () const # ifdef USE_MMAP ; # else // USE_MMAP { return myNumStates; } # endif // USE_MMAP public: /** Fetch an encoded state from the reachability graph * @param number number of the state * @param length (output) length of the encoded state in bytes * @param erroneous (output) flag: erroneous state * @return the encoded state, or NULL */ word_t* fetchState (card_t number, size_t& length, bool* erroneous) const; /** Get a state by number * @param number number of the state * @return the decoded state */ class GlobalMarking* fetchState (card_t number) const; /** Get the number of predecessor states of a state * @param state number of the state * @return number of directly preceding states */ card_t getNumPredecessors (card_t state) const; /** Fetch an offset to the predecessor records for a state * @param state number of the state * @return offset to the event storage (FPOS_NONE if none) */ fpos_t getPredecessors (card_t state) const; /** Fetch predecessor state numbers for a state * @param pos (in/out) offset to the event storage * @return number of the source state (pos==FPOS_NONE at end) */ card_t getPredecessor (fpos_t& pos) const; /** Fetch the successor arcs for a state * @param state number of the state * @param data (output) the encoded successors * @return amount and numbers of successor states */ card_t* getSuccessors (card_t state, word_t** data = 0) const; /** Evaluate a condition in a state * @param state the state * @param cond the condition (NULL=true) * @return whether the condition holds */ bool eval (card_t state, const class Expression* cond) const; /** Tree of paths */ typedef std::map PathMap; /** Extract a path from a leaf to the root of a tree * @param tree the tree * @param dest the leaf of the tree * @return the path */ static card_t* toPath (const PathMap& tree, card_t dest); /** Determine the shortest path from a state to a state * @param state the source state * @param target the target state * @param pathc condition that must hold in every state on the path * @return the amount and numbers of the states on the path */ card_t* path (card_t state, card_t target, const class Expression* pathc) const; /** Determine the shortest path to a state fulfilling a condition * @param state the source state * @param cond the condition * @param pathc condition that must hold in every state on the path * @return the amount and numbers of the states on the path */ card_t* path (card_t state, const class Expression& cond, const class Expression* pathc) const; /** Determine the shortest path from a state fulfilling a condition * @param state the target state * @param cond the condition * @param pathc condition that must hold in every state on the path * @return the amount and numbers of the states on the path */ card_t* rpath (card_t state, const class Expression& cond, const class Expression* pathc) const; /** Determine the shortest path to a loop state * @param state the source state * @param loop the amount and numbers of the states forming the loop * @param pathc condition that must hold in every state on the path * @return the amount and numbers of the states on the path */ card_t* path (card_t state, const card_t* loop, const class Expression* pathc) const; /** Flag a state erroneous * @param number the state number * @return whether the state already was flagged erroneous */ bool flagErroneous (card_t number); /** Determine whether a state is erroneous * @param number the state number */ bool isErroneous (card_t number) const; /** Determine whether a state has been processed * @param number the state number */ bool isProcessed (card_t number) const; private: /** Add a reverse arc to the graph * @param source source state number * @param target target state number */ void addReverse (card_t source, card_t target); private: /** The net whose reachability graph this is */ const class Net& myNet; /** Buffer for successor state numbers of events */ card_t* mySucc; # ifndef USE_MMAP /** Number of arcs */ unsigned myNumArcs; /** Number of states */ unsigned myNumStates; # endif // !USE_MMAP /** The state hash */ class BTree* myStates; # if defined __sgi || defined __DECCXX public: # endif // __sgi || __DECCXX /** The graph files */ struct files myFiles; # if defined __sgi || defined __DECCXX private: # endif // __sgi || __DECCXX /** Offset of the state directory in myDirectory */ fpos_t myDirectoryOffset; /** Name of the Petri Net */ const char* myFilename; /** Base name for the graph files */ const char* myFilebase; /** Labelled state transition system output for newly generated states */ class LSTS* myLSTS; }; #endif // GRAPH_H_ maria-1.3.5/Graph/GraphReporter.C0000644000175000017500000004722107643247662016736 0ustar msmakelamsmakela// Reporting successor states in graph-based analysis -*- c++ -*- /** @file GraphReporter.C * Interface for reporting successor states in graph-based analysis */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "GraphReporter.h" #include "Graph.h" #include "ComponentGraph.h" #include "SyncStates.h" #include "Net.h" #include "Transition.h" #include "Valuation.h" #include "Printer.h" #include "LSTS.h" #include "PropertyState.h" #include "GlobalMarking.h" #include "BitVector.h" #ifdef EXPR_COMPILE # include "Compilation.h" #endif // EXPR_COMPILE /** Report graph size statistics * @param states number of generated states * @param arcs number of generated arcs * @param pending number of unprocessed states * @param printer the output stream */ static void showProgress (card_t states, card_t arcs, card_t pending, const class Printer& printer) { printer.print (states); printer.printRaw (" states, "); printer.print (arcs); printer.printRaw (" arcs, "); printer.print (pending); printer.printRaw (" pending"); printer.finish (); } /** Decode a state for interpreter-based analysis * @param buf the encoded inflated state * @param net the model the state belongs to * @return the decoded state */ static class GlobalMarking* decode (const word_t* buf, const class Net& net) { assert (!!buf); class GlobalMarking* marking = new class GlobalMarking (net); marking->decode (*net.getInitMarking (), buf); return marking; } #ifdef EXPR_COMPILE /** Decoded a state for compiler-based analysis * @param net the net * @param buf the encoded deflated state * @param size length of the state in bytes * @param compilation interface to the compiled code * @return the decoded state */ static void decode (const class Net& net, word_t* buf, size_t size, const class Compilation& compilation) { assert (!!buf); compilation.stateDecode (net.getIndex (), buf, size); } #endif // EXPR_COMPILE GraphReporter::GraphReporter ( #ifdef EXPR_COMPILE const class Compilation* compilation, #endif // EXPR_COMPILE const class Net& net_, const class Printer& printer_, unsigned maxerrors, bool compress, bool local, bool flattened, unsigned threshold, class Graph& graph) : StateReporter ( #ifdef EXPR_COMPILE compilation, #endif // EXPR_COMPILE net_, printer_, maxerrors, compress, local, flattened), myThreshold (threshold), myGraph (graph), myComponents (0), myChildren (flattened || !net_.getNumChildren () ? 0 : new class GraphReporter*[net_.getNumChildren ()]), myVisited (0), myStates (), myStateNum (CARD_T_MAX), myTargetNum (CARD_T_MAX), myProcessed (false), myWeaklyFair (new unsigned[net.getNumMaxFair () + 1]), myStronglyFair (new unsigned[net.getNumMaxFair () + 1]), myAddOld (false) { if (!flattened) { class SyncStates* sync = myChildren ? new class SyncStates (net) : 0; class BitVector* visited = myChildren ? new class BitVector (1) : 0; for (unsigned i = net_.getNumChildren (); i--; ) { class Graph* g = new class Graph (net_.getChild (i)); if (!g->openFiles (true)) { delete g; myChildren[i] = 0; } else { myChildren[i] = new class GraphReporter ( #ifdef EXPR_COMPILE compilation, #endif // EXPR_COMPILE net_.getChild (i), printer_, maxerrors, compress, local, false, 0, *g); myChildren[i]->mySync = sync; myChildren[i]->myVisited = visited; } } } } GraphReporter::~GraphReporter () { if (!isFlattened ()) { if (myChildren) { delete (*myChildren)->mySync; delete (*myChildren)->myVisited; } for (unsigned i = net.getNumChildren (); i--; ) { if (!myChildren[i]) continue; delete &myChildren[i]->myGraph; delete myChildren[i]; } } delete myComponents; delete[] myChildren; delete[] myWeaklyFair; delete[] myStronglyFair; } class GraphReporter& GraphReporter::getChild (const unsigned* path) { class GraphReporter* r = this; if (path) { for (unsigned i = 1; i <= *path; i++) { assert (!r->isFlattened ()); assert (!!r->myChildren); assert (path[i] < r->net.getNumChildren ()); assert (!!r->myChildren[path[i]]); r = r->myChildren[path[i]]; } } return *r; } unsigned GraphReporter::strong (card_t state, const class Expression* cond) { assert (state < myGraph.getNumStates ()); if (myComponents) delete myComponents; myComponents = new class ComponentGraph (myGraph); return myComponents->compute (state, cond); } class SearchList& GraphReporter::getSuccessors (card_t state) { assert (myStates.empty ()); if (!(myProcessed = myGraph.isProcessed (state))) { myStates.push (state); StateReporter::analyze (StateReporter::Single); } else if (card_t* data = myGraph.getSuccessors (state)) { for (card_t i = 1; i <= *data; i++) myStates.push (data[i]); delete[] data; } return myStates; } class SearchList& GraphReporter::getSuccessors (const class Transition& transition) { class GlobalMarking* m = pop (false); assert (!!m); if (m) { transition.analyze (*m, *this); delete m; } return myStates; } card_t* GraphReporter::prepareFair (card_t state, word_t*& buf, class BitUnpacker*& u) { card_t* succ = myGraph.getSuccessors (state, &buf); if (succ) { assert (*succ && buf); #ifdef EXPR_COMPILE if (myCompilation) u = 0, myCompilation->eventInflate (buf, 0); else #endif // EXPR_COMPILE u = new class BitUnpacker (buf); } return succ; } unsigned* GraphReporter::computeFair (card_t state, class BitUnpacker* u, unsigned** strong) { #ifdef EXPR_COMPILE if (myCompilation) { assert (!u); if (enum Error err = myCompilation->eventDecode (!!strong)) { printer.printRaw ("fairness constraint at state "); printer.printState (state); printer.delimiter (':'); printer.printRaw (Valuation::msg (err)); printer.finish (); flagFatal (); return 0; } if (strong) *strong = myCompilation->getStronglyFair (); return myCompilation->getWeaklyFair (); } else { #endif // EXPR_COMPILE const class Transition* transition; class Valuation valuation; assert (!!u); net.decode (*u, transition, valuation, isFlattened ()); transition->computeWeaklyFair (valuation, myWeaklyFair); if (!valuation.isOK ()) { printer.printRaw ("weakly_fair "); error: printer.printQuoted (transition->getName ()); printer.printRaw ("at state "); printer.printState (state); printer.delimiter (':'); printer.linebreak (); valuation.display (printer); printer.finish (); flagFatal (); return 0; } if (strong) { transition->computeStronglyFair (valuation, myStronglyFair); if (!valuation.isOK ()) { printer.printRaw ("strongly_fair "); goto error; } *strong = myStronglyFair; } return myWeaklyFair; #ifdef EXPR_COMPILE } #endif // EXPR_COMPILE } const unsigned* GraphReporter::eval (card_t state, unsigned prop, const class PropertyState& ps) { #ifdef EXPR_COMPILE if (myCompilation) { size_t size; word_t* buf = myGraph.fetchState (state, size, 0); ::decode (net, buf, size, *myCompilation); delete[] buf; if (enum Error err = myCompilation->propEval (prop)) { printer.printRaw ("property "); printer.print (prop); printer.printRaw (" evaluation error at state "); printer.printState (state); printer.printRaw (":"); printer.delimiter (' '); printer.printRaw (Valuation::msg (err)); printer.finish (); flagFatal (); return 0; } return myCompilation->getPropSucc (); } else { #endif /** vector of enabled gates in the property automaton */ unsigned* enabled; class GlobalMarking* m = myGraph.fetchState (state); class Valuation valuation; valuation.setGlobalMarking (m); if (!ps.eval (valuation, enabled)) { printer.printRaw ("property "); printer.print (prop); printer.printRaw (" evaluation error at state "); printer.printState (state); printer.printRaw (":"); printer.finish (); valuation.display (printer); printer.finish (); delete[] enabled; enabled = 0; flagFatal (); } else assert (valuation.isOK ()); delete m; return enabled; #ifdef EXPR_COMPILE } #endif // EXPR_COMPILE } void GraphReporter::analyzeModular (enum SearchKind kind) { assert (!isFlattened ()); const unsigned numTr = net.getNumTransitions (); extern bool interrupted; #ifdef EXPR_COMPILE if (myCompilation) { while (!interrupted && !myFatal) { if (!popCompiled (kind == Breadth)) break; myProcessed = myGraph.isProcessed (myStateNum); mySrcDeadlock = true, myPriority = 0; unsigned i; for (i = 0; !interrupted && !myFatal && i < numTr; i++) { const class Transition& t = net.getTransition (i); if ((!myPriority || t.getPriority () == myPriority) && !t.getNumChildren ()) analyze (t); // synchronisation transitions (which have children) are analysed // by SyncStates::sync (), called below } if (myChildren) { i = net.getNumChildren (); word_t** srcs = new word_t*[i]; // analyze child state spaces for (; !interrupted && !myFatal && i--; ) { const class Net& child = net.getChild (i); unsigned bytes; const void* buf = myCompilation->stateProject (child.getIndex (), 0, 0, bytes); unsigned numWords = bytes ? (bytes - 1) / sizeof (word_t) + 1 : 0; /* back up the source state */ srcs[i] = bytes ? new word_t[numWords] : 0; memcpy (srcs[i], buf, numWords * sizeof (word_t)); BitPacker::inflate (srcs[i][numWords - 1], (-bytes) % sizeof (word_t)); #ifdef SYNC_CACHE if ((*myChildren)->mySync->lookup (i, srcs[i], numWords)) continue; // the modular state has already been analyzed #endif // SYNC_CACHE class GraphReporter& reporter = *myChildren[i]; class Graph::AddStatus src = reporter.myGraph.add (buf, bytes); reporter.init (src.number); reporter.myVisited->clear (); reporter.myVisited->extend (src.number, true); unsigned numErrors = reporter.getNumErrors (); reporter.analyzeModular (Breadth); /* restore the source state */ myCompilation->stateDecode (child.getIndex (), srcs[i], 0); if (reporter.myFatal) myFatal = true; if (reporter.getNumErrors () > numErrors) reportError (false); } // find out enabled synchronisation transitions and synchronise for (i = net.getNumTransitions (); i--; ) { const class Transition& t = net.getTransition (i); if ((!myPriority || t.getPriority () == myPriority) && t.getNumChildren ()) (*myChildren)->mySync->sync (t, *this, srcs); } for (i = net.getNumChildren (); i--; ) delete[] srcs[i]; delete[] srcs; #ifndef SYNC_CACHE (*myChildren)->mySync->cleanup (); #endif // !SYNC_CACHE } if (mySrcDeadlock && !interrupted && !myFatal) { switch (myCompilation->stateDeadlock (net.getIndex ())) { case errNone: break; default: myFatal = true; // fall through case errComp: reportError (true); } } if (suppress ()) continue; addEvents (); if (kind >= Single) break; } return; } else #endif // EXPR_COMPILE while (!interrupted && !myFatal) { class GlobalMarking* m = pop (kind == Breadth); if (!m) break; myProcessed = myGraph.isProcessed (myStateNum); mySrcDeadlock = true, myPriority = 0; unsigned i; for (i = 0; !interrupted && !myFatal && i < numTr; i++) { const class Transition& t = net.getTransition (i); if ((!myPriority || t.getPriority () == myPriority) && !t.getNumChildren ()) t.analyze (*m, *this); // synchronisation transitions (which have children) are analysed // by SyncStates::sync (), called below } if (myChildren) { // analyze child state spaces for (i = net.getNumChildren (); !interrupted && !myFatal && i--; ) { const class Net& child = net.getChild (i); m->encode (myStateBuf, child); #ifdef SYNC_CACHE if ((*myChildren)->mySync->lookup (i, myStateBuf.getBuf (), myStateBuf.getNumWords ())) continue; // the modular state has already been analyzed #endif // SYNC_CACHE myStateBuf.deflate (); class GraphReporter& reporter = *myChildren[i]; class Graph::AddStatus src = reporter.myGraph.add (myStateBuf.getBuf (), myStateBuf.getNumBytes ()); reporter.init (src.number); reporter.myVisited->clear (); reporter.myVisited->extend (src.number, true); unsigned numErrors = reporter.getNumErrors (); reporter.analyzeModular (Breadth); if (reporter.myFatal) myFatal = true; if (reporter.getNumErrors () > numErrors) reportError (false); } // find out enabled synchronisation transitions and synchronise for (i = net.getNumTransitions (); i--; ) { const class Transition& t = net.getTransition (i); if ((!myPriority || t.getPriority () == myPriority) && t.getNumChildren ()) (*myChildren)->mySync->sync (*m, t, *this); } #ifndef SYNC_CACHE (*myChildren)->mySync->cleanup (); #endif // !SYNC_CACHE } if (mySrcDeadlock && !interrupted && !myFatal) { switch (net.isDeadlock (*m, false)) { case Net::OK: break; case Net::Fatal: myFatal = true; // fall through case Net::Error: reportError (true); } } delete m; if (suppress ()) continue; addEvents (); if (kind >= Single) break; } } bool GraphReporter::do_addState (const void* state, size_t size) { bool isNew = do_addStateOnly (state, size); if (myVisited) { if (myTargetNum >= myVisited->getSize ()) myVisited->extend (myTargetNum, true); else if (myVisited->tset (myTargetNum)) { assert (!isNew); return false; } } if (myVisited || isNew || myAddOld) myStates.push (myTargetNum); return isNew; } bool GraphReporter::do_addStateOnly (const void* state, size_t size) { if (myProcessed) { myTargetNum = myGraph.lookup (state, size); assert (myTargetNum != CARD_T_MAX); return false; } class Graph::AddStatus target = myGraph.add (state, size); myGraph.add (myStateNum, myTargetNum = target.number); if (myThreshold && !(myGraph.getNumArcs () % myThreshold)) ::showProgress (myGraph.getNumStates (), myGraph.getNumArcs (), myStates.size (), printer); return target.isNew; } word_t* GraphReporter::do_popState (bool tail, size_t& size) { if (myStates.empty ()) return 0; myStateNum = myStates.pop (tail); assert (!isFlattened () || !myGraph.isProcessed (myStateNum)); return myGraph.fetchState (myStateNum, size, 0); } class GlobalMarking* GraphReporter::pop (bool breadth) { return popState (breadth) ? inflate (), ::decode (mySrc, net) : 0; } #ifdef EXPR_COMPILE bool GraphReporter::popCompiled (bool breadth) { assert (!!myCompilation); if (popState (breadth)) ::decode (net, mySrc, mySrcSize, *myCompilation); return !!mySrc; } #endif // EXPR_COMPILE void GraphReporter::addEvents () { #ifdef EXPR_COMPILE if (myCompilation) { if (!myProcessed) { size_t bytes; const void* buf = myCompilation->eventDeflate (bytes); myGraph.addEvents (myStateNum, buf, bytes); } myCompilation->eventClear (); } else { #endif // EXPR_COMPILE if (!myProcessed) { myEventBuf.deflate (); myGraph.addEvents (myStateNum, myEventBuf.getBuf (), myEventBuf.getNumBytes ()); } myEventBuf.clear (); #ifdef EXPR_COMPILE } #endif // EXPR_COMPILE } bool GraphReporter::report (const class Transition& transition, const class Valuation& valuation, const class GlobalMarking& marking, bool rejected) { myStateBuf.deflate (); bool isNew; if (transition.getName ()) { const bool hidden = transition.isHidden (valuation); isNew = rejected ? do_addStateOnly (myStateBuf.getBuf (), myStateBuf.getNumBytes ()) : addState (myStateBuf.getBuf (), myStateBuf.getNumBytes (), hidden); if (rejected || !hidden || !isReduced ()) net.encode (myEventBuf, transition, valuation, isFlattened ()); if (isNew && myGraph.getLSTS ()) myGraph.getLSTS ()->outputState (marking, myTargetNum); } else { // do not add arcs for anonymous (interactively defined) transitions class Graph::AddStatus target = myGraph.add (myStateBuf.getBuf (), myStateBuf.getNumBytes ()); isNew = target.isNew; myTargetNum = target.number; } if (rejected) { if (isNew) { myGraph.flagErroneous (myTargetNum); printer.printRaw (myFatal ? "fatally rejected state " : "rejected state "); printer.printState (myTargetNum); } else { printer.printRaw (myFatal ? "fatally rejected state reachable from " : "rejected state reachable from "); printer.printState (myStateNum); } printer.finish (); if (error ()) flagFatal (); } return isNew; } void GraphReporter::reportError (bool deadlock) { if (deadlock) printer.printRaw (myFatal ? "fatal deadlock state " : "deadlock state "); else { myGraph.flagErroneous (myStateNum); printer.printRaw (myFatal ? "fatally rejected subnet state reachable from " : "rejected subnet state reachable from "); } printer.printState (myStateNum); printer.finish (); if (error ()) myFatal = true; if (myFatal) myStates.clear (); } #ifdef EXPR_COMPILE bool GraphReporter::report (const void* state, size_t size, bool rejected, bool hidden) { assert (!!myCompilation); const bool isNew = rejected ? do_addStateOnly (state, size) : addState (state, size, hidden); if (isNew && myGraph.getLSTS ()) myGraph.getLSTS ()->outputState (*myCompilation, myTargetNum); if (rejected) { myGraph.flagErroneous (myTargetNum); printer.printRaw (myFatal ? "fatally rejected state " : "rejected state "); printer.printState (myTargetNum); printer.finish (); if (error ()) flagFatal (); } return isNew; } #endif // EXPR_COMPILE void GraphReporter::reject () { printer.printState (myStateNum); printer.delimiter (':'); if (myFatal) myStates.clear (); } void GraphReporter::printState (const class GlobalMarking& m, card_t state, const class Printer& out) { out.printState (state); if (!isFlattened () && net.getNumChildren ()) { out.delimiter ('('); for (unsigned i = 0; i < net.getNumChildren (); ) { const class Net& child = net.getChild (i); m.encode (myStateBuf, child); myStateBuf.deflate (); card_t s = myChildren[i]->myGraph.lookup (myStateBuf.getBuf (), myStateBuf.getNumBytes ()); if (s != CARD_T_MAX) out.printState (s); else out.printRaw ("@?"); if (++i >= net.getNumChildren ()) break; out.delimiter (' '); } out.delimiter (')'); } } maria-1.3.5/Graph/GraphReporter.h0000644000175000017500000002312007643247662016773 0ustar msmakelamsmakela// Reporting successor states in graph-based analysis -*- c++ -*- #ifndef GRAPHREPORTER_H_ # define GRAPHREPORTER_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "StateReporter.h" # include "Search.h" /** @file GraphReporter.h * Interface for reporting successor states in graph-based analysis */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Reporting successor states in graph-based analysis */ class GraphReporter : public StateReporter { public: /** Constructor * @param compilation the compiled model (optional) * @param net_ the net that is being analysed * @param printer_ printer object for diagnostic output * @param maxerrors maximum number of allowed errors (0=infinity) * @param compress flag: collapse deterministic sequences? * @param local flag: suppress transient (invisible) states? * @param flattened flag: consider the flattened net? * @param threshold threshold for reporting state space statistics * @param graph the reachability graph being generated */ GraphReporter ( #ifdef EXPR_COMPILE const class Compilation* compilation, #endif // EXPR_COMPILE const class Net& net_, const class Printer& printer_, unsigned maxerrors, bool compress, bool local, bool flattened, unsigned threshold, class Graph& graph); private: /** Copy constructor */ GraphReporter (const class GraphReporter& old); /** Assignment operator */ class GraphReporter& operator= (const class GraphReporter& other); public: /** Destructor */ ~GraphReporter (); /** Get a reference to the reachability graph */ const class Graph& getGraph () const { return myGraph; } /** Get the graph of strongly connected components */ const class ComponentGraph* getComponents () const { return myComponents; } /** Get a GraphReporter by module * @param path amount and indexes of path components (subnets) */ class GraphReporter& getChild (const unsigned* path); /** Get a GraphReporter by module * @param path amount and indexes of path components (subnets) */ const class GraphReporter& getChild (const unsigned* path) const { return const_cast(this)->getChild (path); } /** Compute the strongly connected components for this graph * @param state start state of the search * @param cond condition for exploring states (NULL=true) * @return number of strongly connected components (0=fail) */ unsigned strong (card_t state, const class Expression* cond); /** Initialize the search list * @param state the state to be analyzed */ void init (card_t state) { assert (myStates.empty ()); myStates.push (state); } /** Assign the addOld flag */ void setAddOld (bool addOld) { myAddOld = addOld; } /** Retrieve the successors of a state * @param state the state to be analyzed * @return the successors of the state (must be cleared by caller) */ class SearchList& getSuccessors (card_t state); /** Analyze an anonymous transition * @param transition the transition * @return the successor states (must be cleared by caller) */ class SearchList& getSuccessors (const class Transition& transition); /** Prepare for computing the enabled fairness sets * @param state the state to be analyzed * @param buf (output) the encoded event labels (deleted by caller) * @param u (output) the bit unpacker object (deleted by caller) * @return the successors of the state (deleted by caller) */ card_t* prepareFair (card_t state, word_t*& buf, class BitUnpacker*& u); /** Compute the enabled fairness sets * @param state the state being analyzed (for diagnostics) * @param u the bit unpacker object from prepareFair () * @param strong (output) the enabled strong fairness sets (optional) * (static allocation; not deleted by caller) * @return amount and numbers of enabled weak fairness sets * (static allocation; not deleted by caller) */ unsigned* computeFair (card_t state, class BitUnpacker* u, unsigned** strong); /** Evaluate the gates of a property automaton * @param state the state number of the reachability graph * @param prop the state number of the property automaton * @param ps current state in the property automaton * @return the amount and numbers of enabled successor states */ const unsigned* eval (card_t state, unsigned prop, const class PropertyState& ps); /** Finish evaluating the gates of a property automaton * @param enabled an array of enabled states returned by eval () */ #ifdef EXPR_COMPILE void eval_done (const unsigned* enabled) const #else static void eval_done (const unsigned* enabled) #endif // EXPR_COMPILE { #ifdef EXPR_COMPILE if (!myCompilation) #endif // EXPR_COMPILE delete[] enabled; } /** Search the state space in a modular way * @param kind Type of search */ void analyzeModular (enum SearchKind kind); private: /** Add an encoded state to the state space * @param state the encoded state * @param size length of the encoded state in bytes * @return true if the state was new */ bool do_addState (const void* state, size_t size); /** Add an encoded state to the state space, but do not enqueue it * @param state the encoded state * @param size length of the encoded state in bytes * @return true if the state was new */ bool do_addStateOnly (const void* state, size_t size); /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @param size (output) length of the encoded stream * @return the encoded state, or NULL if none available */ word_t* do_popState (bool tail, size_t& size); /** Dequeue an unprocessed state * @param breadth true=dequeue (FIFO, queue), false=pop (LIFO, stack) * @return an unprocessed state, or NULL if all processed */ class GlobalMarking* pop (bool breadth); #ifdef EXPR_COMPILE /** Dequeue an unprocessed state * @param breadth true=dequeue (FIFO, queue), false=pop (LIFO, stack) * @return true if a state was found, or false if all processed */ bool popCompiled (bool breadth); /** Determine whether arcs should be generated */ bool isGraph () const { return true; } #endif // EXPR_COMPILE /** Add all events from the current source state to the graph */ void addEvents (); /** Report a successor state * @param transition the transition fired * @param valuation the binding of the transition * @param marking the resulting marking * @param rejected flag: is the state rejected? * @return true if the state was new */ bool report (const class Transition& transition, const class Valuation& valuation, const class GlobalMarking& marking, bool rejected); /** Report a deadlock or an error in the current state * @param deadlock flag: is this a deadlock? */ void reportError (bool deadlock); public: #ifdef EXPR_COMPILE /** Report a successor state * @param state the resulting encoded deflated state (mandatory) * @param size length of the encoded state, in bytes * @param rejected flag: is the state rejected? * @param hidden flag: is the transition to the state hidden? * @return true if the state was new */ bool report (const void* state, size_t size, bool rejected, bool hidden); #endif // EXPR_COMPILE private: /** Report an inconsistent successor state */ void reject (); public: /** Display a state number * @param m the state (to be decomposed into module states) * @param state the state number * @param out the output stream */ void printState (const class GlobalMarking& m, card_t state, const class Printer& out); private: /** Threshold for reporting intermediate statistics */ const unsigned myThreshold; /** The reachability graph being constructed */ class Graph& myGraph; /** Graph of strongly connected components (optional) */ class ComponentGraph* myComponents; /** GraphReporters for modules (only for non-flattened analysis) */ class GraphReporter** const myChildren; /** Table for keeping track of visited states in non-flattened analysis */ class BitVector* myVisited; /** Buffer for encoding events */ class BitPacker myEventBuf; /** List of unprocessed states */ class SearchList myStates; /** Number of the state being analyzed */ card_t myStateNum; /** Number of the state last generated (set by do_addState) */ card_t myTargetNum; /** Flag: is myStateNum being revisited? */ bool myProcessed; /** Work area for computing enabled weak fairness sets */ unsigned* myWeaklyFair; /** Work area for computing enabled strong fairness sets */ unsigned* myStronglyFair; /** Flag: add also existing states to the state list */ bool myAddOld; }; #endif // GRAPHREPORTER_H_ maria-1.3.5/Graph/HashGraph.C0000644000175000017500000001211507643247662016011 0ustar msmakelamsmakela// Probabilistic reachability set storage -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "HashGraph.h" #include "ByteBuffer.h" #include #include #include /** @file HashGraph.C * Transient, probabilistic reachability set storage */ /* Copyright © 2001-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Number of bits size_t holds */ #define SIZE_T_BIT (sizeof (size_t) * CHAR_BIT) /** primes[x] == prime closest to 32 << x */ static unsigned primes[] = { 0x1f, 0x3d, 0x7f, 0x101, 0x1fd, 0x3fd, 0x805, 0xffd, 0x1fff, 0x3ffd, 0x8003, 0xfff1, 0x1ffff, 0x3fffb, 0x7ffff, 0xffffd, 0x1ffff7, 0x3ffffd, 0x7ffff1, 0xfffffd, 0x2000023, 0x3fffffb, 0x800001d, 0x10000003, 0x1ffffffd, 0x40000003, 0x7fffffff, 0xfffffffb }; HashGraph::~HashGraph () { for (unsigned s = myNumTables; s--; ) { free (myHashes[s]); free (myHashers[s]); } free (myHashes); free (myHashers); } bool HashGraph::init (unsigned numTables, unsigned& funcSize, unsigned& hashSize) { assert (!myHashes && !myHashers && !myNumTables && !getNumStates ()); if (!openFile ()) return false; unsigned s; /* round the hash function size to the next power of 2 */ for (s = 2; s < funcSize && sizeof (size_t) * s << 1; s <<= 1); funcSize = s; /* round the hash table size to the closest prime in our table */ for (s = 0; s < ((sizeof primes) / sizeof *primes) - 1; s++) if (primes[s] >= hashSize) break; hashSize = primes[s]; s = 1 + (hashSize - 1) / SIZE_T_BIT; /* allocate the tables */ if (!(myHashers = static_cast(calloc (numTables, sizeof *myHashers))) || !(myHashes = static_cast(calloc (numTables, sizeof *myHashes)))) { failure: if (myHashers) free (myHashers), myHashers = 0; if (myHashes) free (myHashes), myHashes = 0; return false; } unsigned t; for (t = numTables; t--; ) { if (!(myHashers[t] = static_cast(calloc (funcSize, sizeof *myHashers[t]))) || !(myHashes[t] = static_cast(calloc (s, sizeof *myHashes[t])))) { for (; t < numTables; t++) free (myHashers[t]), free (myHashes[t]); goto failure; } } /* Initialize the tables for the hash functions */ srand (time (0)); for (t = numTables; t--; ) for (s = funcSize; s--; ) myHashers[t][s] = size_t ((hashSize + double (1)) * rand () / (RAND_MAX + double (1))); myNumTables = numTables; myFuncSize = funcSize - 1; myHashSize = hashSize; return true; } bool HashGraph::do_add (const void* buf, size_t size) { /** flag: was the state found? */ bool found = true; /** the encoded byte stream */ const char* state = reinterpret_cast(buf); for (unsigned t = myNumTables; t--; ) { /* compute the hash value */ size_t h = 0; const size_t* hasher = myHashers[t]; for (size_t s = size; s--; ) h += state[s] * hasher[s & myFuncSize]; /* test and set the corresponding bit in the hash table */ h %= myHashSize; size_t& ht = myHashes[t][h / SIZE_T_BIT]; size_t mask = size_t (1) << (h % SIZE_T_BIT); if (!(ht & mask)) ht |= mask, found = false; } if (found) return false; newState (); assert (myPathFileLength == ftell (myPathFile)); assert (!myOffset || myOffset < myPathFileLength); mySearch.push (buf, size, myPathFileLength); class BytePacker p; p.append (myOffset), p.append (size); fwrite (p.getBuf (), 1, p.getLength (), myPathFile); fwrite (buf, 1, size, myPathFile); myPathFileLength += p.getLength () + size; return true; } word_t* HashGraph::getState (long pos, size_t* size) const { unsigned char rbuf[8]; class ByteUnpacker u (rbuf); assert (pos < myPathFileLength); fseek (myPathFile, pos, SEEK_SET); fread (rbuf, sizeof rbuf, 1, myPathFile); unsigned offset = u.extract (); unsigned len = u.extract (); u.buf = rbuf; word_t* state = new word_t[len + (sizeof (word_t) - 1) / sizeof (word_t)]; fseek (myPathFile, pos + BytePacker::size (offset) + BytePacker::size (len), SEEK_SET); fread (state, 1, len, myPathFile); *size = len; return state; } word_t* HashGraph::pop (bool tail, size_t& size) { if (mySearch.empty ()) return 0; return mySearch.pop (tail, myOffset, &size); } maria-1.3.5/Graph/HashGraph.h0000644000175000017500000000622707643247662016065 0ustar msmakelamsmakela// Probabilistic reachability set storage -*- c++ -*- #ifndef HASHGRAPH_H_ # define HASHGRAPH_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "StateSet.h" /** @file HashGraph.h * Transient, probabilistic reachability set storage */ /* Copyright © 2001-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Probabilistic reachability set storage */ class HashGraph : public StateSet { public: /** Constructor */ HashGraph () : StateSet (), myNumTables (0), myFuncSize (0), myHashSize (0), myHashers (0), myHashes (0) {} private: /** Copy constructor */ HashGraph (const class HashGraph& old); /** Assignment operator */ class HashGraph& operator= (const class HashGraph& old); public: /** Destructor */ ~HashGraph (); /** Initialize the hash tables * @param numTables number of hash tables * @param funcSize (in/out) number of elements in the hash functions * @param hashSize (in/out) number of elements in the hash tables * @return true if the initialization succeeded */ bool init (unsigned numTables, unsigned& funcSize, unsigned& hashSize); private: /** Add a state to the graph * @param state the encoded state * @param size length of the encoded state, in bytes * @return true if the state was enqueued to mySearch */ bool do_add (const void* state, size_t size); protected: /** Get a deflated state from myPathFile * @param pos file offset to the state * @param size (output) length of the encoded state */ word_t* getState (long pos, size_t* size) const; public: /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @param size (output) length of the encoded stream * @return the encoded state */ word_t* pop (bool tail, size_t& size); private: /** Fetch a state from a counterexample path * @param u cursor to the counterexample path * @return the encoded state, inflated */ word_t* getState (class ByteUnpacker& u) const; /** Number of hash tables */ unsigned myNumTables; /** Number of elements in the hash function tables (power of 2) */ unsigned myFuncSize; /** Number of elements in the hash tables (power of 2) */ unsigned myHashSize; /** The hash functions */ size_t** myHashers; /** The hash tables */ size_t** myHashes; }; #endif // HASHGRAPH_H_ maria-1.3.5/Graph/LSTS.C0000644000175000017500000002310510254524032014707 0ustar msmakelamsmakela// Labelled state transition system output interface -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "LSTS.h" #include "Graph.h" #include "GlobalMarking.h" #include "Net.h" #include "Transition.h" #include "Valuation.h" #include "VariableDefinition.h" #include "Expression.h" #include "Printer.h" /** @file LSTS.C * Labelled state transition system output interface */ /* Copyright © 2001-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Suffix for the transition file (the longest suffix) */ static const char transitionSuffix[] = "-trans"; /** Suffix for the action file */ static const char actionSuffix[] = "-act"; /** Print a string in special escaped format * @param name the string to be printed * @param file the output stream */ static void escapeString (const char* name, FILE* file) { while (*name) { register const char c = *name++; /* We cannot use isprint () here, as some LSTS processing tools might expect the ASCII character set. */ if ((c >= 0 && c < 040) || (c >= char (0200) && c < char (0240)) || (c == '"' || c == '\\' || c == 0177)) fprintf (file, "\\%02x", static_cast(c)); else putc (c, file); } } LSTS::LSTS (const class Net& net, const char* filebase) : myNet (net), myFilebase (newString (filebase)), myNumProps (net.getNumProps ()), myNumStates (0), myNumTransitions (0), myActionSet (), myProps (new FILE*[net.getNumProps ()]), myTransitions (0), myActions (0), myIndex (0) { assert (!!filebase); memset (myProps, 0, myNumProps * sizeof *myProps); } LSTS::~LSTS () { unsigned prop; for (Set::iterator i = myActionSet.begin (); i != myActionSet.end (); i++) operator delete (*i); if (myTransitions) { fputs ("End Transitions\n", myTransitions); fclose (myTransitions); } if (myActions) { fputs ("End Action_names\n", myActions); fclose (myActions); } if (myIndex) { fprintf (myIndex, "LSTS_File\n" "Begin Header\n" "State_cnt=%u\n" "Action_cnt=%u\n" "Transition_cnt=%u\n" "State_prop_cnt=%u\n" "Initial_state=1\n" "End Header\n", myNumStates, unsigned (myActionSet.size ()), myNumTransitions, myNumProps); fputs ("Include Action_names From \"", myIndex); escapeString (myFilebase, myIndex); escapeString (actionSuffix, myIndex); fputs ("\"\n" "Begin State_props\n", myIndex); for (prop = 0; prop < myNumProps; prop++) { FILE* f = myProps[prop]; static char buf[BUFSIZ]; rewind (f); while (size_t len = fread (buf, 1, sizeof buf, f)) fwrite (buf, 1, len, myIndex); fputs (";\n", myIndex); } fputs ("End State_props\n" "Include Transitions From \"", myIndex); escapeString (myFilebase, myIndex); escapeString (transitionSuffix, myIndex); fputs ("\"\n" "End_LSTS\n", myIndex); fclose (myIndex); } for (prop = myNumProps; prop--; ) if (myProps[prop]) fclose (myProps[prop]); delete[] myProps; delete[] myFilebase; } bool LSTS::openFiles () { assert (!myNumStates && !myNumTransitions && myActionSet.empty ()); assert (!myTransitions && !myActions); size_t len = strlen (myFilebase); char* filename = new char[len + sizeof transitionSuffix]; memcpy (filename, myFilebase, len); class Printer printer (0, Printer::Decimal); for (unsigned prop = myNumProps; prop--; ) { if (!(myProps[prop] = tmpfile ())) goto fail; printer.setOutput (myProps[prop]); printer.printQuoted (myNet.getPropName (prop)); fputc (':', myProps[prop]); } memcpy (filename + len, transitionSuffix, sizeof transitionSuffix); if (!(myTransitions = fopen (filename, "w"))) goto fail; fputs ("Begin Transitions\n", myTransitions); memcpy (filename + len, actionSuffix, sizeof actionSuffix); if (!(myActions = fopen (filename, "w"))) goto fail; fputs ("Begin Action_names\n", myActions); if (!(myIndex = fopen (myFilebase, "w"))) goto fail; delete[] filename; return true; fail: fputs (filename, stderr); fputs (": ", stderr); perror ("fopen"); delete[] filename; return false; } /** Context for reporting properties */ struct propcontext { card_t state; ///< the state number FILE** props; ///< array of property files }; /** Report a state property that holds * @param prop number of the property * @param data the context */ static bool outputProp (unsigned prop, const void* data) { const struct propcontext& p = *static_cast(data); fprintf (p.props[prop], " %u", p.state); return true; } void LSTS::outputState (const class GlobalMarking& m, card_t state) { assert (&myNet == &m.getNet ()); const struct propcontext p = { state + 1, myProps }; if (myNumStates <= state) myNumStates = state + 1; if (!myNet.checkProps (m, ::outputProp, &p)) assert (false); } #ifdef EXPR_COMPILE # include "Compilation.h" void LSTS::outputState (const class Compilation& compilation, card_t state) { const struct propcontext p = { state + 1, myProps }; if (myNumStates <= state) myNumStates = state + 1; if (!compilation.checkProps (::outputProp, &p)) assert (false); } #endif // EXPR_COMPILE void LSTS::outputArc (card_t source, card_t target, const class Transition& transition, const class Valuation& valuation) { assert (valuation.isOK ()); fprintf (myTransitions, "%u", source + 1); class BitPacker out; class StringBuffer sbuf; unsigned action = 0; myNumTransitions++; if (!transition.isHidden (valuation)) { // convert the action to canonic form (no values of hidden variables) out.clear (); if (myNet.getNumTransitions () > 1) out.append (transition.getRootIndex (), log2 (myNet.getNumAllTransitions ())); else assert (myNet.getNumTransitions () == 1); for (Transition::const_iterator i = transition.begin (); i != transition.end (); i++) { if (i->second->isHidden ()) continue; const class Value* value = valuation.getValue (*i->second); if (i->second->isUndefined ()) out.append (!value, 1); else assert (!!value); if (value) out.append (*value); } out.deflate (); size_t* b = static_cast (operator new (out.getNumBytes () + 2 * sizeof *b)); memcpy (b + 2, out.getBuf (), *b = out.getNumBytes ()); // determine if this is a new action std::pair p = myActionSet.insert (b); if (p.second) { action = b[1] = myActionSet.size (); fprintf (myActions, "%u=\"", action); sbuf.append (transition.getName ()); sbuf.escape (0); valuation.displayEscaped (sbuf, true); fwrite (sbuf.getString (), 1, sbuf.getLength (), myActions); sbuf.create (0); fputs ("\"\n", myActions); } else { operator delete (b); action = (*p.first)[1]; } } fprintf (myTransitions, " %u %u", target + 1, action); fputs (";\n", myTransitions); } void LSTS::outputArcs (const class Graph& graph, card_t source, const card_t* targets, word_t* buf) { assert (targets && *targets && buf); fprintf (myTransitions, "%u", source + 1); class BitUnpacker in (buf); class BitPacker out; class StringBuffer sbuf; for (card_t i = 1; i <= *targets; i++) { const class Transition* transition; class Valuation v; unsigned action = 0; myNet.decode (in, transition, v, true); assert (transition && v.isOK ()); myNumTransitions++; if (!transition->isHidden (v)) { // convert the action to canonic form (no values of hidden variables) out.clear (); if (myNet.getNumTransitions () > 1) out.append (transition->getRootIndex (), log2 (myNet.getNumAllTransitions ())); else assert (myNet.getNumTransitions () == 1); for (Transition::const_iterator t = transition->begin (); t != transition->end (); t++) { if (t->second->isHidden ()) continue; const class Value* value = v.getValue (*t->second); if (t->second->isUndefined ()) out.append (!value, 1); else assert (!!value); if (value) out.append (*value); } out.deflate (); size_t* b = static_cast (operator new (out.getNumBytes () + 2 * sizeof *b)); memcpy (b + 2, out.getBuf (), *b = out.getNumBytes ()); // determine if this is a new action std::pair p = myActionSet.insert (b); if (p.second) { action = b[1] = myActionSet.size (); fprintf (myActions, "%u=\"", action); sbuf.append (transition->getName ()); sbuf.escape (0); v.displayEscaped (sbuf, true); fwrite (sbuf.getString (), 1, sbuf.getLength (), myActions); sbuf.create (0); fputs ("\"\n", myActions); } else { operator delete (b); action = (*p.first)[1]; } } fprintf (myTransitions, " %u %u", targets[i] + 1, action); } fputs (";\n", myTransitions); } maria-1.3.5/Graph/LSTS.h0000644000175000017500000001002007643247662014767 0ustar msmakelamsmakela// Labelled state transition system output interface -*- c++ -*- #ifndef LSTS_H_ # define LSTS_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "BitBuffer.h" # include # include /** @file LSTS.h * Labelled state transition system output interface */ /* Copyright © 2001-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Interface for outputting labelled state transition systems */ class LSTS { public: /** Less-than comparison for encoded actions */ struct ltact { /** Compare two encoded actions (length-tagged memory areas) * @param a1 first action to compare * @param a2 second action to compare * @return true if act1 sorts before act2 */ bool operator () (const size_t* a1, const size_t* a2) const { return *a1 < *a2 || (*a1 == *a2 && memcmp (a1 + 2, a2 + 2, *a1) < 0); } }; /** Set of encoded actions */ typedef std::set Set; /** Constructor * @param net the net * @param filebase base name for the files */ LSTS (const class Net& net, const char* filebase); private: /** Copy constructor */ LSTS (const class LSTS& old); /** Assignment operator */ class LSTS& operator= (const class LSTS& old); public: /** Destructor */ ~LSTS (); /** Open the files * @return true on success (otherwise display diagnostics) */ bool openFiles (); /** Dump a state * @param m representation of the state * @param state number of the state */ void outputState (const class GlobalMarking& m, card_t state); # ifdef EXPR_COMPILE /** Dump a state * @param compilation the compilation for evaluating state properties * @param state number of the state */ void outputState (const class Compilation& compilation, card_t state); # endif // EXPR_COMPILE /** Dump an arc * @param source source state number * @param target target state number * @param transition the high-level transition * @param valuation values for the transition variables */ void outputArc (card_t source, card_t target, const class Transition& transition, const class Valuation& valuation); /** Dump the arcs * @param graph the graph whose arcs these are * @param source source state number * @param targets amount and numbers of target states * @param buf encoded transition names and instances (inflated) */ void outputArcs (const class Graph& graph, card_t source, const card_t* targets, word_t* buf); private: /** The net whose reachability graph is being processed */ const class Net& myNet; /** Base name for the files */ char* myFilebase; /** Number of state propositions */ const unsigned myNumProps; /** Number of generated states */ unsigned myNumStates; /** Number of generated transitions */ unsigned myNumTransitions; /** Actions generated so far */ Set myActionSet; /** Output streams for state proposition truth tables */ FILE** const myProps; /** Output stream for LSTS transitions (reachability graph arcs) */ FILE* myTransitions; /** Output stream for named LSTS actions (Petri net transition instances) */ FILE* myActions; /** Output stream for the LSTS index */ FILE* myIndex; }; #endif // LSTS_H_ maria-1.3.5/Graph/ParSet.C0000644000175000017500000001366107734544120015337 0ustar msmakelamsmakela// Parallelized, lossless reachability set storage -*- c++ -*- #ifdef __GNUC__ # pragma implementation "ParSet.h" #endif // __GNUC__ #if defined WIN32 || defined __WIN32 # undef __STRICT_ANSI__ # include "ParSet.h" # include # include typedef long ssize_t; # undef HAVE_POLL #else # include "ParSet.h" # include # include # if defined __CYGWIN__ || defined __APPLE__ # undef HAVE_POLL # include # elif defined __OpenBSD__ # define HAVE_POLL extern "C" { # include }; # else # define HAVE_POLL # include # endif #endif #ifndef USE_MMAP # include #endif // !USE_MMAP #include // exit(2) #ifndef __WIN32 # include #endif // !__WIN32 #include #ifndef MSG_NOSIGNAL # define MSG_NOSIGNAL 0 #endif // MSG_NOSIGNAL /** @file ParSet.C * Parallelized, lossless reachability set storage */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ ParSet::ParSet (int s) : StateSet (), myFD (s), myRecv (), mySend (), myRecvCount (0), mySendCount (0) { } ParSet::~ParSet () { close (myFD); } /** Send pending data to a socket * @param fd the socket to be written * @param sbuf the buffer to write * @param sbufu index of the first unsent byte in sbuf */ static void sendBuf (int fd, class BytePacker& sbuf, unsigned& sbufu) { assert (sbuf.getLength () > sbufu); const char* buf = reinterpret_cast(sbuf.getBuf ()); ssize_t i = send (fd, buf + sbufu, sbuf.getLength () - sbufu, MSG_NOSIGNAL); if (i < 0) { #if defined WIN32 || defined __WIN32 fprintf (stderr, "send: WinSock error %d\n", WSAGetLastError ()); #else perror ("send"); #endif exit (-1); } if ((sbufu += i) == sbuf.getLength ()) sbuf.clear (), sbufu = 0; } void ParSet::reject (const void* dstate, size_t dlen, const class StateSetReporter&, enum StateSet::Code reason, bool reduced) const { assert (!dstate == !dlen); mySend.append (reduced ? unsigned (reason) | 0x20 : unsigned (reason)); mySend.append (dlen); mySend.append (dstate, dlen); // flush the buffer to notify the server of the rejected state do sendBuf (myFD, mySend, mySendCount); while (mySendCount); } bool ParSet::do_add (const void* buf, size_t size) { mySearch.push (buf, size, 0); return true; } word_t* ParSet::pop (bool, size_t& size) { if (unsigned numStates = mySearch.size ()) { if (getNumArcs ()) mySend.append (addStates), mySend.append (numStates); else assert (numStates == 1), mySend.append (initialState); for (StateList::const_iterator i = mySearch.begin (); i != mySearch.end (); i++) mySend.append (i->size), mySend.append (i->data, i->size); } else mySend.append (addStates), mySend.append (0); mySearch.clear (); again: #ifndef HAVE_POLL fd_set readfds, writefds; FD_ZERO (&readfds); FD_ZERO (&writefds); FD_SET (myFD, &readfds); FD_SET (myFD, &writefds); switch (select (myFD + 1, &readfds, &writefds, 0, 0)) { default: #if defined WIN32 || defined __WIN32 if (WSAGetLastError () == WSAEINTR) goto again; fprintf (stderr, "select: WinSock error %d\n", WSAGetLastError ()); #else if (errno == EINTR) goto again; perror ("select"); #endif return 0; case 1: case 2: if (FD_ISSET (myFD, &writefds)) sendBuf (myFD, mySend, mySendCount); if (FD_ISSET (myFD, &readfds)) goto enqueue; // fall through: no data available for reading case 0: goto dequeue; } #else struct pollfd ufd; ufd.fd = myFD; ufd.events = POLLIN | POLLOUT; ufd.revents = 0; switch (poll (&ufd, 1, -1)) { default: if (errno == EINTR) goto again; perror ("poll"); return 0; case 1: if (ufd.revents & POLLOUT) sendBuf (myFD, mySend, mySendCount); if (ufd.revents & POLLIN) goto enqueue; // fall through: no data available for reading case 0: goto dequeue; } #endif dequeue: { class ByteUnpacker u (myRecv.getBuf () + myRecvCount); unsigned len; if (!u.extract (myRecv, len) || !u.ensureData (myRecv, len)) { assert (myRecv.getBuf () + myRecvCount <= u.buf); goto enqueue; } if ((myRecvCount = u.buf - myRecv.getBuf () + len) == myRecv.getLength ()) myRecvCount = 0, myRecv.clear (); size = len; return static_cast (memcpy (new word_t[1 + (len - 1) / sizeof (word_t)], u.buf, len)); } enqueue: assert (myRecvCount ? myRecvCount < myRecv.getLength () : !myRecv.getLength ()); myRecv.allocate (2048); ssize_t rlen = recv (myFD, reinterpret_cast (myRecv.getBuf () + myRecv.getLength ()), myRecv.getAllocated () - myRecv.getLength (), MSG_NOSIGNAL); if (rlen < 0) { #if defined WIN32 || defined __WIN32 int wsaerror = WSAGetLastError (); if (wsaerror != WSAECONNRESET) fprintf (stderr, "recv: WinSock error %d\n", wsaerror); #else if (errno != ECONNRESET) perror ("recv"); #endif return 0; } else if (!rlen) // the remote end tells us to terminate return 0; myRecv.setLength (myRecv.getLength () + rlen); goto dequeue; } maria-1.3.5/Graph/ParSet.h0000644000175000017500000000553507643247662015417 0ustar msmakelamsmakela// Parallelized, lossless reachability set storage -*- c++ -*- #ifndef PARSET_H_ # define PARSET_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "StateSet.h" # include "ByteBuffer.h" # include "file.h" /** @file ParSet.h * Transient, parallelized lossless reachability set storage */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Parallelized reachability set storage */ class ParSet : public StateSet { public: /** Constructor * @param s the communications socket */ ParSet (int s); private: /** Copy constructor */ ParSet (const class ParSet& old); /** Assignment operator */ class ParSet& operator= (const class ParSet& old); public: /** Destructor */ ~ParSet (); /** Display path to a rejected state * @param dstate the encoded rejected state (0=deadlock) * @param dlen length of dstate in bytes * @param reporter the state reporter * @param reason reason for rejecting the state * @param reduced flag: is this a reduced state space? */ void reject (const void* dstate, size_t dlen, const class StateSetReporter& reporter, enum Code reason, bool reduced) const; private: /** Add a state to the graph * @param state the encoded state * @param size length of the encoded state, in bytes * @return true if the state was enqueued to mySearch */ bool do_add (const void* state, size_t size); public: /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @param size (output) length of the encoded stream * @return the encoded state */ word_t* pop (bool tail, size_t& size); private: /** The socket file descriptor */ int myFD; /** The reception buffer */ mutable class BytePacker myRecv; /** The transmission buffer */ mutable class BytePacker mySend; /** Index to the first unread byte in myRecv */ mutable unsigned myRecvCount; /** Index to the first unsent byte in mySend */ mutable unsigned mySendCount; }; #endif // PARSET_H_ maria-1.3.5/Graph/Search.C0000644000175000017500000000207607643247662015356 0ustar msmakelamsmakela// State of reachability analysis -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Search.h" /** @file Search.C * List of search states */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ maria-1.3.5/Graph/Search.h0000644000175000017500000000502007643247662015413 0ustar msmakelamsmakela// State of reachability analysis -*- c++ -*- #ifndef SEARCH_H_ # define SEARCH_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include "typedefs.h" /** @file Search.h * List of search states */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** List of search states */ class SearchList { public: /** List of the state numbers in the search stack or queue */ typedef std::list List; /** Iterator to the state number list */ typedef List::iterator iterator; /** Constant iterator to the state number list */ typedef List::const_iterator const_iterator; /** Constructor */ SearchList () : myList () {} /** Copy constructor */ SearchList (const class SearchList& old) : myList (old.myList) {} /** Assignment operator */ class SearchList& operator= (const class SearchList& old) { myList = old.myList; return *this; } /** Destructor */ ~SearchList () {} /** @name Accessors to the state number list */ /*@{*/ bool empty () const { return myList.empty (); } size_t size () const { return myList.size (); } const_iterator begin () const { return myList.begin (); } const_iterator end () const { return myList.end (); } void clear () { myList.clear (); } /*@}*/ /** Insert an item to the list */ void push (card_t item) { myList.push_front (item); } /** Fetch an item * @param tail flag: retrieve from tail of list instead of head */ card_t pop (bool tail = false) { iterator i; if (tail) (i = myList.end ())--; else i = myList.begin (); card_t search = *i; myList.erase (i); return search; } private: /** The search list */ List myList; }; #endif // SEARCH_H_ maria-1.3.5/Graph/StateList.C0000644000175000017500000000210007643247662016051 0ustar msmakelamsmakela// List of unprocessed states -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "StateList.h" /** @file StateList.C * List of unprocessed states */ /* Copyright © 2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ maria-1.3.5/Graph/StateList.h0000644000175000017500000001111707643247662016126 0ustar msmakelamsmakela// List of unprocessed states -*- c++ -*- #ifndef STATELIST_H_ # define STATELIST_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include "BitBuffer.h" /** @file StateList.h * List of unprocessed states */ /* Copyright © 2001-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** List of unprocessed states */ class StateList { public: /** An unprocessed state stored in the list */ struct item { /** the encoded state */ word_t* data; /** length of the encoded state, in bytes */ size_t size; /** offset to the counterexample path file */ long offset; }; typedef std::list List; typedef List::const_iterator const_iterator; /** Constructor */ StateList () : myList () {} private: /** Copy constructor */ StateList (const class StateList& old); /** Assignment operator */ class StateList& operator= (const class StateList& old); public: /** Destructor */ ~StateList () { clear (); } /** Determine whether the list is empty */ bool empty () const { return myList.empty (); } /** Clear the list */ void clear () { for (List::iterator i = myList.begin (); i != myList.end (); i++) delete[] i->data; myList.clear (); } /** Clear the list, not deallocating the states */ void clear_allocated () { myList.clear (); } /** Insert an encoded state to the list * @param buf the encoded state * @param len length of the encoded state in bytes * @param offset offset to the counterexample path file */ void push (const void* buf, size_t len, long offset) { size_t last = (len - 1) / sizeof (word_t); struct item i = { buf ? new word_t[last + 1] : 0, len, offset }; if (buf) { i.data[last] = 0; memcpy (i.data, buf, len); } myList.push_front (i); } /** Insert an encoded state to the list * @param buf the encoded state (new copy) * @param len length of the encoded state in bytes * @param offset offset to the counterexample path file */ void push_allocated (word_t* buf, size_t len, long offset) { struct item i = { buf, len, offset }; myList.push_front (i); } /** Push all states of a list to the list * @param other the queue to be pushed to this */ void push (class StateList& other) { for (List::iterator i = other.myList.begin (); i != other.myList.end (); i++) myList.push_back (*i); other.myList.clear (); } /** Fetch an encoded state from the list * @param tail flag: retrieve from tail of list instead of head * @param offset (output) offset to the counterexample path file * @param len (output) length of the encoded stream (optional) * @return the encoded state */ word_t* pop (bool tail, long& offset, size_t* len = 0) { List::iterator i; if (tail) (i = myList.end ())--; else i = myList.begin (); offset = i->offset; word_t* data = i->data; if (len) *len = i->size; else BitPacker::inflate (data[(i->size - 1) / sizeof (word_t)], (-i->size) % sizeof (word_t)); myList.erase (i); return data; } /** Dequeue an item from the list * @param tail flag: retrieve from tail of list instead of head * @param i (optional output) the dequeued item */ void pop (bool tail, struct item* i) { List::iterator l; if (tail) (l = myList.end ())--; else l = myList.begin (); if (i) *i = *l; myList.erase (l); } /** @name accessors to the list */ /*@{*/ const_iterator begin () const { return myList.begin (); } const_iterator end () const { return myList.end (); } size_t size () const { return myList.size (); } /*@}*/ private: /** The list of unprocessed states */ List myList; }; #endif // STATELIST_H_ maria-1.3.5/Graph/StateReporter.C0000644000175000017500000004213607762612243016746 0ustar msmakelamsmakela// Reporting successor states -*- c++ -*- /** @file StateReporter.C * Interface for reporting successor states */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifdef __GNUC__ # pragma implementation "StateReporter.h" #endif // __GNUC__ #include "StateSetReporter.h" #include "States.h" #include "Net.h" #include "Transition.h" #include "Valuation.h" #include "GlobalMarking.h" #include "FullSet.h" #include "SyncStates.h" #ifdef EXPR_COMPILE # include "Compilation.h" # include "Printer.h" #endif // EXPR_COMPILE /** Flag: has the analysis been interrupted? */ volatile bool interrupted = false; StateReporter::StateReporter ( #ifdef EXPR_COMPILE const class Compilation* compilation, #endif // EXPR_COMPILE const class Net& net_, const class Printer& printer_, unsigned maxerrors, bool compress, bool local, bool flattened) : #ifdef EXPR_COMPILE myCompilation (compilation), #endif // EXPR_COMPILE net (net_), printer (printer_), myMaxErrors (maxerrors), myNumErrors (0), myNumLocal (0), myEnabled (net.getNumEnabled () ? new char[net.getNumEnabled ()] : 0), mySync (0), myFatal (false), mySrcDeadlock (true), myPriority (0), myStateBuf (), mySrc (0), mySrcSize (0), myFlattened (flattened), myLocal (local ? new class FullSet () : 0), mySuppressed (compress ? new class States () : 0), mySuccessors (None), myMinSize (size_t (-1L)), myMaxSize (0) { if (net.getNumEnabled ()) memset (myEnabled, 0, net.getNumEnabled ()); if (myLocal && !myLocal->init (true)) { delete myLocal; *const_cast(&myLocal) = 0; } } StateReporter::StateReporter (const class StateReporter& old) : #ifdef EXPR_COMPILE myCompilation (old.myCompilation), #endif // EXPR_COMPILE net (old.net), printer (old.printer), myMaxErrors (old.myMaxErrors), myNumErrors (0), myNumLocal (0), myEnabled (net.getNumEnabled () ? new char[net.getNumEnabled ()] : 0), mySync (0), myFatal (false), mySrcDeadlock (true), myPriority (0), myStateBuf (), mySrc (0), mySrcSize (0), myFlattened (old.myFlattened), myLocal (old.myLocal ? new class FullSet () : 0), mySuppressed (old.mySuppressed ? new class States () : 0), mySuccessors (None), myMinSize (size_t (-1L)), myMaxSize (0) { if (net.getNumEnabled ()) memset (myEnabled, 0, net.getNumEnabled ()); if (myLocal && !myLocal->init (true)) { delete myLocal; *const_cast(&myLocal) = 0; } } StateReporter::~StateReporter () { delete[] myEnabled; delete[] mySrc; delete mySuppressed; delete myLocal; } void StateReporter::enabled (const class Transition& transition) { assert (!myPriority || transition.getPriority () == myPriority); mySrcDeadlock = false; myPriority = transition.getPriority (); } #ifdef EXPR_COMPILE /** Report an encoded state * @param buf the encoded state * @param size length of the encoded state, in bytes * @param err errNone if the state is not rejected * @param tr the number of the transition that fired * @param ftr the number of the transition in the flattened net * @param hide flag: is the transition hidden? * @param ctx the call-back context */ static void addState (const void* buf, size_t size, enum Error err, unsigned tr, unsigned ftr, int hide, void* ctx) { class StateReporter& reporter = *static_cast(ctx); if (err && err != errComp) reporter.flagFatal (); reporter.addState (buf, size, err != errNone, hide, reporter.isFlattened () ? ftr : tr); } /** Report a potential synchronisation state * @param tr the number of the transition that fired * @param ctx the call-back context */ static void syncState (unsigned tr, void* ctx) { class StateReporter& reporter = *static_cast(ctx); reporter.reportSync (reporter.net.getTransition (tr)); } void StateReporter::analyze (const class Transition& transition) { if (unsigned errors = myCompilation->eventAnalyze (transition.getRootIndex (), this, myEnabled)) { enabled (transition); reject (); printer.printQuoted (transition.getName ()); printer.delimiter (':'); printer.print (errors); printer.printRaw (errors == 1 ? " error" : " errors"); printer.finish (); } } void StateReporter::addState (const void* buf, size_t size, bool rejected, bool hidden, unsigned tr) { const class Transition& t = net.getTransition (tr); enabled (t); report (buf, size, rejected, hidden); } #endif // EXPR_COMPILE void StateReporter::analyze (enum SearchKind kind) { #ifdef EXPR_COMPILE if (myCompilation) { myCompilation->linkAddState (&::addState); myCompilation->linkReporter (&::syncState, isGraph (), myFlattened); myCompilation->getFatal () = &myFatal; myCompilation->getFlattened () = myFlattened; } #endif // EXPR_COMPILE if (myFlattened) analyzeFlattened (kind); else analyzeModular (kind); } void StateReporter::analyzeFlattened (enum SearchKind kind) { assert (myFlattened); const unsigned numTr = net.getNumAllTransitions (); #ifdef EXPR_COMPILE if (myCompilation) { while (!interrupted && !myFatal) { if (!popCompiled (kind == Breadth)) break; mySrcDeadlock = true, myPriority = 0; for (unsigned i = 0; !interrupted && !myFatal && i < numTr; i++) { const class Transition& t = net.getTransition (i); if (!myPriority || t.getPriority () == myPriority) analyze (t); } if (mySrcDeadlock && !interrupted && !myFatal) { switch (myCompilation->stateDeadlock (net.getIndex ())) { case errNone: break; default: myFatal = true; // fall through case errComp: reportError (true); } } if (suppress ()) continue; addEvents (); if (kind >= Single) break; } return; } #endif // EXPR_COMPILE while (!interrupted && !myFatal) { class GlobalMarking* m = pop (kind == Breadth); if (!m) break; mySrcDeadlock = true, myPriority = 0; for (unsigned i = 0; !interrupted && !myFatal && i < numTr; i++) { const class Transition& t = net.getTransition (i); if (!t.getNumParents () && (!myPriority || t.getPriority () == myPriority)) t.analyze (*m, *this); } if (mySrcDeadlock && !interrupted && !myFatal) { switch (net.isDeadlock (*m, true)) { case Net::OK: break; case Net::Fatal: myFatal = true; // fall through case Net::Error: reportError (true); } } delete m; if (suppress ()) continue; addEvents (); if (kind >= Single) break; } } void StateReporter::analyzeModular (enum SearchKind kind) { assert (!myFlattened); /** state spaces of the child nets */ class FullSet* childset = initModules (); /** the synchronising state space */ class SyncStates* sync = childset ? new class SyncStates (net) : 0; unsigned i; const unsigned numTr = net.getNumTransitions (); while (!interrupted && !myFatal) { class GlobalMarking* m = #ifdef EXPR_COMPILE myCompilation ? 0 : #endif // EXPR_COMPILE pop (kind == Breadth); if ( #ifdef EXPR_COMPILE myCompilation ? !popCompiled (kind == Breadth) : #endif // EXPR_COMPILE !m) break; mySrcDeadlock = true, myPriority = 0; for (i = 0; !interrupted && !myFatal && i < numTr; i++) { const class Transition& t = net.getTransition (i); if ((!myPriority || t.getPriority () == myPriority) && !t.getNumChildren ()) { #ifdef EXPR_COMPILE if (myCompilation) analyze (t); else #endif // EXPR_COMPILE t.analyze (*m, *this); } // synchronisation transitions (which have children) are analysed // by SyncStates::sync (), called via analyzeModules () below } if (childset) { #ifdef EXPR_COMPILE if (myCompilation) analyzeModules (*sync, childset); else #endif // EXPR_COMPILE analyzeModules (*m, *sync, childset); } if (mySrcDeadlock && !interrupted && !myFatal) { #ifdef EXPR_COMPILE if (myCompilation) { switch (myCompilation->stateDeadlock (net.getIndex ())) { case errNone: break; default: myFatal = true; // fall through case errComp: reportError (true); } } else #endif // EXPR_COMPILE switch (net.isDeadlock (*m, false)) { case Net::OK: break; case Net::Fatal: myFatal = true; // fall through case Net::Error: reportError (true); } } delete m; if (suppress ()) continue; addEvents (); if (kind >= Single) break; } for (i = net.getNumChildren(); i--; ) myNumLocal += childset[i].getNumStates (); delete[] childset; delete sync; } class FullSet* StateReporter::initModules () const { unsigned i = myFlattened ? 0 : net.getNumChildren (); class FullSet* childset = i ? new class FullSet[i] : 0; while (i--) { if (!childset[i].init (false)) { assert (false); delete[] childset; return 0; } } return childset; } void StateReporter::analyzeModules (const class GlobalMarking& m, class SyncStates& sync, class FullSet* childset) { assert (net.getNumChildren () > 0); unsigned i; // analyze child state spaces for (i = net.getNumChildren (); !interrupted && !myFatal && i--; ) { const class Net& child = net.getChild (i); childset[i].clear (); m.encode (myStateBuf, child); #ifdef SYNC_CACHE if (sync.lookup (i, myStateBuf.getBuf (), myStateBuf.getNumWords ())) continue; // the modular state has already been analyzed #endif // SYNC_CACHE myStateBuf.deflate (); if (!childset[i].add (myStateBuf.getBuf (), myStateBuf.getNumBytes ())) assert (false); // this should be a new state // to do: support safety-LTL property checking for the modules class StateSetReporter reporter ( #ifdef EXPR_COMPILE myCompilation, #endif child, printer, 0, false, false, false, 0, 0, false, childset[i], 0); reporter.mySync = &sync; reporter.analyzeModular (Breadth); // to do: report the error graphically, show step from mySrc to myStateBuf if (reporter.myFatal) myFatal = true; if (reporter.getNumErrors ()) reportError (false); myNumLocal += reporter.myNumLocal; } // find out enabled synchronisation transitions and synchronise for (i = net.getNumTransitions (); i--; ) { const class Transition& t = net.getTransition (i); if ((!myPriority || t.getPriority () == myPriority) && t.getNumChildren ()) sync.sync (m, t, *this); } #ifndef SYNC_CACHE sync.cleanup (); #endif // !SYNC_CACHE } #ifdef EXPR_COMPILE void StateReporter::analyzeModules (class SyncStates& sync, class FullSet* childset) { assert (net.getNumChildren () > 0); assert (!!myCompilation); unsigned i = net.getNumChildren (); word_t** srcs = new word_t*[i]; // analyze child state spaces for (; !interrupted && !myFatal && i--; ) { const class Net& child = net.getChild (i); childset[i].clear (); unsigned bytes; const void* buf = myCompilation->stateProject (child.getIndex (), 0, 0, bytes); word_t* data = const_cast(static_cast(buf)); unsigned numWords = bytes ? (bytes - 1) / sizeof (word_t) + 1 : 0; /* back up the source state */ BitPacker::inflate (data[numWords - 1], (-bytes) % sizeof (word_t)); srcs[i] = bytes ? new word_t[numWords] : 0; memcpy (srcs[i], data, numWords * sizeof (word_t)); #ifdef SYNC_CACHE if (sync.lookup (i, data, numWords)) continue; // the modular state has already been analyzed #endif // SYNC_CACHE BitPacker::deflate (data[numWords - 1], (-bytes) % sizeof (word_t)); if (!childset[i].add (buf, bytes)) assert (false); // this should be a new state // to do: support safety-LTL property checking for the modules class StateSetReporter reporter (myCompilation, child, printer, 0, false, false, false, 0, 0, false, childset[i], 0); reporter.mySync = &sync; reporter.analyzeModular (Breadth); /* restore the source state */ myCompilation->stateDecode (child.getIndex (), srcs[i], 0); // to do: report the error graphically, show step from mySrc to myStateBuf if (reporter.myFatal) myFatal = true; if (reporter.getNumErrors ()) reportError (false); myNumLocal += reporter.myNumLocal; } // find out enabled synchronisation transitions and synchronise for (i = net.getNumTransitions (); i--; ) { const class Transition& t = net.getTransition (i); if ((myPriority && t.getPriority () != myPriority) || !t.getNumChildren ()) continue; sync.sync (t, *this, srcs); } for (i = net.getNumChildren (); i--; ) delete[] srcs[i]; delete[] srcs; # ifndef SYNC_CACHE sync.cleanup (); # endif // !SYNC_CACHE } void StateReporter::sync (const class Transition& transition) { assert (transition.getNumChildren () > 0); unsigned bytes; const void* buf = myCompilation->stateProject (transition.getNet ()->getIndex (), 0, 0, bytes); unsigned numWords = (bytes - 1) / sizeof (word_t) + 1; word_t* s = numWords ? new word_t[numWords] : 0; memcpy (s, buf, bytes); BitPacker::inflate (s[numWords - 1], (-bytes) % sizeof (word_t)); setSyncSource (s, bytes); analyze (transition); } #endif // EXPR_COMPILE bool StateReporter::suppress () { if (myLocal && myLocal->getNumStates ()) return true; if (mySuppressed) { switch (mySuccessors) { case One: return true; case Many: if (const size_t num = mySuppressed->size ()) { const struct States::state& s = (*mySuppressed)[num - 1]; do_addState (s.buf, s.size); mySuccessors = None; } // fall through case None: mySuppressed->clear (); } } return false; } bool StateReporter::report (const class Transition& transition, const class Valuation& valuation, const class GlobalMarking& marking) { card_t errorplace; assert (valuation.isOK ()); enabled (transition); if (myEnabled) transition.logEnabled (valuation, myEnabled); if (marking.encode (myStateBuf, *net.getInitMarking (), &errorplace)) { enum Net::Status status = net.isReject (marking, myFlattened); switch (status) { case Net::OK: break; case Net::Fatal: flagFatal (); // fall through case Net::Error: break; } return report (transition, valuation, marking, status != Net::OK); } assert (!!net.getPlace (errorplace)); reject (transition, valuation, marking, 0, net.getPlace (errorplace)); return true; } void StateReporter::reportSync (const class Transition& transition) { assert (mySync && transition.getNumParents ()); assert (!myFlattened); enabled (transition); mySync->add (transition, mySrc, (mySrcSize + (sizeof (word_t) - 1)) / sizeof (word_t)); } bool StateReporter::addState (const void* state, size_t size, bool hidden) { if (size > myMaxSize) myMaxSize = size; if (size < myMinSize) myMinSize = size; if (hidden && myLocal) return myLocal->add (state, size), false; // local state suppressed if (!mySuccessors && mySuppressed && mySuppressed->size () && mySuppressed->add (state, size)) return mySuccessors = One, false; // path compression applied mySuccessors = Many; return do_addState (state, size); } word_t* StateReporter::popState (bool tail) { delete[] mySrc; if (myLocal) { if ((mySrc = myLocal->pop (tail, mySrcSize))) return mySrc; if (myLocal->getNumStates ()) addEvents (); myLocal->clear (); } if (mySuppressed) { if (const size_t num = mySuppressed->size ()) { const struct States::state& s = (*mySuppressed)[num - 1]; switch (mySuccessors) { case One: mySrc = new word_t[1 + (s.size - 1) / sizeof (word_t)]; memcpy (mySrc, s.buf, mySrcSize = s.size); mySuccessors = None; return mySrc; case Many: do_addState (s.buf, s.size); mySuccessors = None; // fall through case None: mySuppressed->clear (); } } } if ((mySrc = do_popState (tail, mySrcSize)) && mySuppressed) if (!mySuppressed->add (mySrc, mySrcSize)) assert (false); return mySrc; } void StateReporter::addEvents () { } void StateReporter::reject (const class Transition& transition, const class Valuation& valuation, const class GlobalMarking& marking, const char* reason, const class Place* place) { if (valuation.getError () == errFatal) flagFatal (); reject (); transition.report (valuation, marking, reason, place, printer); enabled (transition); } maria-1.3.5/Graph/StateReporter.h0000644000175000017500000002702507643247662017022 0ustar msmakelamsmakela// Reporting successor states -*- c++ -*- #ifndef STATEREPORTER_H_ # define STATEREPORTER_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "BitBuffer.h" /** @file StateReporter.h * Interface for reporting successor states */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Reporting successor states */ class StateReporter { public: /** Search kinds */ enum SearchKind { Breadth, ///< exhaustive breadth-first search Depth, ///< exhaustive depth-first search Single ///< process a single state }; /** Constructor * @param compilation the compiled model (optional) * @param net_ the net that is being analysed * @param printer_ printer object for diagnostic output * @param maxerrors maximum number of allowed errors (0=infinity) * @param compress flag: collapse deterministic sequences? * @param local flag: suppress transient (invisible) states? * @param flattened flag: consider the flattened net? */ StateReporter ( # ifdef EXPR_COMPILE const class Compilation* compilation, # endif // EXPR_COMPILE const class Net& net_, const class Printer& printer_, unsigned maxerrors, bool compress, bool local, bool flattened); /** Copy constructor */ StateReporter (const class StateReporter& old); private: /** Assignment operator */ class StateReporter& operator= (const class StateReportert& other); public: /** Destructor */ virtual ~StateReporter (); /** Get the number of errors that have been reported */ unsigned getNumErrors () const { return myNumErrors; } /** Get the number of local states generated in modular analysis */ unsigned getNumLocal () const { return myNumLocal; } /** Get the minimum length of state vectors */ size_t getMinSize () const { return myMinSize; } /** Get the maximum length of state vectors */ size_t getMaxSize () const { return myMaxSize; } /** Get the transition enabledness sets */ const char* getEnabled () const { return myEnabled; } /** Determine if the flattened net is being considered */ bool isFlattened () const { return myFlattened; } /** Determine whether this is a reduced state space */ bool isReduced () const { return !!myLocal; } /** Note an enabled transition * @param transition the transition */ void enabled (const class Transition& transition); # ifdef EXPR_COMPILE protected: /** Analyze the successors of a transition * @param transition the transition */ void analyze (const class Transition& transition); public: /** Report a successor state * @param buf the encoded state * @param size length of the encoded state, in bytes * @param rejected flag: is the state rejected? * @param hidden flag: is the transition to the state hidden? * @param tr the index of the transition that fired */ void addState (const void* buf, size_t size, bool rejected, bool hidden, unsigned tr); # endif // EXPR_COMPILE /** Search the state space * @param kind Type of search */ void analyze (enum SearchKind kind); private: /** Search the state space of the flattened net * @param kind Type of search */ void analyzeFlattened (enum SearchKind kind); /** Search the state space in a modular way * @param kind Type of search */ virtual void analyzeModular (enum SearchKind kind); protected: /** Initialize the state spaces of the modules * @return the state spaces of the modules, or 0 if not modular */ class FullSet* initModules () const; /** Search the state spaces of the modules * @param m the source marking * @param sync the synchronisation states * @param childset the state spaces of the modules */ void analyzeModules (const class GlobalMarking& m, class SyncStates& sync, class FullSet* childset); # ifdef EXPR_COMPILE /** Search the state spaces of the modules * @param sync the synchronisation states * @param childset the state spaces of the modules */ void analyzeModules (class SyncStates& sync, class FullSet* childset); public: /** Generate the successors of a synchronisation transition * @param transition the transition */ void sync (const class Transition& transition); protected: # endif // EXPR_COMPILE /** Determine if a state can be suppressed */ bool suppress (); public: /** Report a successor state * @param transition the transition fired * @param valuation the binding of the transition * @param marking the resulting marking * @return true if analysis should proceed; false on fatal error */ bool report (const class Transition& transition, const class Valuation& valuation, const class GlobalMarking& marking); /** Report a synchronisation state * @param transition the synchronisation transition */ void reportSync (const class Transition& transition); /** Set the synchronisation source state (called by SyncStates) * @param src the encoded source state * @param size length of the encoded state in bytes */ void setSyncSource (word_t* src, size_t size) { delete[] mySrc; mySrc = src; mySrcSize = size; } protected: /** Report an error * @return true when the maximum amount of errors has been reached */ bool error () { return ++myNumErrors == myMaxErrors; } /** Add an encoded state to the state space (called by report ()) * @param state the encoded state * @param size length of the encoded state in bytes * @param hidden flag: is the transition to the state hidden? * @return true if the state was new */ bool addState (const void* state, size_t size, bool hidden); /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @return the encoded state (mySrc), or NULL if none available */ word_t* popState (bool tail); /** Inflate the source state buffer */ void inflate () { BitPacker::inflate (mySrc[(mySrcSize - 1) / sizeof (word_t)], (-mySrcSize) % sizeof (word_t)); } /** Deflate the source state buffer */ void deflate () { BitPacker::deflate (mySrc[(mySrcSize - 1) / sizeof (word_t)], (-mySrcSize) % sizeof (word_t)); } private: /** Add an encoded state to the state space * @param state the encoded state * @param size length of the encoded state in bytes * @return true if the state was new */ virtual bool do_addState (const void* state, size_t size) = 0; /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @param size (output) length of the encoded stream * @return the encoded state, or NULL if none available */ virtual word_t* do_popState (bool tail, size_t& size) = 0; /** Dequeue an unprocessed state * @param breadth true=dequeue (FIFO, queue), false=pop (LIFO, stack) * @return an unprocessed state, or NULL if all processed */ virtual class GlobalMarking* pop (bool breadth) = 0; # ifdef EXPR_COMPILE /** Dequeue an unprocessed state * @param breadth true=dequeue (FIFO, queue), false=pop (LIFO, stack) * @return true if a state was found, or false if all processed */ virtual bool popCompiled (bool breadth) = 0; /** Determine whether arcs should be generated */ virtual bool isGraph () const { return false; } # endif // EXPR_COMPILE /** Add all events from the current source state to the graph */ virtual void addEvents (); /** Report a successor state * @param transition the transition fired * @param valuation the binding of the transition * @param marking the resulting marking * @param rejected flag: is the state rejected? * @return true if the state was new */ virtual bool report (const class Transition& transition, const class Valuation& valuation, const class GlobalMarking& marking, bool rejected) = 0; /** Report a deadlock or an error in the current state * @param deadlock flag: is this a deadlock? */ virtual void reportError (bool deadlock) = 0; public: # ifdef EXPR_COMPILE /** Report a successor state * @param state the resulting encoded deflated state (mandatory) * @param size length of the encoded state, in bytes * @param rejected flag: is the state rejected? * @param hidden flag: is the transition to the state hidden? * @return true if the state was new */ virtual bool report (const void* state, size_t size, bool rejected, bool hidden) = 0; # endif // EXPR_COMPILE /** Report an inconsistent successor state * @param transition the transition fired * @param valuation the binding of the transition * @param marking the resulting marking * @param reason reason for failure (optional) * @param place the place whose marking could not be encoded (optional) */ void reject (const class Transition& transition, const class Valuation& valuation, const class GlobalMarking& marking, const char* reason, const class Place* place); /** Determine whether a fatal condition has occurred */ bool isFatal () const { return myFatal; } /** Flag a fatal condition */ void flagFatal () { myFatal = true; } private: /** Report an inconsistent successor state */ virtual void reject () = 0; public: # ifdef EXPR_COMPILE /** The compiled model */ const class Compilation* const myCompilation; # endif // EXPR_COMPILE /** The net being analyzed */ const class Net& net; /** Printer object for diagnostics */ const class Printer& printer; private: /** Maximum allowed number of errors (0=infinite) */ const unsigned myMaxErrors; /** Number of errors that have occurred */ unsigned myNumErrors; /** Number of local states generated in modular analysis */ unsigned myNumLocal; /** Log of enabledness set occurrences (optional) */ char* const myEnabled; protected: /** Synchronisation states for modular analysis (optional) */ class SyncStates* mySync; /** Flag: has a fatal condition occurred? */ bool myFatal; /** Flag: is the source state a deadlock? */ bool mySrcDeadlock; /** Priority level of the last fired transition */ unsigned myPriority; /** Encoder for states */ class BitPacker myStateBuf; /** The encoded state that is being analyzed */ word_t* mySrc; /** Length of mySrc, in bytes */ size_t mySrcSize; private: /** Flag: apply search on flattened state space? */ const bool myFlattened; /** Set of local (transient, invisible) states */ class FullSet* const myLocal; /** Suppressed states (when applying path compression) */ class States* const mySuppressed; /** Flag: how many successors does the state have (in path compression) */ enum { None = 0, One, Many } mySuccessors; /** Minimum length of encoded state vectors */ size_t myMinSize; /** Maximum length of encoded state vectors */ size_t myMaxSize; }; #endif // STATEREPORTER_H_ maria-1.3.5/Graph/StateSet.C0000644000175000017500000001632307724604474015703 0ustar msmakelamsmakela// Storage of encoded states -*- c++ -*- /** @file StateSet.C * Set of reached states, represented with bit vectors */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifdef __GNUC__ # pragma implementation "StateSet.h" #endif // __GNUC__ #include "FullSet.h" #include "Printer.h" #include "Net.h" #include "Dotty.h" #include "ByteBuffer.h" #include "StateSetReporter.h" /** Flag: has the analysis been interrupted? */ extern volatile bool interrupted; bool StateSet::openFile () { if (!(myPathFile = tmpfile ())) perror ("tmpfile"); return !!myPathFile; } /** Display the reason for rejecting a state * @param reason the reason for rejecting the state * @param printer the output stream */ static void printReason (enum StateSet::Code reason, const class Printer& printer) { switch (reason) { case StateSet::initialState: case StateSet::addStates: assert (false); break; case StateSet::deadlockState: printer.printRaw ("deadlock"); break; case StateSet::deadlockFatal: printer.printRaw ("fatal deadlock"); break; case StateSet::rejectState: printer.printRaw ("rejected state"); break; case StateSet::rejectFatal: printer.printRaw ("fatally rejected state"); break; case StateSet::propertyError: printer.printRaw ("property evaluation error"); break; case StateSet::inconsistent: printer.printRaw ("inconsistent successor"); break; } printer.finish (); } /** Read the file offsets to the counterexample trace * @param numOffset (output) the length of the offset sequence * @param off the offset to the path file * @param end the end offset to the path file * @param f the path file */ static unsigned* readOffsets (unsigned& numOffsets, long off, long end, FILE* f) { #ifndef NDEBUG assert (off < end); fseek (f, 0, SEEK_END); assert (end <= ftell (f)); #endif // NDEBUG numOffsets = 1; unsigned* offsets = new unsigned[1]; if ((*offsets = off)) { unsigned char rbuf[8]; class ByteUnpacker u (rbuf); do { fseek (f, offsets[numOffsets - 1], SEEK_SET); if (!(numOffsets & (numOffsets + 1))) { unsigned* o = new unsigned[(numOffsets + 1) << 1]; memcpy (o, offsets, numOffsets * sizeof *offsets); delete[] offsets; offsets = o; } fread (rbuf, sizeof rbuf, 1, f); offsets[numOffsets] = u.extract (); u.buf = rbuf; assert (offsets[numOffsets] < offsets[numOffsets - 1]); } while (offsets[numOffsets++]); } return offsets; } void StateSet::reject (const void* dstate, size_t dlen, const class StateSetReporter& reporter, enum Code reason, bool reduced) const { assert (!!dstate); if (!myPathFile) return; reporter.displayPrologue (); ::printReason (reason, reporter.printer); if (reduced) { class FullSet states; if (!states.init (false)) { assert (false); return; } unsigned numOffsets; unsigned* offsets = ::readOffsets (numOffsets, myOffset, myPathFileLength, myPathFile); const unsigned* o = offsets + numOffsets; size_t size = 0; word_t* state = 0; if (!reporter.net.getParent ()) reporter.displayMarking (*reporter.net.getInitMarking ()); else { // the first state on the path is the "initial" one: display it assert (numOffsets > 0); assert (!o[-1]); state = getState (*--o, &size); BitPacker::inflate (state[(size - 1) / sizeof (word_t)], (-size) % sizeof (word_t)); reporter.displayState (state); } for (const unsigned* o = offsets + numOffsets; o-- > offsets && !interrupted; ) { delete[] state; state = getState (*o, &size); if (states.getNumStates ()) { BitPacker::inflate (state[(size - 1) / sizeof (word_t)], (-size) % sizeof (word_t)); class StateSetReporter recoverer (reporter, true, states, state, 1 + (size - 1) / sizeof (word_t)); recoverer.analyze (StateReporter::Breadth); assert (recoverer.isFatal ()); BitPacker::deflate (state[(size - 1) / sizeof (word_t)], (-size) % sizeof (word_t)); states.clear (); } if (!states.add (state, size)) assert (false); } if (!interrupted && (dlen != size || memcmp (state, dstate, size))) { word_t* d1 = new word_t[(dlen + (sizeof (word_t) - 1)) / sizeof (word_t)]; memcpy (d1, dstate, dlen); BitPacker::inflate (d1[(dlen - 1) / sizeof (word_t)], (-dlen) % sizeof (word_t)); class StateSetReporter recoverer (reporter, true, states, d1, 1 + (dlen - 1) / sizeof (word_t)); recoverer.analyze (StateReporter::Breadth); assert (recoverer.isFatal ()); delete[] d1; } delete[] state; delete[] offsets; fseek (myPathFile, myPathFileLength, SEEK_SET); } else displayPath (dstate, dlen, reporter); reporter.displayEpilogue (); } void StateSet::displayPath (const void* dstate, size_t dlen, const class StateSetReporter& reporter) const { assert (!!dstate); if (!myPathFile) return; unsigned numOffsets; unsigned* offsets = ::readOffsets (numOffsets, myOffset, myPathFileLength, myPathFile); const unsigned* o = offsets + numOffsets; word_t* s1 = 0; size_t size = 0; if (!reporter.net.getParent ()) reporter.displayMarking (*reporter.net.getInitMarking ()); else { // the first state on the path is the "initial" one: display it assert (numOffsets > 0); assert (!o[-1]); s1 = getState (*--o, &size); BitPacker::inflate (s1[(size - 1) / sizeof (word_t)], (-size) % sizeof (word_t)); reporter.displayState (s1); } while (o-- > offsets && !interrupted) { word_t* state = getState (*o, &size); BitPacker::inflate (state[(size - 1) / sizeof (word_t)], (-size) % sizeof (word_t)); if (s1) { reporter.displayPath (s1, state, 1 + (size - 1) / sizeof (word_t)); delete[] s1; } s1 = state; } if (!interrupted) { word_t* d1 = new word_t[(dlen + (sizeof (word_t) - 1)) / sizeof (word_t)]; memcpy (d1, dstate, dlen); const unsigned dwords = 1 + (dlen - 1) / sizeof (word_t); BitPacker::inflate (d1[dwords - 1], (-dlen) % sizeof (word_t)); if (dlen != size || memcmp (s1, d1, dwords * sizeof (word_t))) reporter.displayPath (s1, d1, dwords); delete[] d1; } delete[] s1; delete[] offsets; fseek (myPathFile, myPathFileLength, SEEK_SET); } word_t* StateSet::getState (long, size_t*) const { assert (false); return 0; } maria-1.3.5/Graph/StateSet.h0000644000175000017500000001207307643247662015750 0ustar msmakelamsmakela// Storage of encoded states -*- c++ -*- #ifndef STATESET_H_ # define STATESET_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "StateList.h" # include /** @file StateSet.h * Set of reached states, represented with bit vectors */ /* Copyright © 2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Set of reached states */ class StateSet { public: /** codes reported from worker to server */ enum Code { initialState, //< report the initial state addStates, //< add successor states deadlockState, //< notify of a rejected deadlock state deadlockFatal, //< notify of a fatally rejected deadlock rejectState, //< notify of a rejected state rejectFatal, //< notify of a fatally rejected state propertyError, //< notify of property evaluation error inconsistent //< notify of an inconsistent successor state }; /** Constructor */ StateSet () : myNumStates (0), myNumArcs (0), mySearch (), myPathFile (0), myPathFileLength (0), myOffset (0) {} private: /** Copy constructor */ StateSet (const class StateSet& old); /** Assignment operator */ class StateSet& operator= (const class StateSet& old); public: /** Destructor */ virtual ~StateSet () { if (myPathFile) fclose (myPathFile); } /** Get the number of states */ unsigned getNumStates () const { return myNumStates; } /** Get the number of arcs (number of add () invocations) */ unsigned getNumArcs () const { return myNumArcs - 1; } /** Get the number of unprocessed states */ unsigned getNumPending () const { return mySearch.size (); } /** Open the counterexample path file * @return true on success; false on failure */ bool openFile (); /** Display path to a rejected state * @param dstate the encoded rejected state * @param dlen length of dstate in bytes * @param reporter the state reporter * @param reason reason for rejecting the state * @param reduced flag: is this a reduced state space? */ virtual void reject (const void* dstate, size_t dlen, const class StateSetReporter& reporter, enum Code reason, bool reduced) const; /** Display subpath to a state in a recovered state space * @param dstate the encoded rejected state (0=deadlock) * @param dlen length of dstate in bytes * @param reporter the state reporter */ void displayPath (const void* dstate, size_t dlen, const class StateSetReporter& reporter) const; /** Add a state to the set * @param state the encoded state * @param size length of the encoded state, in bytes * @return true if the state was enqueued to mySearch */ bool add (const void* state, size_t size) { myNumArcs++; return do_add (state, size); } private: /** Add a state to the set * @param state the encoded state * @param size length of the encoded state, in bytes * @return true if the state was enqueued to mySearch */ virtual bool do_add (const void* state, size_t size) = 0; protected: /** Increment the state count */ void newState () { myNumStates++; } /** Get a deflated state from myPathFile * @param pos file offset to the state * @param size (output) length of the encoded state */ virtual word_t* getState (long pos, size_t* size) const; public: /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @param size (output) length of the encoded stream * @return the encoded state */ virtual word_t* pop (bool tail, size_t& size) = 0; /** Set the offset to the counterexample path file */ void setOffset (long offset) { myOffset = offset; } /** Read the offset to the counterexample path file */ long getOffset () const { return myOffset; } private: /** Number of generated states */ unsigned myNumStates; /** Number of generated arcs (invocations to add ()) */ unsigned myNumArcs; protected: /** The search list of states */ class StateList mySearch; /** Counterexample path file */ FILE* myPathFile; /** Used length of counterexample path file */ long myPathFileLength; /** Current state offset in the counterexample path file */ long myOffset; # if defined __sgi && !defined __GNUC__ public: # endif // MIPS CC bug work-around }; #endif // STATESET_H_ maria-1.3.5/Graph/StateSetReporter.C0000644000175000017500000002665607643247662017442 0ustar msmakelamsmakela// Reporting successor states in safety property analysis -*- c++ -*- /** @file StateSetReporter.C * Interface for reporting successor states in safety property analysis */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "StateSetReporter.h" #include "FullSet.h" #include "SyncStates.h" #include "Net.h" #include "Transition.h" #include "Valuation.h" #include "GlobalMarking.h" #include "Property.h" #include "Printer.h" #include "Dotty.h" StateSetReporter::StateSetReporter ( #ifdef EXPR_COMPILE const class Compilation* compilation, #endif // EXPR_COMPILE const class Net& net_, const class Printer& printer_, unsigned maxerrors, bool compress, bool local, bool flattened, unsigned threshold, const class Dotty* dotty, bool merge, class StateSet& states, const class Property* prop) : StateReporter ( #ifdef EXPR_COMPILE compilation, #endif // EXPR_COMPILE net_, printer_, maxerrors, compress, local, flattened), myThreshold (threshold), myDotty (dotty), myMerge (merge), myUpdate (true), myDest (0), myDestSize (0), myStates (states), myProp (prop), myPropBits (prop ? log2 (prop->getNumStates ()) : 0), myPropSucc (0), myPropReject (false) { } StateSetReporter::StateSetReporter (const class StateSetReporter& old, bool update, class StateSet& states, const word_t* dest, unsigned destsize) : StateReporter ( #ifdef EXPR_COMPILE old.myCompilation, #endif // EXPR_COMPILE old.net, old.printer, 1, false, false, old.isFlattened ()), myThreshold (0), myDotty (old.myDotty), myMerge (old.myMerge), myUpdate (update), myDest (dest), myDestSize (destsize), myStates (states), myProp (old.myProp), myPropBits (old.myPropBits), myPropSucc (0), myPropReject (false) { } StateSetReporter::StateSetReporter (const class StateSetReporter& old, class StateSet& states) : StateReporter (old), myThreshold (0), myDotty (old.myDotty), myMerge (old.myMerge), myUpdate (true), myDest (0), myDestSize (0), myStates (states), myProp (old.myProp), myPropBits (old.myPropBits), myPropSucc (0), myPropReject (false) { } StateSetReporter::~StateSetReporter () { delete[] myPropSucc; } void StateSetReporter::displayPrologue () const { if (myDotty) myDotty->displayPrologue (myMerge); } void StateSetReporter::displayEpilogue () const { if (myDotty) myDotty->displayEpilogue (); } void StateSetReporter::displayMarking (const class GlobalMarking& m) const { if (myDotty) myDotty->displayMarking (m); else m.display (printer), printer.finish (); } void StateSetReporter::displayState (const word_t* s) const { class GlobalMarking m (net); m.decode (*net.getInitMarking (), s, myPropBits); displayMarking (m); } void StateSetReporter::displayPath (const word_t* src, const word_t* dest, unsigned destsize) const { class StateSetReporter reporter (*this, false, myStates, dest, destsize); reporter.displayPath (src); } bool StateSetReporter::do_addState (const void* state, size_t size) { return myStates.add (state, size); } word_t* StateSetReporter::do_popState (bool tail, size_t& size) { return myStates.pop (tail, size); } class GlobalMarking* StateSetReporter::pop (bool breadth) { delete[] myPropSucc; myPropSucc = 0; while (popState (breadth)) { inflate (); class GlobalMarking* m = new class GlobalMarking (net); const unsigned ps = m->decode (*net.getInitMarking (), mySrc, myPropBits); if (myProp) { class Valuation valuation; valuation.setGlobalMarking (m); myPropReject = !(*myProp)[ps].eval (valuation, myPropSucc, myProp->getFinalState ()); if (myPropReject && !valuation.isOK ()) { printer.printRaw ("property "); printer.print (ps); printer.printRaw (" evaluation error"); printer.finish (); flagFatal (); if (!myDest) myStates.reject (mySrc, mySrcSize, *this, StateSet::propertyError, isReduced ()); delete[] myPropSucc; myPropSucc = 0; delete m; return 0; } else if (!*myPropSucc) { delete[] myPropSucc; myPropSucc = 0; delete m; continue; } } return m; } return 0; } #ifdef EXPR_COMPILE # include "Compilation.h" bool StateSetReporter::popCompiled (bool breadth) { assert (!!myCompilation); delete[] myPropSucc; myPropSucc = 0; while (popState (breadth)) { myCompilation->stateDecode (net.getIndex (), mySrc, mySrcSize); if (myProp) { const unsigned ps = *myCompilation->getPropSucc (); enum Error err = myCompilation->propEval (ps); myPropReject = err == errComp; if (err && err != errComp) { printer.printRaw ("property "); printer.print (ps); printer.printRaw (" evaluation error"); printer.finish (); flagFatal (); if (!myDest) myStates.reject (mySrc, mySrcSize, *this, StateSet::propertyError, isReduced ()); delete[] myPropSucc; myPropSucc = 0; return false; } else if (!*myCompilation->getPropSucc ()) { continue; } } return true; } return false; } #endif // EXPR_COMPILE void StateSetReporter::addEvents () { delete[] myPropSucc; myPropSucc = 0; } bool StateSetReporter::report (const class Transition& transition, const class Valuation& valuation, const class GlobalMarking& marking, bool rejected) { /** flag: is the state new? */ bool isNew = false; if (myPropReject) rejected = true; const unsigned* p = myPropBits ? (myPropSucc + *myPropSucc) : 0; do { if (myPropBits) myStateBuf.append (*p, myPropBits); if (myDest) { if (myDestSize == myStateBuf.getNumWords () && !memcmp (myDest, myStateBuf.getBuf (), sizeof (word_t) * myDestSize)) { if (myDotty) myDotty->displayEdge (transition, valuation, marking); else transition.displayEdge (valuation, marking, printer); flagFatal (); return true; } } if (!myDest || myUpdate) { myStateBuf.deflate (); if (report (myStateBuf.getBuf (), myStateBuf.getNumBytes (), rejected, transition.isHidden (valuation), 0)) isNew = true; myStateBuf.inflate (); } if (!myPropBits) break; myStateBuf.remove (myPropBits); } while (--p > myPropSucc); return isNew; } void StateSetReporter::reportError (bool deadlock) { if (myDest) return; // reproducing a counterexample, not reporting an error deflate (); myStates.reject (mySrc, mySrcSize, *this, myFatal ? (deadlock ? StateSet::deadlockFatal : StateSet::rejectFatal) : (deadlock ? StateSet::deadlockState : StateSet::rejectState), isReduced ()); inflate (); if (error ()) flagFatal (); } #ifdef EXPR_COMPILE bool StateSetReporter::report (const void* state, size_t size, bool rejected, bool hidden) { return report (state, size, rejected, hidden, 0); } #endif // EXPR_COMPILE bool StateSetReporter::report (const void* state, size_t size, bool rejected, bool hidden, unsigned pending) { if (rejected || myPropReject) { if (!myDest) { myStates.reject (state, size, *this, myFatal ? StateSet::rejectFatal : StateSet::rejectState, isReduced ()); if (error ()) flagFatal (); } return true; } bool status = addState (state, size, hidden); if (myThreshold) { const unsigned numArcs = myStates.getNumArcs (); if (!(numArcs % myThreshold)) { const unsigned numStates = myStates.getNumStates (); printer.print (numStates), printer.printRaw (" states, "); printer.print (numArcs), printer.printRaw (" arcs, "); printer.print (myStates.getNumPending ()); if (pending) printer.delimiter ('+'), printer.print (pending); printer.printRaw (" pending"); printer.finish (); } } return status; } void StateSetReporter::reject (const void* dstate, size_t dlen, long offset, bool reduced, unsigned reason) { myStates.setOffset (offset); myStates.reject (dstate, dlen, *this, static_cast(reason), reduced); } word_t* StateSetReporter::pop (bool tail, size_t& size, long& offset) { word_t* buf = myStates.pop (tail, size); offset = myStates.getOffset (); return buf; } void StateSetReporter::setOffset (long offset) { myStates.setOffset (offset); } void StateSetReporter::reject () { if (!myDest) myStates.reject (mySrc, mySrcSize, *this, StateSet::inconsistent, isReduced ()); } void StateSetReporter::displayPath (const word_t* src) { assert (src && myDest); /** state spaces of the child nets (optional) */ class FullSet* childset = initModules (); /** the synchronising state space */ class SyncStates* sync = childset ? new class SyncStates (net) : 0; /** Flag: has the analysis been interrupted? */ extern volatile bool interrupted; const unsigned numTr = childset ? net.getNumTransitions () : net.getNumAllTransitions (); unsigned ps, i; class GlobalMarking m (net); // Initialize the context and fetch the source state ps = m.decode (*net.getInitMarking (), src, myPropBits); again: myFatal = false; if (myProp) { class Valuation valuation; valuation.setGlobalMarking (&m); myPropReject = !(*myProp)[ps].eval (valuation, myPropSucc, myProp->getFinalState ()); if (myPropReject && !valuation.isOK ()) { assert (false); delete[] childset; delete sync; return; } assert (*myPropSucc > 0); } else myPropSucc = 0; #ifndef NDEBUG mySrcDeadlock = true; #endif // NDEBUG for (i = 0, myPriority = 0; !interrupted && !myFatal && i < numTr; i++) { const class Transition& t = net.getTransition (i); if ((!myPriority || t.getPriority () == myPriority) && (!childset || !t.getNumChildren ())) t.analyze (m, *this); // synchronisation transitions (which have children) are analysed // by SyncStates::sync (), called via analyzeModules () below } if (childset) analyzeModules (m, *sync, childset); assert (i == numTr || interrupted || myFatal); if (!interrupted && !myFatal) { // path compression has eliminated the state; reconstruct it assert (!myPropSucc || *myPropSucc == 1); assert (!mySrcDeadlock); ps = myPropSucc ? myPropSucc[1] : 0; addEvents (); for (i = 0, myPriority = 0; !interrupted && !myFatal && i < numTr; i++) { const class Transition& t = net.getTransition (i); if ((!myPriority || t.getPriority () == myPriority) && (!childset || !t.getNumChildren ())) t.analyze (m, *this); } assert (myFatal); goto again; } assert (interrupted || myFatal); delete[] childset; delete sync; } maria-1.3.5/Graph/StateSetReporter.h0000644000175000017500000002141707643247662017475 0ustar msmakelamsmakela// Reporting successor states in safety property analysis -*- c++ -*- #ifndef STATESETREPORTER_H_ # define STATESETREPORTER_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "StateReporter.h" /** @file StateSetReporter.h * Interface for reporting successor states in safety property analysis */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Reporting successor states in safety property analysis */ class StateSetReporter : public StateReporter { public: /** Constructor * @param compilation the compiled model (optional) * @param net_ the net that is being analysed * @param printer_ printer object for diagnostic output * @param maxerrors maximum number of allowed errors (0=infinity) * @param compress flag: collapse deterministic sequences? * @param local flag: suppress transient (invisible) states? * @param flattened flag: consider the flattened net? * @param threshold threshold for reporting state space statistics * @param dotty visualization interface for counterexamples * @param merge flag: merge visual counterexamples to one graph? * @param states the state space being generated * @param prop property being analyzed (optional) */ StateSetReporter ( # ifdef EXPR_COMPILE const class Compilation* compilation, # endif // EXPR_COMPILE const class Net& net_, const class Printer& printer_, unsigned maxerrors, bool compress, bool local, bool flattened, unsigned threshold, const class Dotty* dotty, bool merge, class StateSet& states, const class Property* prop); /** Constructor for recovering error traces * @param old the reporter being copied * @param update flag: update the state space? * @param states the state space being generated * @param dest the encoded inflated destination state * @param destsize length of the encoded state being sought, in words */ StateSetReporter (const class StateSetReporter& old, bool update, class StateSet& states, const word_t* dest, unsigned destsize); /** Constructor for client-side reporting in distributed search * @param old the reporter being copied * @param states the state space being generated */ StateSetReporter (const class StateSetReporter& old, class StateSet& states); private: /** Copy constructor */ StateSetReporter (const class StateSetReporter& old); /** Assignment operator */ class StateSetReporter& operator= (const class StateSetReportert& other); public: /** Destructor */ ~StateSetReporter (); /** Start displaying an error trace */ void displayPrologue () const; /** Finish displaying an error trace */ void displayEpilogue () const; /** Display a marking */ void displayMarking (const class GlobalMarking& m) const; /** Display an encoded inflated state * @param s the state to be displayed */ void displayState (const word_t* s) const; /** Display a path leading from a state to another * @param src the encoded inflated source state * @param dest the encoded inflated destination state * @param destsize length of the encoded state being sought, in words */ void displayPath (const word_t* src, const word_t* dest, unsigned destsize) const; private: /** Add an encoded state to the state space * @param state the encoded state * @param size length of the encoded state in bytes * @return true if the state was new */ bool do_addState (const void* state, size_t size); /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @param size (output) length of the encoded stream * @return the encoded state, or NULL if none available */ word_t* do_popState (bool tail, size_t& size); /** Dequeue an unprocessed state * @param breadth true=dequeue (FIFO, queue), false=pop (LIFO, stack) * @return an unprocessed state, or NULL if all processed */ class GlobalMarking* pop (bool breadth); # ifdef EXPR_COMPILE /** Dequeue an unprocessed state * @param breadth true=dequeue (FIFO, queue), false=pop (LIFO, stack) * @return true if a state was found, or false if all processed */ bool popCompiled (bool breadth); # endif // EXPR_COMPILE /** Add all events from the current source state to the graph */ void addEvents (); /** Report a successor state * @param transition the transition fired * @param valuation the binding of the transition * @param marking the resulting marking * @param rejected flag: is the state rejected? * @return true if analysis should proceed; false on fatal error */ bool report (const class Transition& transition, const class Valuation& valuation, const class GlobalMarking& marking, bool rejected); /** Report a deadlock or an error in the current state * @param deadlock flag: is this a deadlock? */ void reportError (bool deadlock); public: # ifdef EXPR_COMPILE /** Report a successor state * @param state the resulting encoded deflated state (mandatory) * @param size length of the encoded state, in bytes * @param rejected flag: is the state rejected? * @param hidden flag: is the transition to the state hidden? * @return true if the state was new */ bool report (const void* state, size_t size, bool rejected, bool hidden); # endif // EXPR_COMPILE /** @name Server-side methods for distributed verification */ /*@{*/ /** Report a successor state and a number of pending states * @param state the resulting encoded deflated state (mandatory) * @param size length of the encoded state, in bytes * @param rejected flag: is the state rejected? * @param hidden flag: is the transition to the state hidden? * @param pending number of additional pending states * @return true if the state was new */ bool report (const void* state, size_t size, bool rejected, bool hidden, unsigned pending); /** Display path to a rejected state * @param dstate the encoded rejected state * @param dlen length of dstate in bytes * @param offset offset to the counterexample path file * @param reduced flag: has the state space been reduced? * @param reason reason for rejecting the state */ void reject (const void* dstate, size_t dlen, long offset, bool reduced, unsigned reason); /** Fetch an encoded state * @param tail flag: retrieve from tail of list instead of head * @param size (output) length of the encoded stream * @param offset (output) offset to the counterexample file * @return the encoded state */ word_t* pop (bool tail, size_t& size, long& offset); /** Set the offset to the counterexample * @param offset offset to the counterexample path file */ void setOffset (long offset); /*@}*/ private: /** Report an inconsistent successor state */ void reject (); /** Display a path from src to myDest * @param src the encoded inflated source state */ void displayPath (const word_t* src); private: /** Threshold for reporting intermediate statistics */ const unsigned myThreshold; /** Visualization interface for counterexamples */ const class Dotty* const myDotty; /** Flag: merge visual counterexamples to one graph? */ const bool myMerge; /** Flag: update the state space? */ const bool myUpdate; /** Encoded state being sought (optional) */ const word_t* const myDest; /** Length of the encoded state being sought */ const unsigned myDestSize; /** The state space being generated */ class StateSet& myStates; /** Property being analyzed (optional) */ const class Property* const myProp; /** Number of bits per property state (0 when no property) */ const unsigned myPropBits; /** Amount and numbers of the enabled successor states in myProp */ unsigned* myPropSucc; /** Flag: is the property automaton about to enter a rejecting state? */ bool myPropReject; }; #endif // STATESETREPORTER_H_ maria-1.3.5/Graph/States.C0000644000175000017500000000211407643247662015405 0ustar msmakelamsmakela// Collection of states -*- c++ -*- /** @file States.C * Collection of states, represented with bit vectors */ #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "States.h" /* Copyright © 2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ maria-1.3.5/Graph/States.h0000644000175000017500000000730207643247662015456 0ustar msmakelamsmakela// Collection of states -*- c++ -*- /** @file States.C * Collection of states, represented with bit vectors */ /* Copyright © 2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifndef STATES_H_ # define STATES_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "BitBuffer.h" /** Collection of states */ class States { public: /** An encoded state */ struct state { /** length of the encoded state, in bytes */ size_t size; /** the deflated encoded state */ word_t* buf; }; /** Constructor */ States () : myStates (0), myNumber (0), myAllocated (0) {} private: /** Copy constructor */ States (const class States& old); /** Assignemnt operator */ class States& operator= (const class States& other); public: /** Destructor */ ~States () { for (unsigned i = myNumber; i--; ) delete[] myStates[i].buf; operator delete (myStates); } /** Get the number of states in the set */ size_t size () const { return myNumber; } /** Index the state array */ const struct state& operator[] (unsigned i) { return myStates[i]; } /** Clear the set */ void clear () { for (unsigned i = myNumber; i--; ) delete[] myStates[i].buf; memset (myStates, 0, myNumber * sizeof *myStates); myNumber = 0; } /** Search for a state in the set * @param buf the deflated encoded state * @param len length of the state in bytes * @return the index of the state + 1, or 0 if not found */ unsigned search (const void* buf, size_t len) const { unsigned i = myNumber; while (i--) if (len == myStates[i].size && !memcmp (myStates[i].buf, buf, len)) break; return i + 1; } /** Add a state to the set * @param buf the deflated encoded state * @param len length of the state in bytes * @return true if the state was new */ bool add (const void* buf, size_t len) { if (search (buf, len)) return false; if (!myAllocated) { assert (!myNumber && !myStates); myAllocated = 1; myStates = reinterpret_cast (operator new (sizeof *myStates)); } else if (myNumber >= myAllocated) { assert (myNumber && myStates); struct state* states = reinterpret_cast (memcpy (operator new ((myAllocated << 1) * sizeof *states), myStates, myAllocated * sizeof *states)); delete[] myStates; myStates = states; myAllocated <<= 1; } struct state& s = myStates[myNumber++]; s.size = len; memcpy (s.buf = new word_t[1 + (len - 1) / sizeof (word_t)], buf, len); return true; } # if (!defined __sgi && !defined __DECCXX) || defined __GNUC__ private: # endif // MIPS CC and DEC cxx bug work-around struct state* myStates; private: /** Number of used entries in myStates */ unsigned myNumber; /** Number of entries allocated for myStates */ unsigned myAllocated; }; #endif // STATES_H_ maria-1.3.5/Graph/SyncStates.C0000644000175000017500000003162607643247662016254 0ustar msmakelamsmakela// Collection of synchronisation states -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "SyncStates.h" #include "Net.h" #include "Transition.h" #include "GlobalMarking.h" #include "StateReporter.h" #ifdef ADD_CACHE # include "FullSet.h" #endif // ADD_CACHE /** @file SyncStates.C * Collection of synchronisation states for modular analysis */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ SyncStates::SyncStates (const class Net& net) : myNumModules (net.getNumChildren ()), myTransitionMap (), #ifdef SYNC_CACHE myStateMap (new StateMap[myNumModules]), myStateSet (0), myStateIndex (new unsigned[myNumModules]), myStateUsed (0), myStateAlloc (0) #else // SYNC_CACHE myStateSet (0), myEnabled (0) #endif // SYNC_CACHE #ifdef ADD_CACHE , mySync (net.getParent () ? 0 : new class FullSet ()) #endif // ADD_CACHE { assert (myNumModules > 0); unsigned i = net.getNumTransitions (), numLabels = 0; while (i--) { const class Transition& t = net.getTransition (i); if (t.getNumChildren ()) const_cast(myTransitionMap).insert (TransitionMap::value_type (&t, numLabels++)); } #ifdef SYNC_CACHE for (i = myNumModules; i--; ) myStateIndex[i] = UINT_MAX; #else // SYNC_CACHE *const_cast(&myStateSet) = new StateSet*[myNumModules * numLabels]; memset (myStateSet, 0, myNumModules * numLabels * sizeof *myStateSet); *const_cast(&myEnabled) = new bool[numLabels]; memset (myEnabled, 0, numLabels * sizeof *myEnabled); #endif // SYNC_CACHE #ifdef ADD_CACHE if (mySync && !mySync->init (false)) assert (false); #endif // ADD_CACHE } SyncStates::~SyncStates () { #ifdef SYNC_CACHE for (StateMap* sm = myStateMap + myNumModules; sm-- > myStateMap; ) for (StateMap::iterator si = sm->begin (); si != sm->end (); si++) delete[] si->first; delete[] myStateMap; if (myStateSet) { for (unsigned i = myStateUsed; i--; ) { if (!myStateSet[i]) continue; for (StateSet::iterator j = myStateSet[i]->begin (); j != myStateSet[i]->end (); j++) delete[] *j; delete myStateSet[i]; } delete[] myStateSet; } else assert (!myStateUsed); delete[] myStateIndex; #else // SYNC_CACHE for (unsigned i = myNumModules * myTransitionMap.size (); i--; ) { if (!myStateSet[i]) continue; for (StateSet::iterator j = myStateSet[i]->begin (); j != myStateSet[i]->end (); j++) delete[] *j; delete myStateSet[i]; } delete[] myStateSet; delete[] myEnabled; #endif // SYNC_CACHE #ifdef ADD_CACHE delete mySync; #endif // ADD_CACHE } /** Copy a state * @param buf the state * @param size length of the state in words * @return a copy of the state, tagged with its length */ static word_t* copy (const word_t* buf, word_t size) { word_t* s = new word_t[size + 1]; *s = size; memcpy (s + 1, buf, size * sizeof *buf); return s; } #ifdef SYNC_CACHE bool SyncStates::lookup (unsigned module, const word_t* buf, word_t size) { word_t* state = ::copy (buf, size); std::pair p = myStateMap[module].insert (StateMap::value_type (state, myStateUsed)); if (!p.second) { delete[] state; myStateIndex[module] = p.first->second; return true; } // new source state: add it to the cache myStateIndex[module] = myStateUsed; myStateUsed += myTransitionMap.size (); // expand myStateSet[] if needed if (myStateAlloc < myStateUsed) { unsigned ssize = myStateAlloc ? myStateAlloc << 1 : 1; while (ssize < myStateUsed) ssize <<= 1; StateSet** s = new StateSet*[ssize]; memcpy (s, myStateSet, myStateAlloc * sizeof *s); memset (s + myStateAlloc, 0, (ssize - myStateAlloc) * sizeof *s); delete[] myStateSet; myStateSet = s; myStateAlloc = ssize; } return false; } #else // SYNC_CACHE void SyncStates::cleanup () { memset (myEnabled, 0, myTransitionMap.size () * sizeof *myEnabled); for (unsigned i = myNumModules * myTransitionMap.size (); i--; ) { if (myStateSet[i]) { for (StateSet::iterator j = myStateSet[i]->begin (); j != myStateSet[i]->end (); j++) delete[] *j; delete myStateSet[i]; myStateSet[i] = 0; } } } #endif // SYNC_CACHE void SyncStates::add (const class Transition& transition, const word_t* buf, word_t size) { assert (transition.getNumParents ()); assert (&transition.getNet ()->getParent ()->getChild (transition.getNet ()->getParentIndex ()) == transition.getNet ()); assert (transition.getNet ()->getParentIndex () < myNumModules); for (unsigned parent = transition.getNumParents (); parent--; ) { TransitionMap::const_iterator i = myTransitionMap.find (&transition.getParent (parent)); assert (i != myTransitionMap.end ()); #ifdef SYNC_CACHE StateSet*& s = myStateSet[myStateIndex[transition.getNet ()->getParentIndex ()] + i->second]; #else // SYNC_CACHE const unsigned ti = i->second; myEnabled[ti] = true; StateSet*& s = myStateSet[transition.getNet ()->getParentIndex () + myNumModules * ti]; #endif // SYNC_CACHE if (!s) s = new StateSet (); // for simplicity, copy the state for each label the transition exports word_t* state = ::copy (buf, size); std::pair p = s->insert (state); if (!p.second) delete[] state; } } /** Synchronise on a label * @param child number of the child transition being checked * @param transition the synchronisation label * @param ss the local synchronisation states * @param ssi base indexes to ss[], indexed by module * @param ti index number of the synchronisation label * @param m the source marking * @param tibits number of bits for representing sync labels * @param syncset set of already encountered sync states * @param buf buffer for encoding states * @param reporter the interface for reporting successor states */ static void sync (unsigned child, const class Transition& transition, SyncStates::StateSet** ss, #ifdef SYNC_CACHE const unsigned* ssi, unsigned ti, #elif defined ADD_CACHE unsigned ti, #endif // SYNC_CACHE class GlobalMarking& m, #ifdef ADD_CACHE unsigned tibits, class FullSet* syncset, #endif // ADD_CACHE class BitPacker& buf, class StateReporter& reporter) { if (child < transition.getNumChildren ()) { const class Net& net = *transition.getChild (child).getNet (); assert (&net.getParent ()->getChild (net.getParentIndex ()) == &net); #ifdef SYNC_CACHE if (ssi[net.getParentIndex ()] == UINT_MAX); else if (const SyncStates::StateSet* sset = ss[ssi[net.getParentIndex ()] + ti]) #else // SYNC_CACHE if (const SyncStates::StateSet* sset = ss[net.getParentIndex ()]) #endif // SYNC_CACHE { for (SyncStates::StateSet::const_iterator i = sset->begin (); i != sset->end (); i++) { m.decode (net, (*i) + 1); sync (child + 1, transition, ss, #ifdef SYNC_CACHE ssi, ti, #elif defined ADD_CACHE ti, #endif // SYNC_CACHE m, #ifdef ADD_CACHE tibits, syncset, #endif // ADD_CACHE buf, reporter); } } } else { #ifdef ADD_CACHE if (syncset) { buf.clear (); if (!m.encode (buf, *transition.getNet ()->getInitMarking (), 0)) assert (false); // rejected source state buf.append (ti, tibits); buf.deflate (); if (!syncset->add (buf.getBuf (), buf.getNumBytes ())) { reporter.enabled (transition); return; // this transition has been analysed in the state } else { // we do not need a search queue: we just want to eliminate duplicates size_t size; delete[] syncset->pop (false, size); assert (!syncset->pop (false, size)); } } #endif // ADD_CACHE buf.clear (); if (!m.encode (buf, *transition.getNet ()->getInitMarking (), 0)) assert (false); // rejected source state word_t* s = new word_t[buf.getNumWords ()]; memcpy (s, buf.getBuf (), buf.getNumWords () * sizeof *s); reporter.setSyncSource (s, buf.getNumBytes ()); transition.analyze (m, reporter); } } void SyncStates::sync (const class GlobalMarking& m, const class Transition& transition, class StateReporter& reporter) const { assert (transition.getNumChildren () > 0); assert (myTransitionMap.find (&transition) != myTransitionMap.end ()); class GlobalMarking succ (m); class BitPacker buf; #ifndef SYNC_CACHE if (!myEnabled[myTransitionMap.find (&transition)->second]) return; #endif // SYNC_CACHE ::sync (0, transition, #ifdef SYNC_CACHE myStateSet, myStateIndex, myTransitionMap.find (&transition)->second, #else // SYNC_CACHE myStateSet + myNumModules * myTransitionMap.find (&transition)->second, # ifdef ADD_CACHE myTransitionMap.find (&transition)->second, # endif // ADD_CACHE #endif // SYNC_CACHE succ, #ifdef ADD_CACHE mySync ? ::log2 (myTransitionMap.size ()) : 0, mySync, #endif // ADD_CACHE buf, reporter); } #ifdef EXPR_COMPILE # include "Compilation.h" /** Synchronise on a label * @param child number of the child transition being checked * @param transition the synchronisation label * @param ss the local synchronisation states * @param ssi base indexes to ss[], indexed by module * @param ti index number of the synchronisation label * @param tibits number of bits for representing sync labels * @param syncset set of already encountered sync states * @param reporter the interface for reporting successor states * @param srcs encoded deflated states (for restoring the state) */ static void sync (unsigned child, const class Transition& transition, SyncStates::StateSet** ss, #ifdef SYNC_CACHE const unsigned* ssi, unsigned ti, #elif defined ADD_CACHE unsigned ti, #endif // SYNC_CACHE #ifdef ADD_CACHE unsigned tibits, class FullSet* syncset, #endif // ADD_CACHE class StateReporter& reporter, word_t** srcs) { if (child < transition.getNumChildren ()) { const class Net& net = *transition.getChild (child).getNet (); assert (&net.getParent ()->getChild (net.getParentIndex ()) == &net); #ifdef SYNC_CACHE if (ssi[net.getParentIndex ()] == UINT_MAX); else if (const SyncStates::StateSet* sset = ss[ssi[net.getParentIndex ()] + ti]) #else // SYNC_CACHE if (const SyncStates::StateSet* sset = ss[net.getParentIndex ()]) #endif // SYNC_CACHE { for (SyncStates::StateSet::const_iterator i = sset->begin (); i != sset->end (); i++) { reporter.myCompilation->stateDecode (net.getIndex (), (*i) + 1, 0); sync (child + 1, transition, ss, #ifdef SYNC_CACHE ssi, ti, #elif defined ADD_CACHE ti, #endif // SYNC_CACHE #ifdef ADD_CACHE tibits, syncset, #endif // ADD_CACHE reporter, srcs); } reporter.myCompilation->stateDecode (net.getIndex (), srcs[net.getParentIndex ()], 0); } } else { #ifdef ADD_CACHE if (syncset) { unsigned bytes; const void* buf = reporter.myCompilation->stateProject (transition.getNet ()->getIndex (), ti, tibits, bytes); if (!syncset->add (buf, bytes)) { reporter.enabled (transition); return; // this transition has been analysed in the state } else { // we do not need a search queue: we just want to eliminate duplicates size_t size; delete[] syncset->pop (false, size); assert (!syncset->pop (false, size)); } } #endif // ADD_CACHE reporter.sync (transition); } } void SyncStates::sync (const class Transition& transition, class StateReporter& reporter, word_t** srcs) const { assert (transition.getNumChildren () > 0); assert (myTransitionMap.find (&transition) != myTransitionMap.end ()); #ifndef SYNC_CACHE if (!myEnabled[myTransitionMap.find (&transition)->second]) return; #endif // SYNC_CACHE ::sync (0, transition, #ifdef SYNC_CACHE myStateSet, myStateIndex, myTransitionMap.find (&transition)->second, #else // SYNC_CACHE myStateSet + myNumModules * myTransitionMap.find (&transition)->second, # ifdef ADD_CACHE myTransitionMap.find (&transition)->second, # endif // ADD_CACHE #endif // SYNC_CACHE #ifdef ADD_CACHE mySync ? ::log2 (myTransitionMap.size ()) : 0, mySync, #endif // ADD_CACHE reporter, srcs); } #endif // EXPR_COMPILE maria-1.3.5/Graph/SyncStates.h0000644000175000017500000001142307643247662016312 0ustar msmakelamsmakela// Collection of synchronisation states -*- c++ -*- #ifndef SYNCSTATES_H_ # define SYNCSTATES_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include # include "BitBuffer.h" /** @file SyncStates.h * Collection of synchronisation states for modular analysis */ /* Copyright © 2002-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Collection of synchronisation states for modular analysis */ class SyncStates { public: /** Map of synchronisation labels to label numbers */ typedef std::map TransitionMap; /** Comparison operator for encoded states */ struct ltstate { /** Less-than comparison * @param s1 first state to be compared * @param s2 second state to be compared * @return true if s1 < s2 */ bool operator() (const word_t* s1, const word_t* s2) const { return *s1 == *s2 ? memcmp (s1 + 1, s2 + 1, *s1 * sizeof *s1) : (*s1 < *s2); } }; /** Set of encoded states */ typedef std::set StateSet; # ifdef SYNC_CACHE /** Map from (child,state) pairs to basic indexes to state sets */ typedef std::map StateMap; # endif // SYNC_CACHE /** Constructor * @param net the net whose children are being synchronised */ SyncStates (const class Net& net); private: /** Copy constructor */ SyncStates (const class SyncStates& old); /** Assignment operator */ class SyncStates& operator= (const class SyncStates& old); public: /** Destructor */ ~SyncStates (); # ifdef SYNC_CACHE /** Look up the synchronisation states of a module at a specific state * @param module the index of the module * @param buf the encoded source state * @param size length of the encoded state in words * @return whether the state has been already explored */ bool lookup (unsigned module, const word_t* buf, word_t size); # else // SYNC_CACHE /** Clean up the set of synchronisation states and labels */ void cleanup (); # endif // SYNC_CACHE /** Add a synchronisation state * @param transition the child transition * @param buf the encoded source state * @param size length of the encoded state in words */ void add (const class Transition& transition, const word_t* buf, word_t size); /** Synchronise on a label * @param m the source marking * @param transition the synchronisation label * @param reporter the interface for reporting successor states */ void sync (const class GlobalMarking& m, const class Transition& transition, class StateReporter& reporter) const; # ifdef EXPR_COMPILE /** Synchronise on a label * @param transition the synchronisation label * @param reporter the interface for reporting successor states * @param srcs encoded inflated states (for restoring the state) */ void sync (const class Transition& transition, class StateReporter& reporter, word_t** srcs) const; # endif // EXPR_COMPILE private: /** Number of modules */ const unsigned myNumModules; /** Map from synchronisation labels to index numbers */ const TransitionMap myTransitionMap; # ifdef SYNC_CACHE /** Maps from states to myStateSet[] base indexes, indexed by module */ StateMap* myStateMap; /** Sets of synchronisation states indexed by (src,child)+label numbers */ StateSet** myStateSet; /** myStateSet[] base indexes corresponding to the current (child,src) */ unsigned* myStateIndex; /** Used number of entries in myStateSet */ unsigned myStateUsed; /** Allocated number of entries for myStateSet */ unsigned myStateAlloc; # else // SYNC_CACHE /** Sets of synchronisation states indexed by module+myNumModules*label */ StateSet** const myStateSet; /** Enabled labels */ bool* const myEnabled; # endif // SYNC_CACHE # ifdef ADD_CACHE /** Synchronisation states that have already been processed */ mutable class FullSet* mySync; # endif // ADD_CACHE }; #endif // SYNCSTATES_H_ maria-1.3.5/Graph/file.h0000644000175000017500000000374707643247662015143 0ustar msmakelamsmakela/* Efficient file abstraction layer -*- c++ -*- */ #ifndef FILE_H_ # define FILE_H_ /** @file file.h * Efficient file abstraction layer. * Use mmap(2) and friends on Unix systems when USE_MMAP is defined. * As a portable fall-back method, use FILE pointers. */ /* Copyright © 2001-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ # include # ifndef unix # if defined __unix||defined __unix__||defined __NetBSD__||defined __APPLE__ # define unix # endif # endif # if defined unix && defined USE_MMAP # include # ifdef NO_MMAP # include # else // NO_MMAP # include # endif // NO_MMAP /** File handle */ typedef struct { # ifndef NO_MMAP int fd; /**< UNIX file descriptor */ # endif // !NO_MMAP long len; /**< used file length in bytes */ long alloc; /**< allocated file length in bytes */ # ifdef __sun caddr_t addr; /**< address of the mapped memory area */ # else // __sun void* addr; /**< address of the mapped memory area */ # endif // __sun } file_t; # else // __unix && USE_MMAP # undef USE_MMAP /** File handle */ typedef FILE* file_t; # endif // __unix && USE_MMAP #endif // FILE_H_ maria-1.3.5/Graph/fileformat.html0000644000175000017500000001063207410052536017042 0ustar msmakelamsmakela The format of the disk-based reachability graph files

The format of the disk-based reachability graph files

The machine-dependent disk-based reachability graph files are handled by the class Graph. There are four files: a directory (having a suffix .rgd), a state file (.rgs), containing the global marking of the Petri Net in each state (node of the reachability graph), an arc file (.rga), containing the events leading from one state to another, and a hash map (.rgh) of generated states.

The reachability graph directory (.rgd)

The directory begins with a magic cookie and the file name of the model being analyzed. Following them is an index to all states of the net.

ItemSize
magic cookie (text) sizeof magic
name of the Petri Net a NUL-terminated string
optional padding to make the rest of the file word-aligned 0 to sizeof (Graph::fpos_t)-
number of states sizeof (unsigned)
number of arcs sizeof (unsigned)
offsets in the state, arc and predecessor state files
Setting the most significant bit of the state offset indicates an erroneous state. An arc offset of -2 (all except the least significant bit set) indicates that the state has no successors. An arc offset of -1 (all bits set) indicates that the successors have not been generated. A predecessor state offset of -1 indicates that no predecessors have been stored for the state.
numStates * (3 * sizeof (fpos_t))

The state file (.rgs)

The state file contains the encoded representations of the states (contents of BitPacker::myBuf), stored as bytes. The file is accessed by seeking to the offset recorded in the graph directory.

The arc file (.rga)

The arc file contains the events (transition instances) between states. Each event has a source state (implicit from the graph directory) and a target state.

An offset in the graph directory points to an encoded successor arc record. The length of the encoded transition instances (in bytes) and the number of successor states are stored using a byte-aligned variable-length code. An following array of card_t specifies the target state numbers of the arcs. This array is followed by a bit string that contains the encoded transition instances.

The predecessor state file (.rgp)

The predecessor state file is a singly linked list of state numbers and file offsets. The records are pairs of file offsets (fpos_t) and state numbers (card_t). An offset of -1 (all bits set) indicates the end of the list.

The hash map of generated states (.rgh)

The hash file, implemented as a 256-degree B-tree, maps hash values of encoded states to state numbers. The file consists of blocks of 512 words.

The first word, word 0, contains the number of keys (0 to 255) and a flag that indicates whether the B-tree node is internal (containing links to further B-tree nodes), or a leaf node (containing state numbers).

Words 1 through 255 contain the keys, hash values of encoded states, in ascending order. Unused entries are zeros.

In an internal node, words 256 through 511 contain links to B-trees, zero-based node numbers. Node 0 is the root of the tree. The nodes are stored sequentially in the B-tree file.

In a leaf node, word 256 is unused, and words 257 through 511 contain state numbers. Word 257 contains the state number corresponding the hash value in word 1; the state number in word 258 is associated with the key in word 2, and so on. A leaf node may contain up to 255 state numbers.

maria-1.3.5/Net/0000755000175000017500000000000010272511404013501 5ustar msmakelamsmakelamaria-1.3.5/Net/Transition.C0000644000175000017500000031251610232531653015753 0ustar msmakelamsmakela// Transition class -*- c++ -*- /** @file Transition.C * Transition in an algebraic system net */ /* Copyright © 1998-2003,2005 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Transition.h" #include "Place.h" #include "Arc.h" #include "Constant.h" #include "Undefined.h" #include "VariableDefinition.h" #include "VariableSet.h" #include "LeafValue.h" #include "Token.h" #include "GlobalMarking.h" #include "Valuation.h" #include "Substitution.h" #include "BooleanBinop.h" #include "Function.h" #include "Quantifier.h" #include "Printer.h" #include "DummyReporter.h" #include "Net.h" #include "Search.h" #include "LNet.h" #include "BitVector.h" #include "Variable.h" #include "PlaceContents.h" #include "Property.h" /** Flag: has the analysis been interrupted? */ extern volatile bool interrupted; /** Check for unacceptable valuations and clear the errors * @param status default return value * @param transition the transition * @param valuation valuation to be checked * @param marking the marking being processed * @param reporter object for reporting found states and errors * @param reason reason for failure (optional) * @return status, or false if there is an error in the valuation */ static bool willDo (bool status, const class Transition& transition, class Valuation& valuation, const class GlobalMarking& marking, class StateReporter& reporter, const char* reason = 0) { if (!valuation.isOKorVar () || reason) { status = false; reporter.reject (transition, valuation, marking, reason, 0); } valuation.clearErrors (); return status; } /** Augment the valuation with initial assignments to output variables * @param transition the transition * @param valuation the valuation * @param marking the marking being processed * @param reporter object for reporting found states and errors * @return true if the operation succeeded */ static bool firstOutput (const class Transition& transition, class Valuation& valuation, const class GlobalMarking& marking, class StateReporter& reporter) { if (const class QuantifierList* vars = transition.getOutputVariables ()) { switch (vars->augment (valuation)) { case Quantifier::pass: return true; case Quantifier::fail: switch (vars->advance (valuation)) { case Quantifier::pass: return true; case Quantifier::fail: willDo (false, transition, valuation, marking, reporter, "empty output:"); vars->clear (valuation); return false; case Quantifier::undefined: break; } // fall through case Quantifier::undefined: willDo (false, transition, valuation, marking, reporter, "first output:"); vars->clear (valuation); return false; } } return true; } /** Iterate to the next assignment to output variables * @param transition the transition * @param valuation the valuation * @param marking the marking being processed * @param reporter object for reporting found states and errors * @return true if a new valuation was generated */ static bool nextOutput (const class Transition& transition, class Valuation& valuation, const class GlobalMarking& marking, class StateReporter& reporter) { if (const class QuantifierList* vars = transition.getOutputVariables ()) { switch (vars->advance (valuation)) { case Quantifier::pass: return true; case Quantifier::undefined: willDo (false, transition, valuation, marking, reporter, "iterating output:"); // fall through case Quantifier::fail: vars->clear (valuation); break; } } return false; } /** Fire the output arcs of a transition * @param transition the transition * @param valuation the transition instance * @param marking the state (input/output parameter) * @param reporter object for reporting found states and errors */ static void fireOutputs (const class Transition& transition, class Valuation& valuation, class GlobalMarking& marking, class StateReporter& reporter) { assert (valuation.isOK ()); for (unsigned out = 0; out < transition.getNumOutputs (); out++) { const class Arc& arc = transition.getOutput (out); class PlaceMarking& place = marking[reporter.isFlattened () ? arc.getPlace ().getIndex () : arc.getIndex ()]; if (!arc.getExpr ().add (place, 1, valuation)) { willDo (false, transition, valuation, marking, reporter, "firing:"); return; } } reporter.report (transition, valuation, marking); } Transition::Transition () : myNet (0), myLocalIndex (0), myRootIndex (0), myName (0), myNumParents (0), myParents (0), myNumChildren (0), myChildren (0), myPriority (0), myKind (tNormal), myNumInputs (0), myInputs (0), myNumOutputs (0), myOutputs (0), myOutputMarking (false), myUnif (0), myNumWeaklyFair (0), myNumStronglyFair (0), myNumEnabled (0), myWeaklyFairCond (0), myStronglyFairCond (0), myEnabledCond (0), myWeaklyFairSet (0), myStronglyFairSet (0), myEnabledSet (0), myGates (), myHide (0), myOutputVariables (0), myVariables (), myFunctions (), myNumConstants (0), myConstantNames (0), myConstants (0) { } Transition::Transition (class Net& net, unsigned i, char* name) : myNet (&net), myLocalIndex (i), myRootIndex (i), myName (name), myNumParents (0), myParents (0), myNumChildren (0), myChildren (0), myPriority (0), myKind (tNormal), myNumInputs (0), myInputs (0), myNumOutputs (0), myOutputs (0), myOutputMarking (false), myUnif (0), myNumWeaklyFair (0), myNumStronglyFair (0), myNumEnabled (0), myWeaklyFairCond (0), myStronglyFairCond (0), myEnabledCond (0), myWeaklyFairSet (0), myStronglyFairSet (0), myEnabledSet (0), myGates (), myHide (0), myOutputVariables (0), myVariables (), myFunctions (), myNumConstants (0), myConstantNames (0), myConstants (0) { } Transition::~Transition () { delete[] myName; delete[] myChildren; delete[] myParents; while (myNumInputs) delete myInputs[--myNumInputs]; delete[] myInputs; while (myNumOutputs) delete myOutputs[--myNumOutputs]; delete[] myOutputs; for (struct unif* u; (u = myUnif); myUnif = u) { u = u->next; delete myUnif->vars; delete myUnif; }; while (myNumWeaklyFair) myWeaklyFairCond[--myNumWeaklyFair]->destroy (); delete[] myWeaklyFairCond; delete[] myWeaklyFairSet; while (myNumStronglyFair) myStronglyFairCond[--myNumStronglyFair]->destroy (); delete[] myStronglyFairCond; delete[] myStronglyFairSet; while (myNumEnabled) myEnabledCond[--myNumEnabled]->destroy (); delete[] myEnabledCond; delete[] myEnabledSet; for (GateList::iterator g = myGates.begin (); g != myGates.end (); g++) (*g)->destroy (); myHide->destroy (); for (FunctionMap::iterator f = myFunctions.begin (); f != myFunctions.end (); f++) delete f->second; if (myOutputVariables) { for (QuantifierList::const_iterator q = myOutputVariables->begin (); q != myOutputVariables->end (); q++) { iterator v = myVariables.find ((*q)->getVariable ().getName ()); assert (v != end () && v->second == &(*q)->getVariable ()); v->second = 0; } delete myOutputVariables; } for (iterator v = myVariables.begin (); v != myVariables.end (); v++) delete v->second; while (myNumConstants--) { delete[] myConstantNames[myNumConstants]; myConstants[myNumConstants]->destroy (); } delete[] myConstantNames; delete[] myConstants; } #ifndef NDEBUG bool Transition::hasParent (const class Transition& parent) const { for (unsigned i = myNumParents; i--; ) if (myParents[i] == &parent) return true; return false; } bool Transition::hasChild (const class Transition& child) const { for (unsigned i = myNumChildren; i--; ) if (myChildren[i] == &child) return true; return false; } #endif // NDEBUG /** Enlarge an array of transitions * @param t the array * @param num size of the array */ void enlarge (const class Transition**& t, unsigned num) { if (!(num & (num + 1))) { const class Transition** u = new const class Transition*[(num + 1) << 1]; memcpy (u, t, sizeof (*t) * num); delete[] t; t = u; } } void Transition::changeParent (const class Transition& old, const class Transition& fused) { assert (old.hasChild (*this)); assert (fused.hasChild (*this)); for (unsigned i = myNumParents; i--; ) { if (myParents[i] == &old) { myParents[i] = &fused; return; } } assert (false); } void Transition::addChild (class Transition& child) { assert (myNet && child.myNet); assert (child.myNet->getParent () == myNet || myNet->getParent () == child.myNet); assert (!child.hasParent (*this)); assert (!hasParent (child)); ::enlarge (myChildren, myNumChildren); myChildren[myNumChildren++] = &child; ::enlarge (child.myParents, child.myNumParents); child.myParents[child.myNumParents++] = this; } void Transition::setAssertion (bool fatal) { delete myOutputVariables; myOutputVariables = 0; while (myNumOutputs) delete myOutputs[--myNumOutputs]; delete[] myOutputs; myOutputs = 0; myKind = fatal ? tFatal : tUndefined; } bool Transition::isHidden (const class Valuation& valuation) const { if (!myHide) return false; if (class Value* v = myHide->eval (valuation)) { assert (v->getKind () == Value::vLeaf); bool hidden = bool (*static_cast(v)); delete v; return hidden; } valuation.clearErrors (); return false; } void Transition::addGate (class Expression& gate) { assert (gate.getType () && gate.getType ()->getKind () == Type::tBool); if (!myGates.empty () && (*myGates.begin ())->getKind () == Expression::eConstant) { // there is a constant gate (which should be always disabled): // ignore subsequent gate definitions #ifndef NDEBUG { const class Expression* g = *myGates.begin (); const class Value& v = static_cast(g)->getValue (); assert (v.getKind () == Value::vLeaf); assert (!bool (static_cast(v))); } #endif // NDEBUG ignore: gate.destroy (); return; } if (!gate.isAtomic () && gate.getKind () == Expression::eBooleanBinop) { class BooleanBinop& b = static_cast(gate); if (b.isConj ()) { addGate (*const_cast(b.getLeft ()).copy ()); addGate (*const_cast(b.getRight ()).copy ()); b.destroy (); return; } } else if (gate.getKind () == Expression::eConstant) { const class Value& v = static_cast(gate).getValue (); assert (v.getKind () == Value::vLeaf); if (bool (static_cast(v))) goto ignore; // the gate is always true; it can be ignored else { // gate is always false; remove other gates for (GateList::iterator g = myGates.begin (); g != myGates.end (); g++) (*g)->destroy (); myGates.clear (); myGates.insert (myGates.end (), &gate); } return; } else if (gate.getKind () == Expression::eUndefined) { setAssertion (static_cast(gate).isFatal ()); goto ignore; } // see if there is such a gate already for (GateList::const_iterator g = myGates.begin (); g != myGates.end (); g++) if (**g == gate) goto ignore; // insert the gate myGates.insert (myGates.end (), &gate); } void Transition::addHide (class Expression& qualifier) { assert (qualifier.isBasic () && !qualifier.isTemporal ()); assert (qualifier.getType () && qualifier.getType ()->getKind () == Type::tBool); // if the transition has been declared always hidden, ignore the qualifier if (myHide && myHide->getKind () == Expression::eConstant) { #ifndef NDEBUG const class Value& v = static_cast(qualifier).getValue (); assert (v.getKind () == Value::vLeaf); assert (bool (static_cast(v))); #endif // NDEBUG qualifier.destroy (); return; } // treat constant qualifiers specially if (qualifier.getKind () == Expression::eConstant) { const class Value& v = static_cast(qualifier).getValue (); assert (v.getKind () == Value::vLeaf); if (!bool (static_cast(v))) qualifier.destroy (); else { myHide->destroy (); myHide = &qualifier; } return; } myHide = myHide ? BooleanBinop::construct (false, *myHide, qualifier) : &qualifier; } unsigned Transition::addFairness (class Expression& qualifier, unsigned number, bool isStrong) { assert (qualifier.isBasic () && !qualifier.isTemporal ()); assert (qualifier.getType () && qualifier.getType ()->getKind () == Type::tBool); unsigned& numFair = isStrong ? myNumStronglyFair : myNumWeaklyFair; if (qualifier.getKind () == Expression::eConstant) { const class Value& v = static_cast(qualifier).getValue (); assert (v.getKind () == Value::vLeaf); if (!bool (static_cast(v))) { qualifier.destroy (); return numFair; } } class Expression**& fc = isStrong ? myStronglyFairCond : myWeaklyFairCond; unsigned*& fs = isStrong ? myStronglyFairSet : myWeaklyFairSet; class Expression** c = new class Expression*[numFair + 1]; memcpy (c, fc, numFair * sizeof *fc); delete[] fc; fc = c; unsigned* s = new unsigned[numFair + 1]; memcpy (s, fs, numFair * sizeof *fs); delete[] fs; fs = s; c[numFair] = &qualifier; s[numFair] = number; return ++numFair; } unsigned Transition::addEnabledness (class Expression& qualifier, unsigned number) { assert (qualifier.isBasic () && !qualifier.isTemporal ()); assert (qualifier.getType () && qualifier.getType ()->getKind () == Type::tBool); if (qualifier.getKind () == Expression::eConstant) { const class Value& v = static_cast(qualifier).getValue (); assert (v.getKind () == Value::vLeaf); if (!bool (static_cast(v))) { qualifier.destroy (); return myNumEnabled; } } class Expression** c = new class Expression*[myNumEnabled + 1]; memcpy (c, myEnabledCond, myNumEnabled * sizeof *myEnabledCond); delete[] myEnabledCond; myEnabledCond = c; unsigned* s = new unsigned[myNumEnabled + 1]; memcpy (s, myEnabledSet, myNumEnabled * sizeof *myEnabledSet); delete[] myEnabledSet; myEnabledSet = s; c[myNumEnabled] = &qualifier; s[myNumEnabled] = number; return ++myNumEnabled; } /** Determine whether a variable occurs in an expression * @param expr a variable in the expression * @param data variable to look for * @return false if the variable was found */ static bool findVariable (const class Expression& expr, void* data) { return expr.getKind () != Expression::eVariable || &static_cast(expr).getVariable () != data; } /** Determine which places are referenced from output arcs * @param expr the literal (Variable or PlaceContents) * @param data set of referenced places (or 0) * @return if data==0 and expr is PlaceContents, false; otherwise true */ static bool findOutput (const class Expression& expr, void* data) { if (expr.getKind () == Expression::ePlaceContents) { if (!data) return false; const class Place& place = static_cast(expr).getPlace (); static_cast(data)->assign (place.getIndex (), true); } return true; } bool Transition::isInput (const class VariableDefinition* variable) const { for (unsigned i = 0; i < myNumInputs; i++) if (!myInputs[i]->getExpr ().forExpressions (&::findVariable, const_cast(variable))) return true; return false; } bool Transition::isOutput (const class VariableDefinition* variable) const { for (unsigned i = 0; i < myNumOutputs; i++) if (!myOutputs[i]->getExpr ().forExpressions (&::findVariable, const_cast(variable))) return true; return false; } bool Transition::isGate (const class VariableDefinition* variable) const { for (GateList::const_iterator i = myGates.begin (); i != myGates.end (); i++) if (!(*i)->forExpressions (&::findVariable, const_cast(variable))) return true; return false; } const class VariableDefinition& Transition::addOutputVariable (const class Type& type, char* name, class Expression* expr) { if (!myOutputVariables) myOutputVariables = new class QuantifierList; if (name) { class VariableDefinition& d = const_cast (*getVariable (name)); assert (&d.getType () == &type && d.isAggregate ()); myOutputVariables->append (*new class Quantifier (d, expr)); return d; } else { for (card_t i = myOutputVariables ? myOutputVariables->size () : 0;; i++) { name = new char[i ? 2 + log16 (i) : 3]; sprintf (name, ":%x", i); if (myVariables.find (name) == myVariables.end ()) break; delete[] name; } } class Quantifier* q = new class Quantifier (name, type, expr); myOutputVariables->append (*q); class VariableDefinition& d = const_cast (q->getVariable ()); assert (myVariables.find (name) == myVariables.end ()); myVariables.insert (VariableMap::value_type (d.getName (), &d)); return d; } const class VariableDefinition& Transition::addVariable (char* name, const class Type& type, bool aggregate, bool hidden) { assert (name && myVariables.find (name) == myVariables.end ()); class VariableDefinition* d = new class VariableDefinition (name, type, aggregate, hidden); myVariables.insert (VariableMap::value_type (d->getName (), d)); return *d; } void Transition::addFunction (class Function& function) { assert (!getFunction (function.getName ())); myFunctions.insert (FunctionMap::value_type (function.getName (), &function)); } bool Transition::checkGates (const class Valuation& valuation, enum Error err) const { for (GateList::const_iterator i = myGates.begin (); i != myGates.end (); i++) { class Value* v = (*i)->eval (valuation); if (!v) { if (valuation.getError () != err) return false; valuation.clearErrors (); continue; } assert (valuation.isOK () && v->getKind () == Value::vLeaf); bool accepted = bool (static_cast(*v)); delete v; if (!accepted) return false; } return true; } void Transition::addArc (class Arc& arc) { if (arc.isOutput ()) { if (myOutputs) { class Arc** a = new class Arc*[myNumOutputs + 1]; memcpy (a, myOutputs, sizeof (*myOutputs) * myNumOutputs); delete[] myOutputs; myOutputs = a; } else { assert (!myNumOutputs); myOutputs = new class Arc*[1]; } myOutputs[myNumOutputs++] = &arc; if (!myOutputMarking && !arc.getExpr ().forExpressions (&::findOutput, 0)) myOutputMarking = true; } else { if (myInputs) { class Arc** a = new class Arc*[myNumInputs + 1]; memcpy (a, myInputs, sizeof (*myInputs) * myNumInputs); delete[] myInputs; myInputs = a; } else { assert (!myNumInputs); myInputs = new class Arc*[1]; } myInputs[myNumInputs++] = &arc; } } class Arc* Transition::getArc (bool output, const class Place& place) { if (output) { for (unsigned i = 0; i < myNumOutputs; i++) if (&myOutputs[i]->getPlace () == &place) return myOutputs[i]; } else { for (unsigned i = 0; i < myNumInputs; i++) if (&myInputs[i]->getPlace () == &place) return myInputs[i]; } return NULL; } /** restore heap order to arrays being sorted * @param keys the keys * @param values values associated with the keys * @param size number of elements in the arrays * @param depth depth below which the heap order is to be restored */ static void heapify (unsigned* keys, unsigned* values, unsigned size, unsigned depth) { unsigned largest = depth, l; for (;;) { l = largest << 1; assert (keys && values && depth < size); if (++l >= size) return; if (keys[l] > keys[depth]) { largest = l; if (++l < size && keys[l] > keys[depth]) largest = l; } else if (++l < size && keys[l] > keys[depth]) largest = l; else return; l = keys[largest], keys[largest] = keys[depth], keys[depth] = l; l = values[largest], values[largest] = values[depth], values[depth] = l; depth = largest; } } bool Transition::addConstant (char* name, class Constant& constant) { assert (name && constant.getType () && !constant.getType ()->isLeaf ()); for (unsigned i = myNumConstants; i--; ) if (!strcmp (name, myConstantNames[i])) return false; if (!(myNumConstants & (myNumConstants + 1))) { char** constantNames = new char*[(myNumConstants + 1) << 1]; memcpy (constantNames, myConstantNames, myNumConstants * sizeof *myConstantNames); delete[] myConstantNames; myConstantNames = constantNames; class Constant** constants = new class Constant*[(myNumConstants + 1) << 1]; memcpy (constants, myConstants, myNumConstants * sizeof *myConstants); delete[] myConstants; myConstants = constants; } myConstantNames[myNumConstants] = name; myConstants[myNumConstants++] = &constant; return true; } const class Constant* Transition::getConstant (const char* name) const { for (unsigned i = myNumConstants; i--; ) if (!strcmp (name, myConstantNames[i])) return myConstants[i]; return 0; } bool Transition::fuse (const class Transition& callee, const class Printer& printer, bool warn) { /** the return status */ bool ok = true; assert (myNet && callee.myNet); assert (callee.myNet == myNet || callee.myNet == myNet->getParent () || callee.myNet->getParent () == myNet); // if the callee is a synchronisation label, register the caller with it if (callee.myNet == myNet->getParent ()) { for (unsigned i = callee.myNumChildren; i--; ) { if (callee.myChildren[i]->myNet == myNet) { printer.printRaw ("transition "); printer.printQuoted (callee.myChildren[i]->myName); printer.printRaw (" already synchronises on "); printer.delimiter (':'); printer.printQuoted (callee.myName); printer.finish (); ok = false; break; } } const_cast(callee).addChild (*this); } /** variable substitutions */ class Substitution substitution; // fuse the variables for (VariableMap::const_iterator i = callee.myVariables.begin (); i != callee.myVariables.end (); i++) { const class VariableDefinition& var = *i->second; if (class Function* func = getFunction (var.getName ())) { if (!func->getArity ()) { if (func->getExpr ().getType () != &var.getType ()) { printer.printRaw ("type mismatch for variable "); printer.printQuoted (var.getName ()); printer.finish (); ok = false; } else if (var.isAggregate ()) { if (warn) { printer.printRaw ("Warning:callee output variable "); printer.printQuoted (var.getName ()); printer.printRaw (" shadows a nullary function"); printer.finish (); } } else substitution.setExpr (var, *const_cast (func->getExpr ()).cse ()->copy ()); continue; } if (warn) { printer.printRaw ("Warning:callee variable "); printer.printQuoted (var.getName ()); printer.printRaw (" shadows a non-nullary function"); printer.finish (); } } if (const class Constant* c = getConstant (var.getName ())) { substitution.setExpr (var, *const_cast(c)->copy ()); continue; } iterator j = myVariables.find (i->first); if (j != myVariables.end ()) { const class VariableDefinition& v = *j->second; if (v.isAggregate () || var.isAggregate ()) { printer.printRaw ("redefinition of output variable "); printer.printQuoted (var.getName ()); printer.finish (); ok = false; } else if (&v.getType () != &var.getType ()) { printer.printRaw ("type mismatch for variable "); printer.printQuoted (var.getName ()); printer.finish (); ok = false; } else substitution.setExpr (var, *(new class Variable (v))->cse ()); } else if (ok && !var.isAggregate ()) { // introduce a new variable class VariableDefinition& v = *new class VariableDefinition (var); myVariables.insert (VariableMap::value_type (v.getName (), &v)); substitution.setExpr (var, *(new class Variable (v))->cse ()); } } // fuse the output variables if (callee.myOutputVariables) { for (QuantifierList::const_iterator q = callee.myOutputVariables->begin (); q != callee.myOutputVariables->end (); q++) { const class VariableDefinition& var = (*q)->getVariable (); class Expression* cond = const_cast((*q)->getCondition ()); substitution.setExpr (var, *(new class Variable (addOutputVariable (var.getType (), 0, cond ? cond->substitute (substitution) : 0)))->cse ()); if (!warn); else if (getConstant (var.getName ())) { printer.printRaw ("Warning:callee output variable "); printer.printQuoted (var.getName ()); printer.printRaw (" shadows a constant"); printer.finish (); } else if (getFunction (var.getName ())) { printer.printRaw ("Warning:callee output variable "); printer.printQuoted (var.getName ()); printer.printRaw (" shadows a function"); printer.finish (); } } } // fuse the gates if (ok) for (GateList::const_iterator g = callee.myGates.begin (); g != callee.myGates.end (); g++) addGate (*(*g)->substitute (substitution)); // fuse the functions for (FunctionMap::const_iterator f = callee.myFunctions.begin (); f != callee.myFunctions.end (); f++) { if (myFunctions.find (f->first) != myFunctions.end ()) { if (f->second->isCopy () && callee.myNet->getParent () == myNet) { /* * We are constructing a fused synchronisation transition here, * by fusing together each synchronising transitions * (the parameter "callee") in child nets. * * This function definition has been copied to the callee from * a synchronisation label. Thus, it will be copied to this * transition from some other source, and it must not be copied * here again. * * This modification was suggested by Charles Lakos. */ continue; } printer.printRaw ("redefinition of function "); printer.printQuoted (f->first); printer.finish (); ok = false; } else if (ok) { const class Function& func = *f->second; unsigned i = func.getArity (); char* name = newString (func.getName ()); class VariableDefinition** params = i ? new class VariableDefinition*[i] : 0; if (const class VariableDefinition* v = i ? 0 : getVariable (name)) { if (v->isAggregate ()) { printer.printRaw ("Warning:nullary callee function "); printer.printQuoted (name); printer.printRaw (" shadows an output variable"); printer.finish (); } else if (&v->getType () != func.getExpr ().getType ()) { printer.printRaw ("type mismatch for variable and nullary function "); printer.printQuoted (name); printer.finish (); ok = false; } else { substitution.setExpr (*v, *const_cast (func.getExpr ()).cse ()->copy ()); iterator v = myVariables.find (name); assert (v != myVariables.end ()); delete v->second; myVariables.erase (v); } } if (warn && !i && getConstant (name)) { printer.printRaw ("Warning:nullary callee function "); printer.printQuoted (name); printer.printRaw (" shadows a constant"); printer.finish (); } while (i--) substitution.setExpr (func[i], *(new class Variable (*(params[i] = new class VariableDefinition (func[i]))))->cse ()); myFunctions.insert (FunctionMap::value_type (name, new class Function (name, func.getArity (), params, const_cast (func.getExpr ()).substitute (substitution), true))); } } // fuse the constants unsigned k; for (k = callee.myNumConstants; k--; ) { const char* name = callee.myConstantNames[k]; class Constant& cc = *const_cast(callee.myConstants[k]); if (const class Constant* c = getConstant (name)) { if (*c == cc) continue; printer.printRaw ("redefinition of constant "); printer.printQuoted (name); printer.finish (); ok = false; } else if (ok) { if (warn && getVariable (name)) { printer.printRaw ("Warning:callee constant "); printer.printQuoted (name); printer.printRaw (" shadows a variable"); printer.finish (); } addConstant (newString (name), *static_cast(cc.copy ())); } } // substitute replaced variables in constraints, gates, functions and arcs if (ok) { for (k = myNumWeaklyFair; k--; ) { class Expression* e = myWeaklyFairCond[k]->substitute (substitution); myWeaklyFairCond[k]->destroy (); myWeaklyFairCond[k] = e; } for (k = myNumStronglyFair; k--; ) { class Expression* e = myStronglyFairCond[k]->substitute (substitution); myStronglyFairCond[k]->destroy (); myStronglyFairCond[k] = e; } for (k = myNumEnabled; k--; ) { class Expression* e = myEnabledCond[k]->substitute (substitution); myEnabledCond[k]->destroy (); myEnabledCond[k] = e; } for (GateList::iterator g = myGates.begin (); g != myGates.end (); g++) { class Expression* e = (*g)->substitute (substitution); (*g)->destroy (); *g = e; } for (FunctionMap::iterator f = myFunctions.begin (); f != myFunctions.end (); f++) f->second->substitute (substitution); for (k = myNumInputs; k--; ) myInputs[k]->substitute (substitution); for (k = myNumOutputs; k--; ) myOutputs[k]->substitute (substitution); } // fuse the fairness and enabledness constraints for (k = callee.myNumWeaklyFair; k--; ) { if (!myNet->addConstraint (*const_cast (callee.myWeaklyFairCond[k])->substitute (substitution), *this, Net::Weak)) { printer.printRaw ("unable to fuse `weakly_fair' constraint"); printer.finish (); ok = false; } } for (k = callee.myNumStronglyFair; k--; ) { if (!myNet->addConstraint (*const_cast (callee.myStronglyFairCond[k])->substitute (substitution), *this, Net::Strong)) { printer.printRaw ("unable to fuse `strongly_fair' constraint"); printer.finish (); ok = false; } } for (k = callee.myNumEnabled; k--; ) { if (!myNet->addConstraint (*const_cast (callee.myEnabledCond[k])->substitute (substitution), *this, Net::Enabled)) { printer.printRaw ("unable to fuse `enabled' constraint"); printer.finish (); ok = false; } } if (ok) { // fuse the inputs for (k = callee.myNumInputs; k--; ) { const class Arc& arc = *callee.myInputs[k]; if (callee.myNet->getParent () == myNet && arc.isCopy () && getArc (false, arc.getPlace ())) { /* * We are constructing a fused synchronisation transition here, * by fusing together each synchronising transitions * (the parameter "callee") in child nets. * * This input arc has been copied to the callee from a * synchronisation label. Thus, it will be copied to this * transition from some other source, and it must not be copied * here again. * * This modification was suggested by Charles Lakos. */ continue; } addArc (*new class Arc (false, *static_cast (const_cast (arc.getExpr ()).substitute (substitution)), arc.getPlace (), true)); } // fuse the assertion status if (callee.myKind > myKind) myKind = callee.myKind; // fuse the outputs only for non-assertion transitions if (!myKind) { for (k = callee.myNumOutputs; k--; ) { const class Arc& arc = *callee.myOutputs[k]; if (callee.myNet->getParent () == myNet && arc.isCopy () && getArc (true, arc.getPlace ())) continue; // see the comment on input arcs, above addArc (*new class Arc (true, *static_cast (const_cast (arc.getExpr ()).substitute (substitution)), arc.getPlace (), true)); } } if (callee.myOutputMarking) myOutputMarking = true; if (!myPriority) myPriority = callee.myPriority; } return ok; } bool Transition::isUnifiable (enum Unif action, const class Printer& printer) { struct unif* u; for (; (u = myUnif); myUnif = u) { // clean up a previous definition u = u->next; delete myUnif->vars; delete myUnif; } // construct the unification list with a depth-first search algorithm: // do // take all arcs that can be fully evaluated // (sorted in ascending order of maximum size of associated markings) // pick an arc that can unify currently unbound variables // and extend the set of unified variables // until all input arcs have been processed // // Primary cost function: // cost1[arc] = 0 if the arc contains unifiable variables, or // cost1[arc] = number of preceding arcs containing unifiable variables // total cost: sum over cost1[] for all arcs // // Secondary cost function (applied when the primary one yields a tie): // cost2[arc] = maximum number of iterations for the arc // total cost: cost2[0] * (1 + cost2[1] * (1 + (...))) /** number of split input arcs */ unsigned numInputs; unsigned input; for (numInputs = input = 0; input < myNumInputs; input++) for (const class Marking* m = myInputs[input]->getExpr ().first (); m; m = m->next (), numInputs++); assert (numInputs >= myNumInputs); /** best primary cost found so far */ unsigned* best1 = numInputs ? new unsigned[numInputs] : 0; /** primary cost of the combination being considered */ unsigned* cost1 = numInputs ? new unsigned[numInputs] : 0; /** best secondary cost found so far */ card_t* best2 = numInputs ? new card_t[numInputs] : 0; /** secondary cost of the combination being considered */ card_t* cost2 = numInputs ? new card_t[numInputs] : 0; /** the split input arcs */ const class Marking** arcs = new const class Marking*[numInputs]; /** split arcs whose multiplicity depends on variables */ class BitVector varMult (numInputs); /** best combination found so far */ unsigned* best = numInputs ? new unsigned[numInputs] : 0; /** combination being considered */ unsigned* comb = numInputs ? new unsigned[numInputs] : 0; /** number of variable-multiplicity unifiers in the best combination */ unsigned bestvar = UINT_MAX; /** number of variable-multiplicity unifiers in current combination */ unsigned combvar = 0; /** variable sets unified from each arc in the best solution */ class VariableSet** varb = numInputs ? new class VariableSet*[numInputs] : 0; /** variable sets unified from each arc in current combination */ class VariableSet** varc = numInputs ? new class VariableSet*[numInputs] : 0; // initialize the costs for (input = numInputs; input--; ) { best1[input] = UINT_MAX, best2[input] = CARD_T_MAX; varb[input] = varc[input] = 0; } // initialize the split input arcs for (numInputs = input = 0; input < myNumInputs; input++) for (const class Marking* m = myInputs[input]->getExpr ().first (); m; m = m->next (), numInputs++) if ((arcs[numInputs] = m)->hasVariableMultiplicity ()) varMult.assign (numInputs, true); /** all variables that could be unified */ class VariableSet vars; /** all variables that can definitely be unified */ class VariableSet allVars; for (input = 0;;) { unsigned i, j; if (input < numInputs) { // see if there are any constant arcs for (i = numInputs; i--; ) { // skip already processed arc expressions for (j = input; j--; ) if (comb[j] == i) goto skipConstant; if (arcs[i]->depends (allVars, true)) { skipConstant: continue; } // calculate the cost functions cost1[input] = 0; for (j = input; j--; ) if (varc[j]) cost1[input]++; cost2[input] = 1; varc[input] = 0; comb[input++] = i; } } if (input == numInputs) { // solution completed assert (bestvar >= combvar); if (bestvar > combvar) { bestvar = combvar; goto better; } for (input = numInputs, i = 0, j = 0; input--; ) i += best1[input], j += cost1[input]; if (i < j) goto worse; else if (i == j) { /** total secondary costs */ card_t b = 0, c = 0; for (input = numInputs; input--; ) { if (b < CARD_T_MAX) { if (b && best2[input] < CARD_T_MAX / b) b *= best2[input]; if (b < CARD_T_MAX) b++; } if (c < CARD_T_MAX) { if (c && cost2[input] < CARD_T_MAX / c) c *= cost2[input]; if (c < CARD_T_MAX) c++; } } if (c > b) goto worse; } better: memcpy (best1, cost1, numInputs * sizeof *best1); memcpy (best2, cost2, numInputs * sizeof *best2); memcpy (best, comb, numInputs * sizeof *best); // copy the variable sets and count them for (input = numInputs, i = 0; input--; ) { delete varb[input]; if ((varb[input] = varc[input])) varb[input] = new class VariableSet (*varb[input]), i++; } if (i > 5) { // more than 5 arcs with unifiable variables: // give up after the first solution // to avoid a combinatorial explosion for (input = numInputs; input--; ) { delete varc[input]; varc[input] = 0; } goto finish; } worse: // backtrack to the last arc with unifiable variables for (input = numInputs; input--; ) if (varc[input]) break; if (!(input + 1)) { // no variables (only constant arcs) assert (vars.empty () && allVars.empty ()); goto finish; } vars.clear (); allVars.clear (); if (varMult[comb[input]]) { assert (combvar >= varc[input]->size ()); combvar -= varc[input]->size (); } delete varc[input]; varc[input] = 0; for (i = 0; i < input; i++) { if (varc[i]) { for (VariableSet::const_iterator v = varc[i]->begin (); v != varc[i]->end (); v++) { const class VariableDefinition& var = **v; assert (!allVars.contains (var)); vars.insert (var); if (!varMult[comb[i]]) allVars.insert (var); } } } i = comb[input]; } else i = numInputs; nextUnifier: // see if there are arcs from which variables can be unified while (i--) { // skip already processed arc expressions for (j = input; j--; ) if (comb[j] == i) goto skipVar; // skip arcs whose multiplicity cannot be evaluated for (const class Marking* mp = arcs[i]; mp; mp = mp->getParent ()) if (const class Expression* mult = mp->getMultiplicity ()) if (mult->depends (allVars, true)) goto skipVar; arcs[i]->getToken ()->getLvalues (allVars, varc[input]); if (!varc[input]) { skipVar: continue; } // calculate the cost functions cost1[input] = 0; cost2[input] = arcs[i]->getType ()->getNumValues (); if (cost2[input] > arcs[i]->getPlace ()->getMaxNumTokens ()) cost2[input] = arcs[i]->getPlace ()->getMaxNumTokens (); comb[input] = i; if (varMult[i]) { if ((combvar += varc[input]->size ()) > bestvar) { combvar -= varc[input]->size (); continue; } } for (VariableSet::const_iterator v = varc[input]->begin (); v != varc[input]->end (); v++) { const class VariableDefinition& var = **v; assert (!allVars.contains (var)); vars.insert (var); if (!varMult[i]) allVars.insert (var); } goto nextArc; } // no unifiable variables found: backtrack while (input--) { if (!varc[input]) continue; vars.clear (); allVars.clear (); if (varMult[comb[input]]) { assert (combvar >= varc[input]->size ()); combvar -= varc[input]->size (); } delete varc[input]; varc[input] = 0; for (i = 0; i < input; i++) { if (varc[i]) { for (VariableSet::const_iterator v = varc[i]->begin (); v != varc[i]->end (); v++) { const class VariableDefinition& var = **v; assert (!allVars.contains (var)); vars.insert (var); if (!varMult[comb[i]]) allVars.insert (var); } } } i = comb[input]; goto nextUnifier; } // out of solutions finish: break; nextArc: input++; continue; } assert (!myUnif); /** flag: is everything ok? */ bool ok = bestvar < UINT_MAX; if (ok) { // sort contiguous sequences of constant arcs in ascending order of // place size for (input = numInputs; input--; ) { if (varb[input]) continue; unsigned i = input; while (i--) { if (varb[i]) break; assert (best2[i] == 1); best2[i] = arcs[best[i]]->getType ()->getNumValues (); if (best2[i] > arcs[best[i]]->getPlace ()->getMaxNumTokens ()) best2[i] = arcs[best[i]]->getPlace ()->getMaxNumTokens (); } if (++i == input) continue; unsigned j = input + 1 - i, k = j / 2; while (k--) ::heapify (best2 + i, best + i, j, k); while (j-- > 1) { k = best2[i], best2[i] = best2[i + j], best2[i + j] = k; k = best[i], best[i] = best[i + j], best[i + j] = k; ::heapify (best2 + i, best + i, j, 0); } input = i; } // check that all input variables could be unified vars.clear (); for (input = numInputs; input--; ) { if (varb[input]) { for (VariableSet::const_iterator v = varb[input]->begin (); v != varb[input]->end (); v++) { const class VariableDefinition& var = **v; vars.insert (var); if (varMult[comb[input]]) const_cast(var).flagUndefined (); } } } // see that all variables of the transition can be unified for (const_iterator vd = begin (); vd != end (); vd++) { const class VariableDefinition& var = *vd->second; if (!var.isAggregate () && !vars.contains (var)) { switch (action) { case uNormal: break; case uRemove: // remove those gates that the variable depends on for (GateList::iterator i = myGates.begin (), j = i; i != myGates.end (); i = j) if (!(*j++)->forExpressions (&::findVariable, const_cast(&var))) (*i)->destroy (), myGates.erase (i); // fall through case uIgnore: if (!isInput (&var)) continue; } printer.printRaw ("variable "); printer.print (var.getName ()); printer.printRaw (" cannot be unified"); printer.finish (); ok = false; } } if (ok) { // construct myUnif for (input = numInputs; input--; ) { u = new struct unif; u->next = myUnif; u->vars = varb[input], varb[input] = 0; u->m = arcs[best[input]]; u->isSet = u->m->getToken ()->isSet (); u->varMult = varMult[best[input]]; u->place = u->m->getPlace ()->getIndex (); assert (!u->isSet || !u->vars); myUnif = u; } } } delete[] best1; delete[] cost1; delete[] best2; delete[] cost2; delete[] comb; delete[] best; delete[] arcs; for (input = numInputs; input--; ) { delete varb[input]; delete varc[input]; } delete[] varb; delete[] varc; // child transitions are not assertions; their parents are if (ok && action == uRemove) myKind = tNormal; return ok; } void Transition::analyze (class GlobalMarking& m, class StateReporter& reporter) const { if (!myGates.empty () && (*myGates.begin ())->getKind () == Expression::eConstant) { // there is a constant gate (which should be always disabled): // ignore the transition #ifndef NDEBUG const class Expression* g = *myGates.begin (); const class Value& v = static_cast(g)->getValue (); assert (v.getKind () == Value::vLeaf); assert (!bool (static_cast(v))); #endif // NDEBUG return; } class Valuation valuation; const struct unif* u = myUnif; /** processed tokens */ class TokenList tokens; for (class Token* token = 0;;) { assert (valuation.isOK ()); // get next input arc inscription (abstract token) to be unified if (u) { // have all arc inscriptions been processed? // evaluate the multiplicity of the token if (card_t mult = u->m->getMultiplicity (valuation)) { assert (valuation.isOK ()); class PlaceMarking& pm = m[u->place]; token = !u->isSet && pm.empty () ? 0 : new class Token (mult, pm, *u); } else if (valuation.isOK ()) { // zero multiplicity => skip the token u = u->next; continue; } else goto unifError; if (token) { if (!u->vars) { // Any variables in the token have been unified before. // Evaluate the token and see if it is present in the input place. if (token->isBindable (valuation)) { // reserve the token and advance to the next one bindToken: assert (valuation.isOK ()); token->reserve (); tokens.push (*token); token = 0; u = u->next; continue; } delete token; if (!valuation.isOK ()) { // report unification error and backtrack unifError: willDo (false, *this, valuation, m, reporter, "unification:"); } } else { // some variables must be unified from the token if (u->varMult) token->addUnified (valuation); for (;;) { #ifndef NDEBUG token->assertUndefined (valuation); #endif // NDEBUG if (!token->getConcrete ()); else if (willDo (token->isCompatible (valuation), *this, valuation, m, reporter)) { u->m->getToken ()->getLvalues (token->getValue (), valuation, *u->vars); #ifndef NDEBUG token->assertDefined (valuation); #endif // NDEBUG if (willDo (checkGates (valuation) && token->isCompatible (valuation) && tokens.isCompatible (valuation), *this, valuation, m, reporter)) goto bindToken; incompatible: token->undefine (valuation); goto incompatible2; } else { incompatible2: if (interrupted || reporter.isFatal ()) { delete token; goto cleanup; } if (token->next ()) continue; } delete token; break; } } } } // everything unified => try to fire the transition else if (myKind) { // an assertion transition is enabled valuation.flagUndefined (myKind == tFatal); reporter.reject (*this, valuation, m, "undefined gate", 0); cleanup: // clean up the unification stack and return while (!tokens.empty ()) { if ((token = &tokens.pop ())->isReserved ()) { token->free (); delete token; } } return; } else if (!willDo (true, *this, valuation, m, reporter, checkGates (valuation, errNone) ? 0 : "undefined gate:")); else if (myNumParents) reporter.reportSync (*this); else if (firstOutput (*this, valuation, m, reporter)) { /** tokens removed from the input places */ class GlobalMarking* inputs = 0; if (myOutputMarking) { inputs = new class GlobalMarking (reporter.net); for (TokenList::const_iterator t = tokens.begin (); t != tokens.end (); t++) { const struct unif& unif = (*t)->getUnifier (); class PlaceMarking& pm = (*inputs)[unif.place]; if (!(*t)->copyRemoved (pm)) assert (false); } } valuation.setGlobalMarking (inputs); // Fire the transition for all allowed bindings of output variables do { /** Placeholder for the successor state */ class GlobalMarking successor (m); // Evaluate the output arcs and add the resulting state fireOutputs (*this, valuation, successor, reporter); } while (!interrupted && !reporter.isFatal () && nextOutput (*this, valuation, m, reporter)); valuation.setGlobalMarking (0); delete inputs; } // Backtrack in the search while (!tokens.empty ()) { token = &tokens.pop (); // Restore the reserved token to the input place if (token->isReserved ()) token->free (); // If the token is "constant", backtrack further if (!(u = &token->getUnifier ())->vars) { delete token; continue; } goto incompatible; } break; } } void Transition::report (const class Valuation& valuation, const class GlobalMarking& marking, const char* reason, const class Place* place, const class Printer& printer) const { if (myName) printer.printQuoted (myName); else printer.printRaw ("(anonymous)"); printer.delimiter (':'); if (place) { printer.printRaw ("integrity violation for "); printer.printQuoted (place->getName ()); } else printer.printRaw (reason ? reason : "rejected successor state"); printer.linebreak (); valuation.display (printer); printer.finish (); marking.display (printer); printer.finish (); } void Transition::displayEdge (const class Valuation& valuation, const class GlobalMarking& marking, const class Printer& printer) const { printer.printRaw ("transition "); printer.print (myName); printer.printRaw ("->"); marking.display (printer); printer.finish (); valuation.display (printer); printer.finish (); } void Transition::unfold (class GlobalMarking& cover, class LNet& lnet, class DummyReporter& reporter) const { assert (&lnet.getNet ().getTransition (myRootIndex) == this); if (myKind) return; // this is a "fact" transition (an assertion) if (!myGates.empty () && (*myGates.begin ())->getKind () == Expression::eConstant) { // there is a constant gate (which should be always disabled): // ignore the transition #ifndef NDEBUG const class Expression* g = *myGates.begin (); const class Value& v = static_cast(g)->getValue (); assert (v.getKind () == Value::vLeaf); assert (!bool (static_cast(v))); #endif // NDEBUG return; } class Valuation valuation; const struct unif* u = myUnif; /** the input marking */ class GlobalMarking& m (cover); /** processed tokens */ class TokenList tokens; lnet.removeTransitions (myRootIndex); for (class Token* token = 0;;) { assert (valuation.isOK ()); // get next input arc inscription (abstract token) to be unified if (u) { // have all arc inscriptions been processed? // evaluate the multiplicity of the token if (card_t mult = u->m->getMultiplicity (valuation)) { assert (valuation.isOK ()); class PlaceMarking& pm = m[u->place]; token = !u->isSet && pm.empty () ? 0 : new class Token (mult, pm, *u); } else if (valuation.isOK ()) { // zero multiplicity => skip the token u = u->next; continue; } else goto unifError; if (token) { if (!u->vars) { // Any variables in the token have been unified before. // Evaluate the token and see if it is present in the input place. if (token->isBindableUnfold (valuation)) { // reserve the token and advance to the next one bindToken: assert (valuation.isOK ()); token->setReservedUnfold (true); tokens.push (*token); token = 0; u = u->next; continue; } delete token; if (!valuation.isOK ()) { // report unification error and backtrack unifError: willDo (false, *this, valuation, m, reporter, "unification:"); } } else { // some variables must be unified from the token if (u->varMult) token->addUnified (valuation); for (;;) { #ifndef NDEBUG token->assertUndefined (valuation); #endif // NDEBUG if (!token->getConcreteUnfold ()); else if (willDo (token->isCompatible (valuation), *this, valuation, m, reporter)) { u->m->getToken ()->getLvalues (token->getValue (), valuation, *u->vars); #ifndef NDEBUG token->assertDefined (valuation); #endif // NDEBUG if (willDo (checkGates (valuation) && token->isCompatible (valuation) && tokens.isCompatible (valuation), *this, valuation, m, reporter)) goto bindToken; incompatible: token->undefine (valuation); goto incompatible2; } else { incompatible2: if (interrupted || reporter.isFatal ()) return; if (token->next ()) continue; } delete token; break; } } } } // everything unified => try to fire the transition else if (willDo (true, *this, valuation, m, reporter, checkGates (valuation, errNone) ? 0 : "undefined gate:") && firstOutput (*this, valuation, m, reporter)) { /** tokens removed from the input places */ class GlobalMarking inputs (lnet.getNet ()); for (TokenList::const_iterator t = tokens.begin (); t != tokens.end (); t++) { const struct unif& unif = (*t)->getUnifier (); class PlaceMarking& pm = inputs[unif.place]; if (!(*t)->copyRemoved (pm)) { willDo (false, *this, valuation, m, reporter, "input multiplicity overflow:"); goto skip; } } valuation.setGlobalMarking (&inputs); // Fire the transition for all allowed bindings of output variables do { /** tokens added to the output places */ class GlobalMarking outputs (lnet.getNet ()); for (unsigned out = 0; out < myNumOutputs; out++) { const class Arc& arc = *myOutputs[out]; class PlaceMarking& place = outputs[reporter.isFlattened () ? arc.getPlace ().getIndex () : arc.getIndex ()]; if (!arc.getExpr ().add (place, 1, valuation)) { willDo (false, *this, valuation, m, reporter, "evaluating outputs:"); goto skip; } } struct LNet::ltrans tr; tr.t = myRootIndex; class BitPacker buf; lnet.getNet ().encode (buf, *this, valuation, true); tr.data = const_cast(buf.getBuf ()); tr.datalen = buf.getNumWords (); if (!tr.in.unfold (lnet, inputs) || !tr.out.unfold (lnet, outputs) || !lnet.addTransition (tr)) willDo (false, *this, valuation, m, reporter, "unfolding:"); for (unsigned i = outputs.getSize (); i--; ) { if (outputs[i].getPlace ()->isConstant () && !(outputs[i] == inputs[i])) willDo (false, *this, valuation, m, reporter, "non-constant place:"); cover[i].setUnion (outputs[i]); } } while (!interrupted && !reporter.isFatal () && nextOutput (*this, valuation, m, reporter)); skip: valuation.setGlobalMarking (0); } // Backtrack in the search while (!tokens.empty ()) { token = &tokens.pop (); token->setReservedUnfold (false); // Restore the reserved token to the input place if (token->isReserved ()) token->free (); // If the token is "constant", backtrack further if (!(u = &token->getUnifier ())->vars) { delete token; continue; } goto incompatible; } break; } } /** Determine whether a variable is first unified from the specified token * @param u head of the token list * @param v limit for the search * @param var variable to be examined * @return false if the variable is unified from a token before v */ inline static bool isFirst (const struct unif* u, const struct unif* v, const class VariableDefinition& var) { for (; u != v; u = u->next) if (u->varMult && u->vars && u->vars->contains (var)) return false; return true; } void Transition::unfold (class LNet& lnet, class DummyReporter& reporter) const { assert (&lnet.getNet ().getTransition (myRootIndex) == this); if (myKind) return; // this is a "fact" transition (an assertion) if (!myGates.empty () && (*myGates.begin ())->getKind () == Expression::eConstant) { // there is a constant gate (which should be always disabled): // ignore the transition #ifndef NDEBUG const class Expression* g = *myGates.begin (); const class Value& v = static_cast(g)->getValue (); assert (v.getKind () == Value::vLeaf); assert (!bool (static_cast(v))); #endif // NDEBUG return; } class Valuation valuation; const struct unif* u = myUnif, *v; VariableSet::const_iterator vi; /** Dummy empty marking for diagnostics */ const class GlobalMarking m (reporter.net); while (!interrupted && !reporter.isFatal ()) { assert (valuation.isOK ()); if (!u) { if (willDo (true, *this, valuation, m, reporter, checkGates (valuation, errNone) ? 0 : "undefined gate:") && firstOutput (*this, valuation, m, reporter)) { /** tokens removed from the input places */ class GlobalMarking inputs (lnet.getNet ()); /** transition variable iterator */ const_iterator i; // clear the "referenced" flags of all variables */ for (i = myVariables.begin (); i != myVariables.end (); i++) i->second->flagReferenced (false); // evaluate the input arcs for (unsigned in = 0; in < myNumInputs; in++) { const class Arc& arc = *myInputs[in]; class PlaceMarking& place = inputs[reporter.isFlattened () ? arc.getPlace ().getIndex () : arc.getIndex ()]; if (!arc.getExpr ().add (place, 1, valuation)) { if (valuation.getError () != errVar) willDo (false, *this, valuation, inputs, reporter, "evaluating inputs:"); goto cont; } } assert (valuation.isOK ()); // check the "referenced" flags of the input variables for (i = myVariables.begin (); i != myVariables.end (); i++) { const class VariableDefinition& var = *i->second; if (var.isReferenced () || var.isAggregate () || !valuation.getValue (var)) continue; assert (var.isUndefined ()); // An input variable is defined, even though it needn't be. // Thus, this is a redundant instance: backtrack goto cont; } // evaluate the output arcs valuation.setGlobalMarking (&inputs); do { /** tokens added to the output places */ class GlobalMarking outputs (lnet.getNet ()); for (unsigned out = 0; out < myNumOutputs; out++) { const class Arc& arc = *myOutputs[out]; class PlaceMarking& place = outputs[reporter.isFlattened () ? arc.getPlace ().getIndex () : arc.getIndex ()]; if (!arc.getExpr ().add (place, 1, valuation)) { willDo (false, *this, valuation, inputs, reporter, "evaluating outputs:"); goto cont; } } struct LNet::ltrans tr; tr.t = myRootIndex; class BitPacker buf; lnet.getNet ().encode (buf, *this, valuation, true); tr.data = const_cast(buf.getBuf ()); tr.datalen = buf.getNumWords (); if (!tr.in.unfold (lnet, inputs) || !tr.out.unfold (lnet, outputs) || !lnet.addTransition (tr)) willDo (false, *this, valuation, inputs, reporter, "unfolding:"); for (unsigned o = outputs.getSize (); o--; ) { if (outputs[o].getPlace ()->isConstant () && !(outputs[o] == inputs[o])) willDo (false, *this, valuation, inputs, reporter, "non-constant place:"); } } while (!interrupted && !reporter.isFatal () && nextOutput (*this, valuation, inputs, reporter)); valuation.setGlobalMarking (0); } cont: #ifndef NDEBUG for (v = u; v; v = v->next) if (v->vars) for (vi = v->vars->begin (); vi != v->vars->end (); vi++) assert ((v->varMult && !::isFirst (myUnif, u, **vi)) || !valuation.getValue (**vi)); #endif // NDEBUG const struct unif* w = 0; for (v = myUnif; v != u; v = v->next) if (v->vars) w = v; if (!(u = w)) return; goto unify; } if ((u->varMult && !u->m->getMultiplicity (valuation)) || !u->vars) { if (valuation.isOK ()) goto next; if (valuation.getError () == errVar) { valuation.clearErrors (); goto cont; } } if (valuation.isOK ()) { if (u->varMult) { for (vi = u->vars->begin (); vi != u->vars->end (); vi++) if (!valuation.getValue (**vi) && !::isFirst (myUnif, u, **vi)) goto cont; } else { for (vi = u->vars->begin (); vi != u->vars->end (); vi++) { assert (!valuation.getValue (**vi)); valuation.setValue (**vi, (*vi)->getType ().getFirstValue ()); } } proceed: if (willDo (checkGates (valuation), *this, valuation, m, reporter)) goto next; unify: if (u->varMult) { for (vi = u->vars->begin (); vi != u->vars->end (); vi++) { const class VariableDefinition& var = **vi; if (!::isFirst (myUnif, u, var)) continue; if (!valuation.getValue (var)) { valuation.setValue (var, var.getType ().getFirstValue ()); goto proceed; } if (valuation.increment (var)) goto proceed; valuation.undefine (var); } for (vi = u->vars->begin (); vi != u->vars->end (); vi++) if (::isFirst (myUnif, u->next, **vi)) valuation.undefine (**vi); } else { for (vi = u->vars->begin (); vi != u->vars->end (); vi++) if (valuation.increment (**vi)) goto proceed; for (vi = u->vars->begin (); vi != u->vars->end (); vi++) valuation.undefine (**vi); } } else willDo (false, *this, valuation, m, reporter, "undefined multiplicity:"); goto cont; next: u = u->next; continue; } } void Transition::computeWeaklyFair (const class Valuation& valuation, unsigned* sets) const { assert (valuation.isOK ()); assert (!!sets); *sets = 0; if (myNumWeaklyFair) { for (unsigned i = myNumWeaklyFair; i--; ) { if (class Value* value = myWeaklyFairCond[i]->eval (valuation)) { assert (value->getKind () == Value::vLeaf); if (bool (static_cast(*value))) sets[++(*sets)] = myWeaklyFairSet[i]; delete value; } else { assert (!valuation.isOK ()); return; } } } } void Transition::computeStronglyFair (const class Valuation& valuation, unsigned* sets) const { assert (valuation.isOK ()); assert (!!sets); *sets = 0; if (myNumStronglyFair) { for (unsigned i = myNumStronglyFair; i--; ) { if (class Value* value = myStronglyFairCond[i]->eval (valuation)) { assert (value->getKind () == Value::vLeaf); if (bool (static_cast(*value))) sets[++(*sets)] = myStronglyFairSet[i]; delete value; } else { assert (!valuation.isOK ()); return; } } } } void Transition::logEnabled (const class Valuation& valuation, char* log) const { assert (valuation.isOK () && log); if (!myName) return; for (unsigned i = myNumEnabled; i--; ) { if (log[myEnabledSet[i]]); else if (class Value* value = myEnabledCond[i]->eval (valuation)) { assert (value->getKind () == Value::vLeaf); log[myEnabledSet[i]] = bool (static_cast(*value)); delete value; } else { assert (!valuation.isOK ()); valuation.clearErrors (); } } } #ifdef EXPR_COMPILE # include "CExpression.h" # include "Net.h" # include "util.h" /** Compile transition output variable advancement * @param cexpr compilation output * @param indent indentation level * @param vars the output variables * @param varbase name of the temporary variable * @param varsuffix offset to varbase * @param fired name of the "fired" flag */ static void compileOutputAdvance (class CExpression& cexpr, unsigned indent, const class QuantifierList& vars, const char* varbase, char* varsuffix, const char* fired) { const char* wrap = cexpr.getTmpFlag (); class StringBuffer& out = cexpr.getOut (); QuantifierList::const_iterator i; for (i = vars.begin (); i != vars.end (); i++) { const class VariableDefinition& var = (*i)->getVariable (); const class Type& type = var.getType (); snprintf (varsuffix, 21, "%u", var.getNumber ()); out.indent (indent), out.append (wrap), out.append ("=0;\n"); type.compileSuccessor (out, indent, varbase, varbase, wrap); out.indent (indent); out.append ("if ("), out.append (wrap), out.append (") {\n"); indent += 2; } out.indent (indent); out.append ("if ("), out.append (fired), out.append (")\n"); cexpr.compileError (indent + 2, errComp); out.indent (indent), out.append (fired), out.append ("=1;\n"); for (i = vars.begin (); i != vars.end (); i++) out.indent (indent -= 2), out.append ("}\n"); for (i = vars.begin (); i != vars.end (); i++) { if (const class Expression* cond = (*i)->getCondition ()) { const char* pass = cexpr.getFlag (); cond->compile (cexpr, indent, pass, 0); out.indent (indent); out.append ("if (!"), out.append (pass), out.append (")\n"); out.indent (indent + 2), out.append ("continue;\n"); } } } /** Compile deassignment of optionally undefined variables * @param out output stream * @param indent indentation level * @param t head of symbolic token list * @param u current symbolic token */ static void compileDeassign (class StringBuffer& out, unsigned indent, const struct unif* t, const struct unif* u) { for (VariableSet::const_iterator vi = u->vars->begin (); vi != u->vars->end (); vi++) { const class VariableDefinition& var = **vi; if (var.isUndefined ()) { const struct unif* v; /** flag: could the variable have been assigned previously? */ bool assigned = false; for (v = t; v != u; v = v->next) { if (v->vars && v->vars->contains (var)) { assigned = true; break; } } out.indent (indent); if (assigned) { /** index number of symbolic token */ unsigned i; out.append ("if ("); for (v = t, i = 0; v != u; v = v->next, i++) { if (v->vars && v->vars->contains (var)) { if (!assigned) { out.append ("&&\n"); out.indent (indent + 4); } assigned = false; out.append ("!token"), out.append (i), out.append (".count"); } } out.append (")\n"); out.indent (indent + 2); } out.append ("DEASSIGN (vars, "); out.append (var.getNumber () - 1); out.append (");\n"); } } } /** Compile code for determining whether a transition is hidden * @param out output stream * @param indent indentation level * @param t head of symbolic token list * @param u current symbolic token */ static void compileHidden (class CExpression& cexpr, unsigned indent, const class Expression& expr, const char* flag) { expr.compile (cexpr, indent, flag, 0); } void Transition::compileAnalysis (class CExpression& cexpr, const std::list& inputPlaces, unsigned numOptVars) const { assert (!!myNet); /** base name for output variables */ static const char varbase[] = "vars.x"; /** output variable name */ char varname[21 + sizeof varbase]; memcpy (varname, varbase, sizeof varbase); /** base name for successor places */ static const char msetbase[] = "mDest.p"; /** successor place name */ char msetname[21 + sizeof msetbase]; memcpy (msetname, msetbase, sizeof msetbase); /** the output stream */ class StringBuffer& out = cexpr.getOut (); if (!myGates.empty () && (*myGates.begin ())->getKind () == Expression::eConstant) { // there is a constant gate (which should be always disabled): // ignore the transition #ifndef NDEBUG const class Expression* g = *myGates.begin (); const class Value& v = static_cast(g)->getValue (); assert (v.getKind () == Value::vLeaf); assert (!bool (static_cast(v))); #endif // NDEBUG out.append (" return 0;\n"); return; } cexpr.setFatalError ("return *fatal=1, ++numErrors;\n"); const struct unif* u, *v; unsigned i, j; // variable declarations out.append (" unsigned numErrors=0;\n"); if (myOutputVariables) out.append (" unsigned fired;\n"); for (u = myUnif, i = 0; u; u = u->next, i++) { out.indent (2); if (myNet->getPlace (u->place)->getMaxNumTokens () == 1) out.append ("TOKEN1"); else out.append (u->vars ? "TOKEN" : (u->isSet ? "TOKENM" : "TOKENC")); out.append (" ("); u->m->getType ()->appendIndex (out); out.append (", "); out.append (i); out.append (");\n"); } // check for insufficiently marked input places std::list::const_iterator p; out.append ("#ifdef TRANSITION_EMPTY\n" " if (0"); for (p = inputPlaces.begin (); p != inputPlaces.end (); p++) { if (!(*p)->getCapacityBits ()) continue; // do not check places with constant number of tokens /** minimum number of tokens the place is guaranteed to contain */ card_t minTokens = 0; if (const class Constraint* c = (*p)->getCapacity ()) { const class Value& value = c->getFirstValue (); assert (value.getKind () == Value::vLeaf); minTokens = card_t (static_cast(value)); } /** minimum number of required tokens from the place */ card_t reqTokens = 0; for (u = myUnif; u; u = u->next) { if (u->varMult || myNet->getPlace (u->place) != *p || u->isSet) continue; if (const class Expression* mult = u->m->getMultiplicity ()) { assert (mult->getKind () == Expression::eConstant); const class Value& value = static_cast(mult)->getValue (); assert (value.getKind () == Value::vLeaf); reqTokens += card_t (static_cast(value)); } else reqTokens++; } if (reqTokens > minTokens) { out.append ("\n ||numTokens["); out.append ((*p)->getIndex ()); out.append ("]<"); out.append (reqTokens); } } out.append (")\n" " return 0;\n" "#endif /* TRANSITION_EMPTY */\n"); // clear the optional variables if (numOptVars) out.append (" memset (vars.y, 0, sizeof vars.y);\n"); // generate the unification code unsigned indent = 2; VariableSet::const_iterator vi; class VariableSet oldvars; for (u = myUnif, i = 0; u; u = u->next, i++) { char token[34]; snprintf (token, sizeof token, "token%u.count", i); if (i) { out.append ("#define ERROR(err){numErrors++;goto cont"); out.append (i); out.append (";}\n"); } else out.append ("#define ERROR(err)return++numErrors\n"); bool* checkpoint = 0; unsigned checkpointSize = u->varMult || u->isSet ? cexpr.getCheckpoint (checkpoint) : 0; if (!u->isSet) { u->m->compileMultiplicity (cexpr, indent, token, &oldvars); cexpr.compileCleanup (indent); if (u->varMult) { out.indent (indent); out.append ("if (!"); out.append (token); out.append (") goto unified"); out.append (i), out.append (";\n"); } } out.append ("#undef ERROR\n"); if (myNet->getPlace (u->place)->getMaxNumTokens () != 1) { out.indent (indent); out.append (u->vars ? "INIT_TOKEN" : (u->isSet ? "INIT_TOKENM" : "INIT_TOKENC")); out.append (" ("); out.append (i); out.append (", mSrc.p"); out.append (u->place); out.append (");\n"); } out.indent (indent); out.append ("for (;;) {\n"); indent += 2; if (myNet->getPlace (u->place)->getMaxNumTokens () == 1) { // place with at most one token: simpler data structure if (u->isSet) { // multiset-valued token: evaluate and compare to place contents snprintf (token, sizeof token, "token%u.item", i); out.append ("#define ERROR(err){numErrors++;break;}\n"); out.indent (indent); out.append (token); out.append ("=0;\n"); u->m->getToken ()->compileScalarMset (cexpr, indent, token, 0, true); cexpr.setCheckpoint (indent, checkpoint, checkpointSize); delete[] checkpoint; out.append ("#undef ERROR\n"); out.indent (indent); out.append ("if ("); out.append (token); out.append (" &&\n"); out.indent (indent + 4); out.append ("(!mSrc.p"); out.append (u->place); out.append (" ||\n"); out.indent (indent + 6); out.append (" (\n"); snprintf (token, sizeof token, "(*token%u.item)", i); char pm[34]; snprintf (pm, sizeof pm, "(*mSrc.p%u)", i); if (!u->m->getType ()->compileEqual (out, indent + 6, token, pm, false, true, true, false)) out.append ("0"); out.append ("))) {\n"); out.indent (indent + 2); out.append ("token"); out.append (i); out.append (".item = 0;\n"); out.indent (indent + 2); out.append ("break;\n"); out.indent (indent); out.append ("}\n"); } else { out.indent (indent); out.append ("if (!(token"); out.append (i); out.append (".item=mSrc.p"); out.append (u->place); out.append (")"); if (u->m->getMultiplicity ()) out.append ("||token"), out.append (i), out.append (".count!=1"); out.append (") break;\n"); snprintf (token, sizeof token, "(*token%u.item)", i); if (u->vars) { // token with variables: unify out.append ("#define ERROR(err) goto cont"); out.append (i); out.append ("\n"); for (vi = u->vars->begin (); vi != u->vars->end (); vi++) oldvars.insert (**vi); // bind the variables u->m->getToken ()->compileLvalue (cexpr, indent, *u->vars, token); // are all tokens unified so far compatible with the new bindings? for (j = 0, v = myUnif; j <= i; v = v->next, j++) { if (!v->m->getToken ()->depends (*u->vars, false)) continue; if (v == u && u->m->getToken ()->getKind () == Expression::eVariable && u->vars->size () == 1 && &static_cast (u->m->getToken ())->getVariable () == *u->vars->begin ()) continue; // the token is a variable unified from the place bool hasMult = v->m->hasMultiplicity (); if (hasMult) { out.indent (indent); out.append ("if (token"); out.append (j); out.append (".count) {\n"); indent += 2; } snprintf (token, sizeof token, "(*token%u.item)", j); v->m->getToken ()->compileCompatible (cexpr, indent, oldvars, token); if (hasMult) { indent -= 2; out.indent (indent); out.append ("}\n"); } } /** flag: has the error macro been redefined? */ bool errors = false; // are all gates compatible with the new bindings? for (GateList::const_iterator g = myGates.begin (); g != myGates.end (); g++) { if (!(*g)->depends (*u->vars, false) || (*g)->depends (oldvars, true)) continue; if (!errors) { errors = true; out.append ("#undef ERROR\n" "#define ERROR(err)" "{if(err!=errVar&&err!=errComp)numErrors++;goto cont"); out.append (i); out.append (";}\n"); } const char* work = cexpr.getFlag (); out.indent (indent); out.append ("do {\n"); (*g)->compile (cexpr, indent + 2, work, &oldvars); out.indent (indent + 2); out.append ("if (!"); out.append (work); out.append (")\n"); cexpr.compileError (indent + 4, errComp); out.indent (indent); out.append ("} while (0);\n"); } out.append ("#undef ERROR\n"); cexpr.compileCleanup (indent); out.indent (indent); out.append ("goto unified"); out.append (i); out.append (";\n"); if (u->varMult) { cexpr.setCheckpoint (indent, checkpoint, checkpointSize, false); ::compileDeassign (out, indent, myUnif, u); } out.indent (indent); out.append ("break;\n"); } else if (u->m->getToken ()->getKind () == Expression::eConstant) { // constant token: compare to place contents out.indent (indent); out.append ("if ("); if (!static_cast(u->m->getToken ()) ->getValue ().compileEqual (out, indent + 4, token, false, true, true)) out.append ("0"); out.append (") break;\n"); } else { // scalar-valued token: evaluate and compare to place contents out.indent (indent); out.append ("else {\n"); out.indent (indent + 2); u->m->getType ()->appendName (out); out.append (" item;\n" "#define ERROR(err){numErrors++;break;}\n"); u->m->getToken ()->compile (cexpr, indent + 2, "item", 0); out.append ("#undef ERROR\n"); out.indent (indent + 2); out.append ("if ("); if (!u->m->getType ()->compileEqual (out, indent + 6, token, "item", false, true, true, false)) out.append ("0"); out.append (") break;\n"); out.indent (indent); out.append ("}\n"); } } } else if (u->vars) { // token with variables: unify out.indent (indent - 2); out.append ("next"); out.append (i); out.append (":\n"); out.indent (indent); out.append ("while (token"); out.append (i); out.append (".i) {\n"); out.indent (indent + 2); out.append ("if (!ENOUGH_TOKEN ("); out.append (i); out.append (")) { NEXT_TOKEN ("); out.append (i); out.append ("); continue; }\n"); snprintf (token, sizeof token, "token%u.i->item", i); // is the token compatible with the existing variable bindings? out.append ("#define ERROR(err){if(err==errVar)continue;\\\n" "else{NEXT_TOKEN ("); out.append (i), out.append (");goto next"); out.append (i), out.append (";}}\n"); for (vi = u->vars->begin (); vi != u->vars->end (); vi++) oldvars.insert (**vi); // bind the variables u->m->getToken ()->compileLvalue (cexpr, indent + 2, *u->vars, token); // are all tokens unified so far compatible with the new bindings? for (j = 0, v = myUnif; j <= i; v = v->next, j++) { if (!v->m->getToken ()->depends (*u->vars, false)) continue; if (v == u && u->m->getToken ()->getKind () == Expression::eVariable && u->vars->size () == 1 && &static_cast (u->m->getToken ())->getVariable () == *u->vars->begin ()) continue; // the token is a variable unified from the place bool hasMult = v->m->hasMultiplicity (); if (hasMult) { out.indent (indent + 2); out.append ("if (token"), out.append (j), out.append (".count) {\n"); indent += 2; } snprintf (token, sizeof token, "token%u.i->item", j); v->m->getToken ()->compileCompatible (cexpr, indent + 2, oldvars, token); if (hasMult) { indent -= 2; out.indent (indent + 2); out.append ("}\n"); } } // are all gates compatible with the new bindings? for (GateList::const_iterator g = myGates.begin (); g != myGates.end (); g++) { if (!(*g)->depends (*u->vars, false) || (*g)->depends (oldvars, true)) continue; const char* work = cexpr.getFlag (); out.indent (indent + 2); out.append ("do {\n"); (*g)->compile (cexpr, indent + 4, work, &oldvars); out.indent (indent + 4); out.append ("if (!"); out.append (work); out.append (")\n"); cexpr.compileError (indent + 6, errComp); out.indent (indent + 2); out.append ("} while (0);\n"); } out.append ("#undef ERROR\n"); cexpr.compileCleanup (indent + 2); out.indent (indent + 2); out.append ("goto unified"); out.append (i); out.append (";\n"); out.indent (indent); out.append ("}\n"); if (u->varMult) { cexpr.setCheckpoint (indent, checkpoint, checkpointSize, false); ::compileDeassign (out, indent, myUnif, u); } out.indent (indent); out.append ("break;\n"); } else if (u->isSet) { // multiset-valued token: evaluate and see if subset of input marking out.append ("#define ERROR(err){numErrors++;break;}\n"); snprintf (token, sizeof token, "token%u.v", i); u->m->getToken ()->compileMset (cexpr, indent, 0, token, 0); cexpr.setCheckpoint (indent, checkpoint, checkpointSize); delete[] checkpoint; out.append ("#undef ERROR\n"); out.indent (indent); out.append ("if (!FIND_TOKENM ("); out.append (i); out.append (", "); u->m->getType ()->appendIndex (out); out.append (")) { FREE ("); out.append (token); out.append ("); break; }\n"); } else { // scalar-valued token: evaluate and search for it in the place out.append ("#define ERROR(err){numErrors++;break;}\n"); snprintf (token, sizeof token, "token%u.item", i); u->m->getToken ()->compile (cexpr, indent, token, 0); out.append ("#undef ERROR\n"); out.indent (indent); out.append ("if (!FIND_TOKEN ("); out.append (i); out.append (", "); u->m->getType ()->appendIndex (out); out.append (")) break;\n"); } // unified a token out.indent (indent - 2); out.append ("unified"); out.append (i); out.append (":\n"); if (u->varMult && !u->isSet) { cexpr.setCheckpoint (indent, checkpoint, checkpointSize); delete[] checkpoint; } out.indent (indent); if (u->varMult) { out.append ("if (token"); out.append (i); out.append (".count)\n"); out.indent (indent + 2); } if (myNet->getPlace (u->place)->getMaxNumTokens () == 1) { out.append ("mSrc.p"); out.append (u->place); out.append ("=0;\n"); } else if (u->isSet) { // multiset-valued token out.append ("RESERVE_TOKENM ("); out.append (i); out.append (", "); u->m->getType ()->appendIndex (out); out.append (");\n"); } else { // scalar-valued token out.append ("RESERVE_TOKEN ("); out.append (i); out.append (");\n"); } } out.append ("#define ERROR(err){if (err!=errComp)numErrors++;goto cont"); out.append (i); out.append (";}\n"); // check the gates depending on possibly undefined variables class VariableSet undefVars; for (const_iterator ui = myVariables.begin (); ui != myVariables.end (); ui++) { const class VariableDefinition& var = *ui->second; if (var.isUndefined ()) undefVars.insert (var); } for (GateList::const_iterator g = myGates.begin (); g != myGates.end (); g++) if ((*g)->depends (undefVars, false)) (*g)->compile (cexpr, indent, cexpr.getFlag (), 0); if (myKind) { // an assertion transition is enabled out.append ("#undef ERROR\n"); cexpr.compileCleanup (indent); // unwind the unification stack and return for (unsigned k = i; k--; ) { for (u = myUnif, j = k; j--; u = u->next); out.indent (indent); if (myNet->getPlace (u->place)->getMaxNumTokens () == 1) { out.append ("mSrc.p"); out.append (u->place); out.append (" = token"); out.append (k); out.append (".item;\n"); } else if (u->isSet) { out.append ("RELEASE_TOKENM ("); out.append (k); out.append (", "); u->m->getType ()->appendIndex (out); out.append (");\n"); } else { out.append ("RELEASE_TOKEN ("); out.append (k); out.append (");\n"); } if (u->vars) ::compileDeassign (out, indent, myUnif, u); } if (myKind == tFatal) cexpr.compileError (indent, errFatal); else { out.indent (indent); out.append ("return ++numErrors;\n"); } i--; goto finish; } if (myNumParents) { // report that a synchronisation transition is enabled out.indent (indent); out.append ("(*syncstate) ("); out.append (myLocalIndex); out.append (", ctx);\n"); goto skip; } if (myOutputMarking) { // Determine which place markings are referenced from the output arcs class BitVector outputArcs (myNet->getNumPlaces ()); for (unsigned arc = 0; arc < myNumOutputs; arc++) if (!myOutputs[arc]->getExpr ().forExpressions (&::findOutput, &outputArcs)) assert (false); cexpr.setMultiset ("mIn"); out.indent (indent); out.append ("freem (&mIn);\n"); for (u = myUnif, i = 0; u; u = u->next, i++) { if (!outputArcs[u->place]) continue; out.indent (indent); if (myNet->getPlace (u->place)->getMaxNumTokens () == 1) { out.append ("if (token"), out.append (i); out.append (".item)\n"); out.indent (indent + 2); out.append ("mIn.p"), out.append (u->place); out.append ("=memcpy(malloc(sizeof("); u->m->getType ()->appendName (out); out.append (")), token"), out.append (i); out.append (".item, sizeof("); u->m->getType ()->appendName (out); out.append ("));\n"); } else { out.append ("mIn.p"), out.append (u->place); out.append ("=insert"); u->m->getType ()->appendIndex (out); out.append (" (mIn.p"), out.append (u->place); out.append (", &token"), out.append (i); out.append (".i->item, token"), out.append (i); out.append (".count);\n"); } } } if (myOutputVariables) { // initialize the output variables to maximum values QuantifierList::const_iterator q; /** flag: is there a condition on the output variables? */ bool cond = false; for (q = myOutputVariables->begin (); q != myOutputVariables->end (); q++) { const class VariableDefinition& var = (*q)->getVariable (); if ((*q)->getCondition ()) cond = true; snprintf (varname + (sizeof varbase) - 1, 21, "%u", var.getNumber ()); var.getType ().compileTop (out, indent, varname); } out.indent (indent); out.append ("fired=0;\n"); out.indent (indent); out.append ("while (!*intr && !*fatal) {\n"); indent += 2; if (cond) { out.indent (indent); out.append ("for (;;) {\n"); ::compileOutputAdvance (cexpr, indent + 2, *myOutputVariables, varname, varname + (sizeof varbase) - 1, "fired"); out.indent (indent + 2); out.append ("break;\n"); out.indent (indent); out.append ("}\n"); } else ::compileOutputAdvance (cexpr, indent, *myOutputVariables, varname, varname + (sizeof varbase) - 1, "fired"); } out.indent (indent); out.append ("initm ();\n"); // fire the outputs for (unsigned arc = 0; arc < myNumOutputs; arc++) { const class Place& place = myOutputs[arc]->getPlace (); assert (myOutputs[arc]->isOutput ()); snprintf (msetname + (sizeof msetbase) - 1, 22, "%u", place.getIndex ()); bool* checkpoint = 0; unsigned checkpointSize = 0; if (place.isImplicit ()) { checkpointSize = cexpr.getCheckpoint (checkpoint); out.append ("#if !NO_INVARIANT_CHECK("); out.append (place.getIndex ()); out.append (")\n"); } if (place.getMaxNumTokens () == 1) { myOutputs[arc]->getExpr ().compileScalarMset (cexpr, indent, msetname, 0, true); out.indent (indent); out.append ("if ("); out.append (msetname); out.append (")\n"); out.indent (indent + 2); out.append (msetname); out.append (" = memcpy (malloc (sizeof *"); out.append (msetname); out.append ("), "); out.append (msetname); out.append (", sizeof *"); out.append (msetname); out.append (");\n"); if (!place.getCapacityBits ()) { out.indent (indent); out.append ("else\n"); cexpr.compileError (indent + 2, errConst); } } else myOutputs[arc]->getExpr ().compileMset (cexpr, indent, 0, msetname, 0); if (place.isImplicit ()) { out.append ("#endif /* NO_INVARIANT_CHECK */\n"); cexpr.setCheckpoint (indent, checkpoint, checkpointSize); delete[] checkpoint; } } cexpr.setMultiset (0); // compute the enabling sets if (myNumEnabled) { const char* work = cexpr.getFlag (); out.indent (indent), out.append ("if (log) {\n"); for (j = 0; j < myNumEnabled; j++) { out.indent (indent + 2); out.append ("if (!log["), out.append (j), out.append ("]) {\n"); myEnabledCond[j]->compile (cexpr, indent + 4, work, 0); out.indent (indent + 4); out.append ("log["), out.append (j), out.append ("] = "); out.append (work), out.append (";\n"); out.indent (indent + 2); out.append ("}\n"); } out.indent (indent), out.append ("}\n"); } // encode the marking and add the arcs // determine whether the transition is hidden if (myHide) { const char* work = cexpr.getFlag (); ::compileHidden (cexpr, indent, *myHide, work); cexpr.compileCleanup (indent); out.indent (indent); out.append ("if (encode ("), out.append (myNet->getIndex ()); out.append (", "), out.append (myLocalIndex); out.append (", "), out.append (myRootIndex); out.append (", "), out.append (work), out.append (", ctx))\n"); } else { cexpr.compileCleanup (indent); out.indent (indent); out.append ("if (encode ("), out.append (myNet->getIndex ()); out.append (", "), out.append (myLocalIndex); out.append (", "), out.append (myRootIndex); out.append (", 0, ctx))\n"); } cexpr.compileError (indent + 2, errCard); // encode the arc inscription out.indent (indent); out.append ("if (arcs) e ();\n"); if (myOutputVariables) out.indent (indent -= 2), out.append ("}\n"); skip: out.append ("#undef ERROR\n"); if (i) { out.indent (indent - 2); out.append ("cont"); out.append (i); out.append (":\n"); out.indent (indent); out.append ("if (*intr || *fatal) return numErrors;\n"); } // move to next token while (i--) { for (u = myUnif, j = i; j--; u = u->next); if (u->next) { out.indent (indent - 2); out.append ("cont"); out.append (i + 1); out.append (":\n"); } if (u->varMult) { out.indent (indent); out.append ("if (!token"), out.append (i), out.append (".count)\n"); out.indent (indent + 2); out.append ("goto cont"), out.append (i), out.append (";\n"); } out.indent (indent); if (myNet->getPlace (u->place)->getMaxNumTokens () == 1) { out.append ("mSrc.p"); out.append (u->place); out.append (" = token"); out.append (i); out.append (".item;\n"); if (u->vars) ::compileDeassign (out, indent, myUnif, u); out.indent (indent); out.append ("break;\n"); } else { if (u->isSet) { out.append ("RELEASE_TOKENM ("); out.append (i); out.append (", "); u->m->getType ()->appendIndex (out); out.append (");\n"); } else { out.append ("RELEASE_TOKEN ("); out.append (i); out.append (");\n"); } if (u->vars) { ::compileDeassign (out, indent, myUnif, u); out.indent (indent); out.append ("NEXT_TOKEN ("); out.append (i); out.append (");\n"); out.indent (indent); out.append ("if (!token"); out.append (i); out.append (".i)\n"); out.indent (indent + 2); } else out.indent (indent); out.append ("goto cont"), out.append (i), out.append (";\n"); } finish: out.indent (indent -= 2); out.append ("}\n"); } // finish cexpr.compileCleanup (indent); cexpr.setFatalError (0); out.append ("cont0:\n" " return numErrors;\n"); } /** Compile transition instance encoder * @param cexpr compilation output * @param iLocal local index number of the transition * @param iGlobal global index number of the transition * @param numTrans number of transitions in the module * @param numAllTrans number of transitions in the whole system * @param vars transition variables */ inline static void compileEncoder (class CExpression& cexpr, unsigned iLocal, unsigned iGlobal, unsigned numTrans, unsigned numAllTrans, const Transition::VariableMap& vars) { class StringBuffer& out = cexpr.getOut (); out.append (" if (flat)"); if (numAllTrans > 1) { out.append ("\n" " enc ("); out.append (iGlobal); out.append (", "); out.append (log2 (numAllTrans)); out.append (");\n"); } else out.append (";\n"); if (numTrans > 1) { out.append (" else\n" " enc ("); out.append (iLocal); out.append (", "); out.append (log2 (numTrans)); out.append (");\n"); } static const char varbase[] = "vars."; char varname[21 + sizeof varbase]; memcpy (varname, varbase, sizeof varbase); for (Transition::const_iterator v = vars.begin (); v != vars.end (); v++) { const class VariableDefinition& var = *v->second; if (var.isUndefined ()) { snprintf (varname + (sizeof varbase) - 1, 22, "y%u", var.getNumber ()); out.append (" if (ASSIGNED (vars, "); out.append (var.getNumber () - 1); out.append (")) {\n enc (0, 1);\n"); var.getType ().compileEncoder (cexpr, 4, "enc", varname); out.append (" }\n else\n enc (1, 1);\n"); } else { snprintf (varname + (sizeof varbase) - 1, 22, "x%u", var.getNumber ()); var.getType ().compileEncoder (cexpr, 2, "enc", varname); } } } /** Compile transition instance decoder and fairness checks * @param cexpr compilation output * @param vars transition variables */ inline static void compileDecoder (class CExpression& cexpr, const Transition::VariableMap& vars) { static const char varbase[] = "vars."; char varname[21 + sizeof varbase]; memcpy (varname, varbase, sizeof varbase); class StringBuffer& out = cexpr.getOut (); for (Transition::const_iterator v = vars.begin (); v != vars.end (); v++) { const class VariableDefinition& var = *v->second; if (var.isUndefined ()) { snprintf (varname + (sizeof varbase) - 1, 22, "y%u", var.getNumber ()); out.append (" if (dec (1))\n DEASSIGN (vars, "); out.append (var.getNumber () - 1); out.append (");\n" " else {\n" " ASSIGN (vars, "); out.append (var.getNumber () - 1); out.append (");\n"); var.getType ().compileDecoder (cexpr, 4, "dec", varname); out.append (" }\n"); } else { snprintf (varname + (sizeof varbase) - 1, 22, "x%u", var.getNumber ()); var.getType ().compileDecoder (cexpr, 2, "dec", varname); } } } /** Compile fairness constraints * @param cexpr compilation output * @param indent indentation level * @param fair variable name of the computed fairness set * @param numFair number of fairness constraints * @param fairCond the fairness conditions * @param fairSet the fairness set numbers */ static void compileFairness (class CExpression& cexpr, unsigned indent, const char* fair, unsigned numFair, const class Expression*const* fairCond, const unsigned* fairSet) { const char* work = 0; class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append ("*"), out.append (fair), out.append (" = 0;\n"); for (unsigned i = numFair; i--; ) { if (!work) work = cexpr.getFlag (); fairCond[i]->compile (cexpr, indent, work, 0); out.indent (indent); out.append ("if ("); out.append (work); out.append (") "); out.append (fair), out.append ("[++*("); out.append (fair), out.append (")]="); out.append (fairSet[i]); out.append (";\n"); } } /** Compile constant declarations * @param out the output stream * @param numConstants number of constants * @param constants the constants * @param constantNames the names of the constants */ inline static void compileConstantDecl (class StringBuffer& out, unsigned numConstants, const class Constant*const* constants, const char*const* constantNames) { class Printer printer; printer.setOutput (&out); for (unsigned i = 0; i < numConstants; i++) { out.append ("#if 0\n"); printer.printQuoted (constantNames[i]); out.append ("\n" "#endif\n" "static "); constants[i]->getType ()->appendName (out); out.append (" c_"); out.append (i); out.append (";\n"); } } /** Compile constant initializations * @param out the output stream * @param numConstants number of constants * @param constants the constants */ inline static void compileConstantInit (class StringBuffer& out, unsigned numConstants, const class Constant*const* constants) { char name[23]; for (unsigned i = 0; i < numConstants; i++) { snprintf (name, sizeof name, "c_%u", i); constants[i]->getValue ().compileInit (name, 2, out); } } void Transition::compile (class StringBuffer& out) const { assert (!!myNet); class CExpression cexpr (out, *myNet, this); out.append ("#include \"mset.h\"\n" "#include \"event.h\"\n" "#include \"token.h\"\n\n" "#ifdef TRANSITION_ID\n" "static const char transition_id[] = "); { class Printer printer; printer.setOutput (&out); printer.printQuoted (myName); } out.append (";\n" "#endif\n\n" "#ifndef NO_INVARIANT_CHECK\n" "# define NO_INVARIANT_CHECK(p) 0\n" "#endif\n\n"); unsigned numOptVars = 0; if (!myVariables.empty ()) { out.append ("static struct {\n"); unsigned numVars = 0; for (const_iterator i = myVariables.begin (); i != myVariables.end (); i++) { const class VariableDefinition& var = *i->second; out.indent (2); var.getType ().appendName (out); numVars++; if (var.isUndefined ()) { const_cast(var).setNumber (++numOptVars); out.append (" y"); } else { const_cast(var).setNumber (numVars); out.append (" x"); } out.append (var.getNumber ()); out.append (";\n"); } if (numOptVars) { out.append (" unsigned long y[("); out.append (numOptVars); out.append (" + sizeof (long) - 1) / sizeof (long)];\n"); } out.append ("} vars;\n\n"); cexpr.setValuation ("vars"); } ::compileConstantDecl (out, myNumConstants, myConstants, myConstantNames); out.append ("extern void\ni"); out.append (myRootIndex); out.append (" (void)\n{\n"); ::compileConstantInit (out, myNumConstants, myConstants); out.append ("}\n"); std::list inputPlaces; std::list::const_iterator ini; for (unsigned in = myNumInputs; in--; ) { for (ini = inputPlaces.begin (); ini != inputPlaces.end (); ini++) if (*ini == &myInputs[in]->getPlace ()) break; if (ini == inputPlaces.end ()) inputPlaces.push_front (&myInputs[in]->getPlace ()); } // encoding { const class Net* root = myNet; while (root->getParent ()) root = root->getParent (); ::compileEncoder (cexpr, myLocalIndex, myRootIndex, myNet->getNumTransitions (), root->getNumAllTransitions (), myVariables); } cexpr.compileCleanup (2); out.append ("static void\ne (void)\n{\n"); cexpr.generate (); out.append ("}\n"); // instance analysis compileAnalysis (cexpr, inputPlaces, numOptVars); out.append ("extern unsigned\na"); out.append (myRootIndex); out.append (" (void* ctx, char* log)\n{\n"); cexpr.generate (); out.append ("}\n"); // decoding ::compileDecoder (cexpr, myVariables); cexpr.getOut ().append ("#define ERROR(err) return err\n"); ::compileFairness (cexpr, 2, "wfair", myNumWeaklyFair, myWeaklyFairCond, myWeaklyFairSet); cexpr.getOut ().append (" if (sf) {\n"); ::compileFairness (cexpr, 4, "sfair", myNumStronglyFair, myStronglyFairCond, myStronglyFairSet); cexpr.getOut ().append (" }\n" "#undef ERROR\n" " return errNone;\n"); cexpr.compileCleanup (2); out.append ("enum Error\nd"); out.append (myRootIndex); out.append (" (unsigned sf)\n{\n"); cexpr.generate (); out.append ("}\n"); } #endif // EXPR_COMPILE void Transition::display (const class Printer& printer) const { printer.printRaw ("trans"); printer.delimiter (' '); printer.print (myName); if (myPriority) printer.delimiter (' '), printer.print (myPriority); printer.finish (); if (myKind) { printer.printRaw (myKind == tFatal ? "gate fatal" : "gate undefined"); printer.finish (); } if (myOutputVariables) { printer.delimiter ('{')++.linebreak (); for (QuantifierList::const_iterator i = myOutputVariables->begin (); i != myOutputVariables->end (); i++) { const class VariableDefinition& v = (*i)->getVariable (); if (const char* name = v.getType ().getName ()) printer.print (name); else printer.print (v.getType ().getSyntacticName ()); printer.delimiter (' '); printer.print (v.getName ()); printer.delimiter ('!'); if (const class Expression* cond = (*i)->getCondition ()) { printer.delimiter ('(')++; cond->display (printer); --printer.delimiter (')'); } printer.delimiter (';'); printer.linebreak (); } printer--; printer.linebreak (); printer.delimiter ('}').finish (); } unsigned i; if (myNumInputs) { printer.finish (); printer.printRaw ("in "); printer.delimiter ('{')++; for (i = 0; i < myNumInputs; i++) { printer.linebreak (); printer.printRaw ("place "); printer.print (myInputs[i]->getPlace ().getName ()); printer.delimiter (':'); myInputs[i]->getExpr ().display (printer); printer.delimiter (';'); } printer--; printer.linebreak (); printer.delimiter ('}'); } if (myNumOutputs) { printer.finish (); printer.printRaw ("out "); printer.delimiter ('{')++; for (i = 0; i < myNumOutputs; i++) { printer.linebreak (); printer.printRaw ("place "); printer.print (myOutputs[i]->getPlace ().getName ()); printer.delimiter (':'); myOutputs[i]->getExpr ().display (printer); printer.delimiter (';'); } printer--; printer.linebreak (); printer.delimiter ('}'); } if (!myGates.empty ()) { printer.finish (); printer.printRaw ("gate "); for (GateList::const_iterator g = myGates.begin ();; ) { (*g)->display (printer); if (++g == myGates.end ()) break; printer.delimiter (','); } } if (myHide) { printer.finish (); printer.printRaw ("hide "); myHide->display (printer); } if (myNumWeaklyFair) { printer.finish (); printer.printRaw ("weakly_fair "); for (i = 0;;) { printer.printRaw ("/*"); printer.print (myWeaklyFairSet[i]); printer.printRaw ("*/"); myWeaklyFairCond[i]->display (printer); if (++i == myNumWeaklyFair) break; printer.delimiter (','); } } if (myNumStronglyFair) { printer.finish (); printer.printRaw ("strongly_fair "); for (i = 0;;) { printer.printRaw ("/*"); printer.print (myStronglyFairSet[i]); printer.printRaw ("*/"); myStronglyFairCond[i]->display (printer); if (++i == myNumStronglyFair) break; printer.delimiter (','); } } if (myNumEnabled) { printer.finish (); printer.printRaw ("enabled "); for (i = 0;;) { printer.printRaw ("/*"); printer.print (myEnabledSet[i]); printer.printRaw ("*/"); myEnabledCond[i]->display (printer); if (++i == myNumEnabled) break; printer.delimiter (','); } } printer.delimiter (';'); printer.finish (); } maria-1.3.5/Net/Arc.C0000644000175000017500000000326007643247642014335 0ustar msmakelamsmakela// Arc class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Arc.h" #include "Marking.h" #include "Place.h" /** @file Arc.C * Labelled arc in a net */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Arc::Arc (bool output, class Marking& expr, const class Place& place, bool copy) : myIsOutput (output), myExpr (&expr), myPlace (place), myIndex (place.getIndex ()), myCopy (copy) { expr.setPlace (&place); } Arc::~Arc () { myExpr->destroy (); } void Arc::substitute (class Substitution& substitution) { class Expression* expr = myExpr->substitute (substitution); assert (expr && expr->getKind () == Expression::eMarking); myExpr->destroy (); myExpr = static_cast(expr); } void Arc::append (class Marking& expr) { expr.setPlace (&myPlace); myExpr->append (expr); } maria-1.3.5/Net/Arc.h0000644000175000017500000000542607643247642014410 0ustar msmakelamsmakela// Arc class -*- c++ -*- #ifndef ARC_H_ # define ARC_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ /** @file Arc.h * Labelled arc in a net */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Arc between a Place and a Transition labelled with Marking expression */ class Arc { public: /** Constructor * @param output Flag: is this an output arc? * @param expr Arc expression (formal tokens) * @param place Place associated with the arc * @param copy Flag: is this a copied definition? */ Arc (bool output, class Marking& expr, const class Place& place, bool copy = false); private: /** Copy constructor */ Arc (const class Arc& old); /** Assignment operator */ class Arc& operator= (const class Arc& old); public: /** Destructor */ ~Arc (); /** Determine whether this is an output arc */ bool isOutput () const { return myIsOutput; } /** Get the arc expression */ const class Marking& getExpr () const { return *myExpr; } /** Substitute the arc expression * @param substitution the variable substitutions */ void substitute (class Substitution& substitution); /** Get the place associated with this arc */ const class Place& getPlace () const { return myPlace; } /** Get the index number of the place associated with this arc */ unsigned getIndex () const { return myIndex; } /** Determine whether this is a copied arc definition */ bool isCopy () const { return myCopy; } /** Append an expression to the arc * @param expr expression to be appended */ void append (class Marking& expr); private: /** Flag: is this an output arc? */ bool myIsOutput; /** Arc expression (formal tokens) */ class Marking* myExpr; /** Place associated with the Arc */ const class Place& myPlace; /** Index number of the place in the net */ const unsigned myIndex; /** Flag: is this a copied arc definition? */ const bool myCopy; }; #endif // ARC_H_ maria-1.3.5/Net/LNet.C0000644000175000017500000006343007643247642014477 0ustar msmakelamsmakela// Low-level net class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "LNet.h" #include "GlobalMarking.h" #include "Net.h" #include "Transition.h" #include "Constraint.h" #include "Printer.h" #include "Place.h" #include "Value.h" #include "Valuation.h" #include "Type.h" #include "BitVector.h" #include "DummyReporter.h" /** @file LNet.C * Low-level (unfolded) net */ /* Copyright © 2000-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ bool LNet::LArc::unfold (class LNet& lnet, const class GlobalMarking& m) { for (unsigned i = m.getSize (); i--; ) { const class PlaceMarking& p = m[i]; if (p.empty () || p.getPlace ()->isConstant ()) continue; for (PlaceMarking::const_iterator pi = p.begin (); pi != p.end (); pi++) if (pi->second && !add (lnet.addPlace (i, *pi->first), pi->second)) return false; } return true; } bool LNet::LArc::read (FILE* f) { unsigned numPlaces; if (1 != fread (&numPlaces, sizeof numPlaces, 1, f)) return false; unsigned* places = new unsigned[numPlaces]; unsigned* weights = new unsigned[numPlaces]; if (places && weights && numPlaces == fread (places, sizeof *places, numPlaces, f) && numPlaces == fread (weights, sizeof *weights, numPlaces, f)) { delete[] myPlaces; delete[] myWeights; myNumPlaces = numPlaces, myPlaces = places, myWeights = weights; return true; } delete[] places; delete[] weights; return false; } bool LNet::LArc::write (FILE* f) const { return 1 == fwrite (&myNumPlaces, sizeof myNumPlaces, 1, f) && myNumPlaces == fwrite (myPlaces, sizeof *myPlaces, myNumPlaces, f) && myNumPlaces == fwrite (myWeights, sizeof *myWeights, myNumPlaces, f); } LNet::LNet (const class Net& net) : myNet (net), myPlaceBits (net.getNumPlaces () ? log2 (net.getNumPlaces ()) : 0), myNumPlaces (0), myPlaces (0), myPlaceMap (), myBuf (), myTransitions (0) { unsigned tr = myNet.getNumAllTransitions (); myTransitions = new FILE*[net.getNumAllTransitions ()]; while (tr--) myTransitions[tr] = tmpfile (); } LNet::~LNet () { delete[] myPlaces; for (iterator i = myPlaceMap.begin (); i != myPlaceMap.end (); i++) delete[] i->first.name; for (unsigned tr = myNet.getNumAllTransitions (); tr--; ) fclose (myTransitions[tr]); delete[] myTransitions; } bool LNet::generateMinimal (const class Printer& printer, unsigned maxerrors) { assert (!myNumPlaces); unsigned i; /** Number of low-level places when high-level transitions were unfolded */ unsigned* numPlaces = new unsigned[myNet.getNumAllTransitions ()]; memset (numPlaces, 0, myNet.getNumAllTransitions () * sizeof *numPlaces); /** The coverable marking */ class GlobalMarking cover (*myNet.getInitMarking ()); // Introduce low-level places for the initial marking for (i = myNet.getNumPlaces (); i--; ) if (myNet.getPlace (i) && myNet.getPlace (i)->isConstant ()) addPlaces (i, cover[i]); /** Flag: was the computation interrupted? */ extern volatile bool interrupted; class DummyReporter reporter (myNet, printer, maxerrors); while (!interrupted && !reporter.isFatal ()) { unsigned n = myNumPlaces; for (i = myNet.getNumAllTransitions (); !interrupted && i--; ) { assert (myNumPlaces >= numPlaces[i]); // Have any new low-level places been generated? if (myNumPlaces <= numPlaces[i] && myNumPlaces) continue; numPlaces[i] = myNumPlaces; myNet.getTransition (i).unfold (cover, *this, reporter); } if (n == myNumPlaces) break; } delete[] numPlaces; return !interrupted && !reporter.isFatal (); } bool LNet::generate (const class Printer& printer, unsigned maxerrors) { assert (!myNumPlaces); /** Flag: was the computation interrupted? */ extern volatile bool interrupted; unsigned i; // Introduce low-level places for the initial marking const class GlobalMarking& m = *myNet.getInitMarking (); for (i = myNet.getNumPlaces (); i--; ) if (myNet.getPlace (i) && !myNet.getPlace (i)->isConstant ()) addPlaces (i, m[i]); class DummyReporter reporter (myNet, printer, maxerrors); for (i = myNet.getNumAllTransitions (); !interrupted && !reporter.isFatal () && i--; ) myNet.getTransition (i).unfold (*this, reporter); return !interrupted && !reporter.isFatal (); } unsigned LNet::getPlace (unsigned p, const class Value& value) const { assert (myBuf.empty ()); if (myPlaceBits) myBuf.append (p, myPlaceBits); myBuf.append (value); unsigned place = getPlace (myBuf.getBuf (), myBuf.getLength ()); myBuf.clear (); return place; } unsigned LNet::addPlace (unsigned p, const class Value& value) { assert (myBuf.empty ()); assert (myNet.getPlace (p) && !myNet.getPlace (p)->isConstant ()); if (myPlaceBits) myBuf.append (p, myPlaceBits); myBuf.append (value); unsigned length = myBuf.getNumWords (); word_t* placename = new word_t[length]; memcpy (placename, myBuf.getBuf (), length * sizeof *placename); length = myBuf.getLength (); myBuf.clear (); return addPlace (placename, length); } void LNet::addPlaces (unsigned place, const class PlaceMarking& p) { assert (myBuf.empty ()); assert (!p.getPlace ()->isConstant ()); if (p.empty ()) return; for (PlaceMarking::const_iterator i = p.begin (); i != p.end (); i++) { if (!i->second) continue; if (myPlaceBits) myBuf.append (place, myPlaceBits); myBuf.append (*i->first); unsigned length = myBuf.getNumWords (); word_t* placename = new word_t[length]; memcpy (placename, myBuf.getBuf (), length * sizeof *placename); addPlace (placename, myBuf.getLength ()); myBuf.clear (); } } void LNet::removeTransitions (unsigned t) { assert (t < myNet.getNumAllTransitions ()); rewind (myTransitions[t]); } bool LNet::addTransition (const struct ltrans& tr) { assert (tr.t < myNet.getNumAllTransitions ()); assert (!tr.datalen || tr.data); FILE* f = myTransitions[tr.t]; return tr.in.write (f) && tr.out.write (f) && 1 == fwrite (&tr.datalen, sizeof tr.datalen, 1, f) && tr.datalen == fwrite (tr.data, sizeof *tr.data, tr.datalen, f); } unsigned* LNet::unfold (const class GlobalMarking& m) const { assert (myBuf.empty ()); if (!myNumPlaces) return 0; unsigned* marking = new unsigned[myNumPlaces]; memset (marking, 0, myNumPlaces * sizeof * marking); for (unsigned i = m.getSize (); i--; ) { const class PlaceMarking& p = m[i]; if (p.empty () || p.getPlace ()->isConstant ()) continue; for (PlaceMarking::const_iterator pi = p.begin (); pi != p.end (); pi++) { if (myPlaceBits) myBuf.append (i, myPlaceBits); myBuf.append (*pi->first); unsigned lp = getPlace (myBuf.getBuf (), myBuf.getLength ()); myBuf.clear (); if (lp == UINT_MAX) { delete[] marking; return 0; } assert (lp < myNumPlaces); marking[lp] = pi->second; } } return marking; } class GlobalMarking& LNet::fold (const unsigned* marking) const { class GlobalMarking& m = *new class GlobalMarking (myNet); for (unsigned lp = myNumPlaces; lp--; ) { if (!marking[lp]) continue; class BitUnpacker buf (myPlaces[lp]); unsigned i = myPlaceBits ? buf.extract (myPlaceBits) : 0; class PlaceMarking& p = m[i]; p.add (*buf.extract (p.getPlace ()->getType ()), marking[lp]); } return m; } /** Read a low-level transition * @param t number of the high-level transition * @param f the input stream * @return a low-level transition, or NULL if end of stream */ static const struct LNet::ltrans* nextTransition (unsigned t, FILE* f) { static struct LNet::ltrans tr; tr.t = t; delete[] tr.data; tr.data = 0; if (!tr.in.read (f) || !tr.out.read (f) || 1 != fread (&tr.datalen, sizeof tr.datalen, 1, f)) return 0; tr.data = new word_t[tr.datalen]; return tr.datalen == fread (tr.data, sizeof *tr.data, tr.datalen, f) ? &tr : 0; } const class Place& LNet::getPlace (unsigned p) const { assert (p < myNumPlaces); class BitUnpacker buf (myPlaces[p]); return *myNet.getPlace (myPlaceBits ? buf.extract (myPlaceBits) : 0); } const class Place& LNet::displayPlace (class StringBuffer& out, unsigned p) const { assert (p < myNumPlaces); class BitUnpacker buf (myPlaces[p]); const class Place& place = *myNet.getPlace (myPlaceBits ? buf.extract (myPlaceBits) : 0); out.append ("PL_"); p = out.getLength (); out.append (place.getName ()); out.escape (p); if (place.getType ().getNumValues () > 1) { class Value* v = buf.extract (place.getType ()); out.append ('_', 2); p = out.getLength (); class Printer printer; printer.setOutput (&out); v->display (printer); delete v; out.escape (p); } return place; } void LNet::displayTransition (class StringBuffer& out, const struct ltrans& t) const { class BitUnpacker buf (t.data); const class Transition* transition; class Valuation valuation; myNet.decode (buf, transition, valuation, true); assert (transition == &myNet.getTransition (t.t)); out.append ("TR_"); unsigned i = out.getLength (); out.append (transition->getName ()); out.escape (i); valuation.displayEscaped (out); } void LNet::display (const class Printer& printer, const unsigned* marking) const { unsigned i; if (myNumPlaces && marking) { for (i = 0; i < myNumPlaces; i++) { if (!marking[i]) continue; class BitUnpacker buf (myPlaces[i]); const class Place& p = *myNet.getPlace (myPlaceBits ? buf.extract (myPlaceBits) : 0); printer.printRaw ("place "); printer.printQuoted (p.getName ()); printer.delimiter (':')++; class Value* v = buf.extract (p.getType ()); v->display (printer); delete v; printer--.finish (); } } for (unsigned tr = 0; tr < myNet.getNumAllTransitions (); tr++) { rewind (myTransitions[tr]); while (const struct ltrans* t = nextTransition (tr, myTransitions[tr])) { class BitUnpacker buf (t->data); const class Transition* transition; class Valuation valuation; myNet.decode (buf, transition, valuation, true); assert (transition == &myNet.getTransition (tr)); printer.printRaw ("trans "); printer.printQuoted (myNet.getTransition (tr).getName ()); valuation.display (printer); printer.linebreak (); printer.delimiter ('<')++; for (i = t->in.getNumPlaces (); i--; ) { class BitUnpacker pbuf (myPlaces[t->in.getPlace (i)]); const class Place& p = *myNet.getPlace (myPlaceBits ? pbuf.extract (myPlaceBits) : 0); printer.linebreak (); if (t->in.getWeight (i) != 1) { printer.print (t->in.getWeight (i)); printer.delimiter ('#'); } printer.printQuoted (p.getName ()); printer.delimiter (':'); class Value* v = pbuf.extract (p.getType ()); v->display (printer); delete v; } printer--.linebreak (); printer.delimiter ('>')++; for (i = t->out.getNumPlaces (); i--; ) { class BitUnpacker pbuf (myPlaces[t->out.getPlace (i)]); const class Place& p = *myNet.getPlace (myPlaceBits ? pbuf.extract (myPlaceBits) : 0); printer.linebreak (); if (t->out.getWeight (i) != 1) { printer.print (t->out.getWeight (i)); printer.delimiter ('#'); } printer.printQuoted (p.getName ()); printer.delimiter (':'); class Value* v = pbuf.extract (p.getType ()); v->display (printer); delete v; } printer--.finish (); } } } void LNet::toLoLA (FILE* file, const unsigned* marking) const { unsigned i; class StringBuffer out; /** flag: print a comma? */ bool comma; if (myNumPlaces) { out.append ("PLACE "); for (i = 0, comma = false; i < myNumPlaces; i++) { if (comma) out.append (',', 1); comma = true; displayPlace (out, i); } out.append (";\n"); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); } if (marking) { out.append ("MARKING "); for (i = 0, comma = false; i < myNumPlaces; i++) { if (!marking[i]) continue; if (comma) out.append (',', 1); comma = true; displayPlace (out, i); out.append (':', 1); out.append (marking[i]); } out.append (";\n"); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); } i = 0; for (unsigned tr = 0; tr < myNet.getNumAllTransitions (); tr++) { rewind (myTransitions[tr]); while (const struct ltrans* t = nextTransition (tr, myTransitions[tr])) { out.append ("TRANSITION "); displayTransition (out, *t); out.append ("\nCONSUME "); unsigned j; if ((j = t->in.getNumPlaces ())) { assert (j <= myNumPlaces); for (j--;;) { assert (t->in.getPlace (j) < myNumPlaces && t->in.getWeight (j) > 0); displayPlace (out, t->in.getPlace (j)); out.append (':', 1); out.append (t->in.getWeight (j)); if (!j--) break; out.append (',', 1); } } out.append (";\nPRODUCE "); if ((j = t->out.getNumPlaces ())) { assert (j <= myNumPlaces); for (j--;;) { assert (t->out.getPlace (j) < myNumPlaces && t->out.getWeight (j) > 0); displayPlace (out, t->out.getPlace (j)); out.append (':', 1); out.append (t->out.getWeight (j)); if (!j--) break; out.append (',', 1); } } out.append (";\n"); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); } } } void LNet::toPEP (FILE* file, const unsigned* marking) const { unsigned i, j; class StringBuffer out; fputs ("PEP\n" "PTNet\n" "FORMAT_N\n" "PL\n", file); for (i = 0; i < myNumPlaces; i++) { out.append (i + 1); out.append ('"', 1); const class Place& p = displayPlace (out, i); out.append ("\"0@0"); if (marking && marking[i]) { out.append ('M', 1), out.append (marking[i]); out.append ('m', 1), out.append (marking[i]); } if (const class Constraint* capacity = p.getCapacity ()) { out.append ('k', 1); class Printer printer; printer.setOutput (&out); capacity->getLastValue ().display (printer); } else out.append ("k-1"); out.append ('\n', 1); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); } fputs ("TR\n", file); unsigned tr; for (tr = i = 0; tr < myNet.getNumAllTransitions (); tr++) { rewind (myTransitions[tr]); while (const struct ltrans* t = nextTransition (tr, myTransitions[tr])) { out.append (++i); out.append ('"', 1); displayTransition (out, *t); out.append ("\"0@0\n"); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); } } fputs ("TP\n", file); for (tr = i = 0; tr < myNet.getNumAllTransitions (); tr++) { rewind (myTransitions[tr]); while (const struct ltrans* t = nextTransition (tr, myTransitions[tr])) { i++; for (j = t->out.getNumPlaces (); j--; ) { assert (t->out.getPlace (j) < myNumPlaces && t->out.getWeight (j) > 0); fprintf (file, "%u<%u", i, t->out.getPlace (j) + 1); if (t->out.getWeight (j) != 1) fprintf (file, "w%u", t->out.getWeight (j)); fputc ('\n', file); } } } fputs ("PT\n", file); for (tr = i = 0; tr < myNet.getNumAllTransitions (); tr++) { rewind (myTransitions[tr]); while (const struct ltrans* t = nextTransition (tr, myTransitions[tr])) { i++; for (j = t->in.getNumPlaces (); j--; ) { assert (t->in.getPlace (j) < myNumPlaces && t->in.getWeight (j) > 0); fprintf (file, "%u>%u", t->in.getPlace (j) + 1, i); if (t->in.getWeight (j) != 1) fprintf (file, "w%u", t->in.getWeight (j)); fputc ('\n', file); } } } } void LNet::toPROD (FILE* file, FILE* extfile, const unsigned* marking) const { bool comma; unsigned k; unsigned kt; unsigned ku; class StringBuffer out; /** Counter for low-level transitions */ size_t si = 0; /** Counter for high-level transitions */ unsigned tr; for (tr = 0; tr < myNet.getNumAllTransitions (); tr++) { rewind (myTransitions[tr]); while (nextTransition (tr, myTransitions[tr])) si++; rewind (myTransitions[tr]); } if (myNumPlaces) { for (unsigned vis = 0; vis < 2; vis++) { for (k = myNumPlaces, comma = false; k--;) { if (getPlace (k).isVisible () != !vis) { out.append ("#enum "); displayPlace (out, k); out.append ('\n', 1); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); comma = true; } } if (!comma) continue; fputs (vis ? "#place v" : "#place i", file); if (marking) { comma = false; for (k = 0; k < myNumPlaces; k++) { if (getPlace (k).isVisible () == !vis) continue; if (!marking[k]) continue; fputs (comma ? " \\\n + " : " \\\n mk ( ", file); comma = true; if (1 != marking[k]) fprintf (file, "%u ", marking[k]); out.append ("<. "); displayPlace (out, k); out.append (".>"); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); } fputs (comma ? " )\n" : "\n", file); } } } else if (!si) return; /** Visited and processed low-level transitions */ class BitVector visited (si), processed (si); fputs ("#place q\n" "extern unsigned long z[1];\n", file); fputs ("#include \"_enum.h\"\n" "unsigned long z[1] = { 0 };\n", extfile); for (unsigned pattern = 0;; pattern++) { /** number of low-level transitions skipped inside this transition */ unsigned ss = 0; const struct ltrans* t; for (tr = 0, si = 0; tr < myNet.getNumAllTransitions (); tr++) { for (ss = 0; (t = nextTransition (tr, myTransitions[tr])); ss++, si++) if (!visited.tset (si)) goto visit; rewind (myTransitions[tr]); } break; visit: struct ltrans u (*t); u.data = new word_t[u.datalen]; memcpy (u.data, t->data, u.datalen * sizeof *u.data); /** number of input places */ const unsigned uin = u.in.getNumPlaces (); /** number of visible input places */ unsigned vin = 0; for (k = uin; k--; ) if (getPlace (u.in.getPlace (k)).isVisible ()) vin++; /** number of output places */ const unsigned uout = u.out.getNumPlaces (); /** number of visible output places */ unsigned vout = 0; for (k = uout; k--; ) if (getPlace (u.out.getPlace (k)).isVisible ()) vout++; /** number of low-level transitions folded in this round */ unsigned n = 1; /** start and end index for the low-level transitions in this round */ size_t sa = si++, sb = 0; out.append ("#enum "); displayTransition (out, u); out.append ('\n', 1); /** start index of the high-level transition in this round */ unsigned ta = tr; assert (ta < myNet.getNumAllTransitions ()); for (; ta < myNet.getNumAllTransitions (); rewind (myTransitions[ta++])) { for (; (t = nextTransition (ta, myTransitions[ta])); si++) { if (visited[si]) continue; if (t->in.getNumPlaces () != uin) continue; for (k = 0, kt = 0; k < uin; k++) if (getPlace (t->in.getPlace (k)).isVisible ()) kt++; if (kt != vin) continue; if (uin > vin) { for (kt = 0, ku = 0; ; kt++, ku++) { while ((kt < uin) && getPlace (t->in.getPlace (kt)).isVisible ()) kt++; if (kt == uin) break; assert (ku < uin); while (getPlace (u.in.getPlace (ku)).isVisible ()) ku++, assert (ku < uin); if (t->in.getWeight (kt) != u.in.getWeight (ku)) break; } if (kt != uin) continue; } if (vin) { for (kt = 0, ku = 0; ; kt++, ku++) { while ((kt < uin) && !getPlace (t->in.getPlace (kt)).isVisible ()) kt++; if (kt == uin) break; assert (ku < uin); while (!getPlace (u.in.getPlace (ku)).isVisible ()) ku++, assert (ku < uin); if (t->in.getWeight (kt) != u.in.getWeight (ku)) break; } if (kt != uin) continue; } if (t->out.getNumPlaces () != uout) continue; for (k = 0, kt = 0; k < uout; k++) if (getPlace (t->out.getPlace (k)).isVisible ()) kt++; if (kt != vout) continue; if (uout > vout) { for (kt = 0, ku = 0; ; kt++, ku++) { while ((kt < uout) && getPlace (t->out.getPlace (kt)).isVisible ()) kt++; if (kt == uout) break; assert (ku < uout); while (getPlace (u.out.getPlace (ku)).isVisible ()) ku++, assert (ku < uout); if (t->out.getWeight (kt) != u.out.getWeight (ku)) break; } if (kt != uout) continue; } if (vout) { for (kt = 0, ku = 0; ; kt++, ku++) { while (kt < uout && !getPlace (t->out.getPlace (kt)).isVisible ()) kt++; if (kt == uout) break; assert (ku < uout); while (!getPlace (u.out.getPlace (ku)).isVisible ()) ku++, assert (ku < uout); if (t->out.getWeight (kt) != u.out.getWeight (ku)) break; } if (kt != uout) continue; } out.append ("#enum "); displayTransition (out, *t); out.append ('\n', 1); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); visited.assign (sb = si, true); n++; } } if (uout) { fprintf (file, "extern unsigned long y%u[%u][%u];\n", pattern, n, uout); fprintf (extfile, "unsigned long y%u[%u][%u] =\n", pattern, n, uout); } out.append ("#trans u"); out.append (pattern); out.append ("\nlet <. t"); for (k = 0; k < uin; k++) out.append (",\n x"), out.append (k); out.append (" .>\n"); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); // rewind the transition file while (ss--) if (!nextTransition (tr, myTransitions[tr])) assert (false); for (ta = tr, si = sa, comma = false; ta < myNet.getNumAllTransitions (); rewind (myTransitions[ta++])) { for (; (t = nextTransition (ta, myTransitions[ta])); si++) { if (!visited[si] || processed.tset (si)) continue; assert (t->in.getNumPlaces () == u.in.getNumPlaces ()); assert (t->out.getNumPlaces () == u.out.getNumPlaces ()); if (!comma) { comma = true; fputs (" <= ", file); if (uout) fputs ("{\n", extfile); } else fputs ("\n + ", file); if (uout) { out.append (" /* "); displayTransition (out, *t); out.append (" */\n { "); fwrite (out.getString (), 1, out.getLength (), extfile); out.create (0); } out.append ("<. "); displayTransition (out, *t); for (k = 0; k < uin; k++) { if (!getPlace (t->in.getPlace (k)).isVisible ()) { out.append (",\n "); displayPlace (out, t->in.getPlace (k)); } } for (k = 0; k < uin; k++) { if (getPlace (t->in.getPlace (k)).isVisible ()) { out.append (",\n "); displayPlace (out, t->in.getPlace (k)); } } out.append (" .>"); fwrite (out.getString (), 1, out.getLength (), file); out.create (0); if (!uout) continue; for (k = 0, kt = 0; k < uout; k++) { if (!getPlace (t->out.getPlace (k)).isVisible ()) { if (kt) out.append (" "); displayPlace (out, t->out.getPlace (k)); if (++kt < uout) out.append (",\n"); } } for (k = 0; k < uout; k++) { if (getPlace (t->out.getPlace (k)).isVisible ()) { if (kt) out.append (" "); displayPlace (out, t->out.getPlace (k)); if (++kt < uout) out.append (",\n"); } } out.append (" }"); fwrite (out.getString (), 1, out.getLength (), extfile); out.create (0); if (si != sb) fputs (",\n", extfile); else break; } } if (uout) fputs ("\n};\n", extfile); fputs (" ;\nin { q : ( z [ 0 ] ) <. t .> ;", file); if (uin > vin) { fputs ("\n i : ", file); for (k = 0, kt = 0; k < uin; k++) { if (!getPlace (u.in.getPlace (k)).isVisible ()) { if (kt) fputs ("\n + ", file); assert (0 < u.in.getWeight (k)); if (1 != u.in.getWeight (k)) fprintf (file, "%u ", u.in.getWeight (k)); fprintf (file, "<. x%u .>", kt); kt++; } } fputs (" ;", file); } if (vin) { fputs ("\n v : ", file); for (k = 0, kt = 0; k < uin; k++) { if (getPlace (u.in.getPlace (k)).isVisible ()) { if (kt) fputs ("\n + ", file); assert (0 < u.in.getWeight (k)); if (1 != u.in.getWeight (k)) fprintf (file, "%u ", u.in.getWeight (k)); fprintf (file, "<. x%u .>", kt + uin - vin); kt++; } } fputs (" ;", file); } fputs (" }\nout { q : ( z [ 0 ] ) <. t .> ;", file); if (uout > vout) { out.append ("\n i : "); for (k = 0, kt = 0; k < uout; k++) { if (!getPlace (u.out.getPlace (k)).isVisible ()) { if (kt) out.append ("\n + "); assert (0 < u.out.getWeight (k)); if (1 != u.out.getWeight (k)) out.append (u.out.getWeight (k)), out.append (' ', 1); out.append ("<. y"), out.append (pattern); out.append (" [ "); displayTransition (out, u); out.append (" - t ] [ "), out.append (kt++), out.append (" ] .>"); } } out.append (" ;"); } if (vout) { out.append ("\n v : "); for (k = 0, kt = 0; k < uout; k++) { if (getPlace (u.out.getPlace (k)).isVisible ()) { if (kt) out.append ("\n + "); assert (0 < u.out.getWeight (k)); if (1 != u.out.getWeight (k)) out.append (u.out.getWeight (k)), out.append (' ', 1); out.append ("<. y"), out.append (pattern); out.append (" [ "); displayTransition (out, u); out.append (" - t ] [ "); out.append (uout - vout + kt++); out.append (" ] .>"); } } out.append (" ;"); } fwrite (out.getString (), 1, out.getLength (), file); out.create (0); fputs (" }\n#endtr\n", file); delete[] u.data; } } maria-1.3.5/Net/GlobalMarking.C0000644000175000017500000001361207722411636016335 0ustar msmakelamsmakela// Global marking (PlaceMarking for each place) -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "GlobalMarking.h" #include "Net.h" #include "Place.h" #include "Valuation.h" #include "Marking.h" #include "LeafValue.h" #include /** @file GlobalMarking.C * Assignment of markings for each place */ /* Copyright © 1999-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ GlobalMarking::GlobalMarking (const class Net& net) : #ifndef NDEBUG myNet (net), #endif // NDEBUG myErroneous (false), mySize (net.getNumPlaces ()), myPlaceMarkings (mySize ? new class PlaceMarking[mySize] : 0) { for (unsigned i = mySize; i--; ) myPlaceMarkings[i].setPlace (net.getPlace (i)); } GlobalMarking::GlobalMarking (const class GlobalMarking& old) : #ifndef NDEBUG myNet (old.myNet), #endif // NDEBUG myErroneous (old.myErroneous), mySize (old.mySize), myPlaceMarkings (mySize ? new class PlaceMarking[mySize] : 0) { for (unsigned i = 0; i < mySize; i++) myPlaceMarkings[i] = old.myPlaceMarkings[i]; } class GlobalMarking& GlobalMarking::operator= (const class GlobalMarking& old) { assert (&myNet == &old.myNet); assert (mySize == old.mySize); myErroneous = old.myErroneous; for (unsigned i = 0; i < mySize; i++) myPlaceMarkings[i] = old.myPlaceMarkings[i]; return *this; } GlobalMarking::~GlobalMarking () { delete[] myPlaceMarkings; } class PlaceMarking& GlobalMarking::operator[] (const class Place& place) { assert (place.getIndex () < mySize); return myPlaceMarkings[place.getIndex ()]; } bool GlobalMarking::encode (class BitPacker& buf, const class GlobalMarking& m0, card_t* errorplace) const { // Clear the encoding buffer buf.clear (); /** Valuation for checking the consistency of implicit places */ class Valuation valuation; valuation.setGlobalMarking (this); // Encode each place marking in the global marking for (card_t i = mySize; i--; ) { /** Current place marking */ const class PlaceMarking& place = (*this)[i]; if (!place.getPlace ()) continue; if (place.getPlace ()->isConstant () ? m0[i] == place : place.encode (buf, &valuation)) continue; if (errorplace) *errorplace = i; return false; } // the buffer must not be empty if (!buf.getNumBytes ()) buf.append (0, 1); return true; } void GlobalMarking::encode (class BitPacker& buf, const class Net& net) const { assert (net.getParent () == &myNet); assert (net.getNumPlaces () <= mySize); // Clear the encoding buffer buf.clear (); for (card_t i = net.getNumPlaces (); i--; ) { if (const class Place* place = net.getPlace (i)) { if (!place->isConstant () && !(*this)[i].encode (buf, 0)) assert (false); // this GlobalMarking should have been valid } } // the buffer must not be empty if (!buf.getNumBytes ()) buf.append (0, 1); } unsigned GlobalMarking::decode (const class GlobalMarking& m0, const word_t* data, unsigned propBits) { card_t i; class BitUnpacker buf (data); // Decode each place marking in the global marking for (i = mySize; i--; ) { class PlaceMarking& p = (*this)[i]; if (p.getPlace ()) p.decode (buf); } computeImplicit (m0); return propBits ? buf.extract (propBits) : 0; } void GlobalMarking::decode (const class Net& net, const word_t* data) { assert (net.getParent () == &myNet); assert (net.getNumPlaces () <= mySize); class BitUnpacker buf (data); for (card_t i = net.getNumPlaces (); i--; ) { class PlaceMarking& p = (*this)[i]; if (net.getPlace (i)) { p.clear (); p.decode (buf); } } computeImplicit (*net.getParent ()->getInitMarking ()); } void GlobalMarking::computeImplicit (const class GlobalMarking& m0) { class Valuation valuation; valuation.setGlobalMarking (this); for (card_t i = 0; i < mySize; i++) { class PlaceMarking& p = (*this)[i]; if (const class Place* place = p.getPlace ()) { if (place->isConstant ()) p = m0[i]; else if (place->isImplicit ()) { const class Marking* expr = place->getInitMarking (); assert (!!expr); p.clear (); if (!expr->add (p, 1, valuation)) assert (false); } } } } bool GlobalMarking::eval (const class Expression& cond) const { class Valuation valuation; valuation.setGlobalMarking (this); bool holds = false; if (class Value* value = cond.eval (valuation)) { assert (value->getKind () == Value::vLeaf); assert (valuation.isOK ()); holds = bool (static_cast(*value)); delete value; } return holds; } #include "Printer.h" void GlobalMarking::display (const class Printer& printer) const { printer.printRaw (isErroneous () ? "erroneous state " : "state "); printer.delimiter ('(')++; for (unsigned i = 0; i < mySize; i++) { assert (myPlaceMarkings[i].getPlace () || myPlaceMarkings[i].empty ()); if (!myPlaceMarkings[i].empty () && !myPlaceMarkings[i].getPlace ()->isSuppressed ()) { printer.linebreak (); myPlaceMarkings[i].display (printer); } } printer--.linebreak (); printer.delimiter (')'); } maria-1.3.5/Net/GlobalMarking.h0000644000175000017500000001173207643247642016411 0ustar msmakelamsmakela// Global marking (PlaceMarking for each place) -*- c++ -*- #ifndef GLOBALMARKING_H_ # define GLOBALMARKING_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "PlaceMarking.h" # include "BitBuffer.h" /** @file GlobalMarking.h * Assignment of markings for each place */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class Net; /** Global marking (PlaceMarking for each place) */ class GlobalMarking { public: /** Constructor */ explicit GlobalMarking (const class Net& net); /** Copy constructor */ explicit GlobalMarking (const class GlobalMarking& old); /** Assignment operator */ class GlobalMarking& operator= (const class GlobalMarking& old); /** Destructor */ ~GlobalMarking (); # ifndef NDEBUG /** Get the net associated with the marking */ const class Net& getNet () const { return myNet; } # endif // NDEBUG /** Get the number of place markings */ unsigned getSize () const { return mySize; } /** Get a PlaceMarking by place number */ class PlaceMarking& operator[] (unsigned i) { assert (i < mySize); return myPlaceMarkings[i]; } /** Get a PlaceMarking by place number */ const class PlaceMarking& operator[] (unsigned i) const { return (*const_cast(this))[i]; } /** Get a PlaceMarking by place */ class PlaceMarking& operator[] (const class Place& place); /** Get a PlaceMarking by place */ const class PlaceMarking& operator[] (const class Place& place) const { return (*const_cast(this))[place]; } /** Flag the state erroneous */ void flagErroneous () { myErroneous = true; } /** Determine whether the state is erroneous */ bool isErroneous () const { return myErroneous; } #ifndef NDEBUG /** Equality comparison * @param other object to be compared with * @return true if the objects are equal */ bool operator== (const class GlobalMarking& other) const { assert (&myNet == &other.myNet && mySize == other.mySize); for (unsigned i = 0; i < mySize; i++) if (!(myPlaceMarkings[i] == other.myPlaceMarkings[i])) return false; return true; } #endif // NDEBUG /** Encode this marking * @param buf buffer to receive the encoded marking * @param m0 initial marking of the system * @param errorplace placeholder for the identity of an erroneous place * @return false in case of an integrity violation */ bool encode (class BitPacker& buf, const class GlobalMarking& m0, card_t* errorplace) const; /** Encode this marking to a subnet marking * @param buf buffer to receive the encoded marking * @param net the subnet */ void encode (class BitPacker& buf, const class Net& net) const; /** Decode a marking to this * @param m0 initial marking of the system * @param data the word-aligned encoded representation * @param propBits number of bits needed for presenting the property state * @return the property state number, or 0 if propBits == 0 */ unsigned decode (const class GlobalMarking& m0, const word_t* data, unsigned propBits = 0); /** Decode a subnet marking to this, replacing the place markings * @param net the subnet * @param data the word-aligned encoded representation */ void decode (const class Net& net, const word_t* data); /** Compute the markings of implicit places * @param m0 initial marking of the system */ void computeImplicit (const class GlobalMarking& m0); /** Evaluate a Boolean condition * @param cond the condition expression (state proposition) * @return true if the condition holds; false otherwise */ bool eval (const class Expression& cond) const; /** Display this object * @param printer The printer object */ void display (const class Printer& printer) const; private: # ifndef NDEBUG /** The net this marking belongs to */ const class Net& myNet; # endif // NDEBUG /** Flag: is the marking erroneous (is an erroneous transition enabled?) */ bool myErroneous; /** Number of place markings (or places in the net) */ unsigned mySize; /** The place markings */ class PlaceMarking* myPlaceMarkings; }; #endif // GLOBALMARKING_H_ maria-1.3.5/Net/LNet.h0000644000175000017500000002573307643247642014550 0ustar msmakelamsmakela// Low-level net class -*- c++ -*- #ifndef LNET_H_ # define LNET_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include # include # include # include "BitBuffer.h" /** @file LNet.h * Low-level (unfolded) net */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Low-level net class */ class LNet { public: /** Low-level arc */ class LArc { public: /** Constructor */ LArc () : myNumPlaces (0), myPlaces (0), myWeights (0) {} /** Copy constructor */ LArc (const class LArc& old) : myNumPlaces (old.myNumPlaces), myPlaces (0), myWeights (0) { myPlaces = new unsigned[myNumPlaces]; memcpy (myPlaces, old.myPlaces, myNumPlaces * sizeof *myPlaces); myWeights = new unsigned[myNumPlaces]; memcpy (myWeights, old.myWeights, myNumPlaces * sizeof *myWeights); } private: /** Assignment operator */ class LArc& operator= (const class LArc& old); public: /** Destructor */ ~LArc () { delete[] myPlaces; delete[] myWeights; } /** Add a place to the arc * @param place number of the place * @param weight weight of the place * @return true if the addition succeeded */ bool add (unsigned place, unsigned weight) { for (unsigned i = myNumPlaces; i--; ) { if (myPlaces[i] == place) { if (myWeights[i] >= UINT_MAX - weight) return false; myWeights[i] += weight; return true; } } unsigned* p = new unsigned[myNumPlaces + 1]; if (!p) return false; memcpy (p, myPlaces, myNumPlaces * sizeof *p); delete[] myPlaces; myPlaces = p; p = new unsigned[myNumPlaces + 1]; if (!p) return false; memcpy (p, myWeights, myNumPlaces * sizeof *p); delete[] myWeights; myWeights = p; myPlaces[myNumPlaces] = place; myWeights[myNumPlaces++] = weight; return true; } /** Unfold a high-level arc * @param lnet the low-level net * @param m the high-level arc * @return true if the operation succeeded */ bool unfold (class LNet& lnet, const class GlobalMarking& m); /** Read the arc from a file * @param f the input stream * @return true if the operation succeeded */ bool read (FILE *f); /** Write the arc to a file * @param f the output stream * @return true if the operation succeeded */ bool write (FILE *f) const; /** Get the number of places on the arc */ unsigned getNumPlaces () const { return myNumPlaces; } /** Get the number of a place on the arc */ unsigned getPlace (unsigned i) const { return myPlaces[i]; } /** Get the weight of a place on the arc */ unsigned getWeight (unsigned i) const { return myWeights[i]; } private: /** number of places */ unsigned myNumPlaces; /** index numbers of places */ unsigned* myPlaces; /** weights of places */ unsigned* myWeights; }; /** Low-level transition */ struct ltrans { /** number of the high level transition */ unsigned t; /** input and output arcs */ class LArc in, out; /** length of the encoded valuation in words */ size_t datalen; /** the encoded valuation */ word_t* data; }; /** Low-level place name */ struct lplace { /** default constructor */ lplace () : length (0), name (0) {} /** length of the name in bits */ unsigned length; /** the name */ word_t* name; }; /** Less-than comparison for low-level place names */ struct lplacecmp { /** Compare two low-level place names * @param p1 the first place name * @param p2 the second place name * @return true if p1 is less than p2 */ bool operator() (const struct lplace& p1, const struct lplace& p2) const { if (p1.length < p2.length) return true; if (p2.length < p1.length) return false; return 0 > memcmp (p1.name, p2.name, (p1.length + (sizeof (word_t) * CHAR_BIT) - 1) / (sizeof (word_t) * CHAR_BIT) * sizeof (word_t)); } }; /** Map from low-level place names to low-level place numbers */ typedef std::map PlaceMap; /** Iterator to the low-level place name map */ typedef PlaceMap::iterator iterator; /** Constant iterator to the low-level place name map */ typedef PlaceMap::const_iterator const_iterator; /** Constructor * @param net the corresponding high-level net */ explicit LNet (const class Net& net); private: /** Copy constructor */ explicit LNet (const class LNet& old); /** Assignment operator */ class LNet& operator= (const class LNet& old); public: /** Destructor */ ~LNet (); /** Get the corresponding high-level net */ const class Net& getNet () const { return myNet; } /** Get the number of generated low-level places */ unsigned getNumPlaces () const { return myNumPlaces; } /** Generate the unfolded net using a "coverable marking" algorithm * @param printer printer object for diagnostic output * @param maxerrors maximum number of allowed errors (0=infinity) * @return true if everything succeeded */ bool generateMinimal (const class Printer& printer, unsigned maxerrors); /** Generate the unfolded net * @param printer printer object for diagnostic output * @param maxerrors maximum number of allowed errors (0=infinity) * @return true if everything succeeded */ bool generate (const class Printer& printer, unsigned maxerrors); /** Add a place to the net * @param name name of the place * @param length length of the name in bits * @return number of the place */ unsigned addPlace (word_t* name, unsigned length) { struct lplace lp; lp.name = name; lp.length = length; std::pair p = myPlaceMap.insert (PlaceMap::value_type (lp, myNumPlaces)); if (p.second) { word_t** places = new word_t*[myNumPlaces + 1]; memcpy (places, myPlaces, myNumPlaces * sizeof *places); places[myNumPlaces] = name; delete[] myPlaces; myPlaces = places; return myNumPlaces++; } delete[] name; return p.first->second; } /** Add a place to the net * @param p number of the high-level place * @param value value of the high-level place * @return number of the low-level place */ unsigned addPlace (unsigned p, const class Value& value); /** Find a place in the net * @param name name of the place * @param length length of the name in bits * @return number of the place (UINT_MAX if not found) */ unsigned getPlace (const word_t* name, unsigned length) const { struct lplace lp; lp.name = const_cast(name); lp.length = length; const_iterator i = myPlaceMap.find (lp); return i == myPlaceMap.end () ? UINT_MAX : i->second; } /** Find a place in the net * @param p number of the high-level place * @param value value of the high-level place * @return number of the low-level place (UINT_MAX if not found) */ unsigned getPlace (unsigned p, const class Value& value) const; /** Introduce low-level places for each token in a high-level marking * @param place number of the high-level place * @param p the high-level marking (multiplicities set to 1) */ void addPlaces (unsigned place, const class PlaceMarking& p); /** Remove transitions generated from a high-level transition * @param t number of the high-level transition */ void removeTransitions (unsigned t); /** Add a transition to the net * @param tr the transition * @return true if the operation succeeded */ bool addTransition (const struct ltrans& tr); /** Unfold a high-level marking * @param m the high-level marking * @return the low-level marking (number of tokens in each place); * NULL if some low-level places do not exist */ unsigned* unfold (const class GlobalMarking& m) const; /** Fold a low-level marking * @param marking the low-level marking * @return the high-level marking */ class GlobalMarking& fold (const unsigned* marking) const; /** Get the high-level place corresponding to a low-level place * @param p index number of the low-level place * @return the originating high-level place */ const class Place& getPlace (unsigned p) const; /** Display a low-level place name * @param out the output stream * @param p index number of the low-level place * @return the originating high-level place */ const class Place& displayPlace (class StringBuffer& out, unsigned p) const; /** Display a low-level transition name * @param out the output stream * @param t the low-level transition */ void displayTransition (class StringBuffer& out, const struct ltrans& t) const; /** Display the net * @param printer the output stream * @param marking initial marking (number of tokens in each place) */ void display (const class Printer& printer, const unsigned* marking) const; /** Dump the net in LoLA format * @param file file to be dumped to * @param marking initial marking (number of tokens in each place) */ void toLoLA (FILE* file, const unsigned* marking) const; /** Dump the net in PEP format * @param file file to be dumped to * @param marking initial marking (number of tokens in each place) */ void toPEP (FILE* file, const unsigned* marking) const; /** Fold the net to special PROD format * @param file file to be dumped to * @param extfile file for external declarations (global data) * @param marking initial marking (number of tokens in each place) */ void toPROD (FILE* file, FILE* extfile, const unsigned* marking) const; private: /** The corresponding high-level net */ const class Net& myNet; /** Number of bits required for representing high-level places */ const unsigned myPlaceBits; /** Number of low-level places */ unsigned myNumPlaces; /** Map from low-level places to encoded high-level places and values */ word_t** myPlaces; /** Map from encoded high-level places and values to low-level places */ PlaceMap myPlaceMap; /** Buffer for converting place names */ mutable class BitPacker myBuf; /** Low-level transition files */ FILE** myTransitions; }; #endif // LNET_H_ maria-1.3.5/Net/Net.C0000644000175000017500000013622610065114170014344 0ustar msmakelamsmakela// Net class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Net.h" #include "Place.h" #include "Transition.h" #include "Arc.h" #include "Type.h" #include "BoolType.h" #include "IntType.h" #include "CardType.h" #include "CharType.h" #include "GlobalMarking.h" #include "Marking.h" #include "Constant.h" #include "Valuation.h" #include "VariableDefinition.h" #include "Function.h" #include "BooleanBinop.h" #include "PlaceContents.h" #include "LeafValue.h" #include "Quantifier.h" #include "Printer.h" #include "StateSet.h" #include "Property.h" #include "Dotty.h" /** @file Net.C * Nested modular algebraic system net */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** The predefined boolean type */ static class BoolType boolType; /** The predefined signed integer type */ static class IntType intType; /** The predefined unsigned integer type */ static class CardType cardType; /** The predefined character type */ static class CharType charType; /** Determine whether a type is predefined * @param type type to be checked * @return true if the type is predefined */ inline static bool isPredefinedType (const class Type* type) { return type == &boolType || type == &intType || type == &cardType || type == &charType; } /** Determine whether a state is fatally rejected * @param m the state * @param expr the rejection condition * @return the status of the check */ static enum Net::Status isFatal (const class GlobalMarking& m, const class Expression& expr) { class Valuation valuation; valuation.setGlobalMarking (&m); bool rejected = false; if (class Value* value = expr.eval (valuation)) { assert (value->getKind () == Value::vLeaf); rejected = bool (static_cast(*value)); delete value; if (!rejected) return Net::OK; } return rejected ? Net::Error : Net::Fatal; } Net::Net ( #ifdef EXPR_COMPILE unsigned ix, #endif // EXPR_COMPILE class Net* parent, unsigned parentix, char* name) : #ifdef EXPR_COMPILE myIndex (ix), myNumDescendents (0), myNumCompiled (0), #endif // EXPR_COMPILE myName (name), myParent (parent), myParentIndex (parentix), myNumChildren (0), myChildren (0), myMaxPriority (UINT_MAX), myNumPlaces (parent ? parent->myNumPlaces : 0), myPlaces (0), myNumTransitions (0), myNumAllTransitions (0), myTransitions (0), myNumCallees (0), myCallees (0), myFunctionMap (), myPlaceMap (), myTransitionMap (), myCalleeMap (), myTypeMap (), myTypeList (), myInitMarking (0), myReject (0), myDeadlock (0), myNumWeaklyFair (0), myNumStronglyFair (0), myNumMaxFair (0), myNumEnabled (0), myNumProps (0), myPropNames (0), myProps (0), myNumConstants (0), myConstantNames (0), myConstants (0) { if (myNumPlaces) { unsigned n; for (n = 1; n <= myNumPlaces; n <<= 1); myPlaces = new class Place*[n]; memset (myPlaces, 0, myNumPlaces * sizeof *myPlaces); } } Net::~Net () { unsigned i; for (i = myNumPlaces; i--; ) if (myPlaces[i] && &myPlaces[i]->getNet () != this) myPlaces[i] = 0; // clear references to places in child nets delete[] myName; for (i = myNumChildren; i--; ) delete myChildren[i]; delete[] myChildren; for (i = myNumPlaces; i--; ) if (myPlaces[i] && &myPlaces[i]->getNet () == this) delete myPlaces[i]; delete[] myPlaces; for (i = myNumTransitions; i--; ) delete myTransitions[i]; delete[] myTransitions; for (i = myNumCallees; i--; ) delete myCallees[i]; delete[] myCallees; for (FunctionMap::iterator f = myFunctionMap.begin (); f != myFunctionMap.end (); f++) delete f->second; for (TypeList::iterator t = myTypeList.begin (); t != myTypeList.end (); t++) { class Type* const type = *t; // do not delete types defined in parent nets for (const class Net* p = myParent; p; p = p->myParent) for (TypeList::const_iterator pt = p->myTypeList.begin (); pt != p->myTypeList.end (); pt++) if (*pt == type) goto notmytype; // do not delete predefined types if (!::isPredefinedType (type)) delete type; notmytype: continue; } delete myInitMarking; myReject->destroy (); myDeadlock->destroy (); for (i = myNumProps; i--; ) { delete[] myPropNames[i]; myProps[i]->destroy (); } delete[] myPropNames; delete[] myProps; for (i = myNumConstants; i--; ) { delete[] myConstantNames[i]; myConstants[i]->destroy (); } delete[] myConstantNames; delete[] myConstants; } class Net& Net::addChild (char* name) { if (!(myNumChildren & (myNumChildren + 1))) { class Net** n = new class Net*[(myNumChildren + 1) << 1]; memcpy (n, myChildren, sizeof (*myChildren) * myNumChildren); delete[] myChildren; myChildren = n; } #ifdef EXPR_COMPILE /** the root net */ class Net* root = this; while (root->myParent) root = root->myParent; #endif // EXPR_COMPILE myChildren[myNumChildren] = new class Net ( #ifdef EXPR_COMPILE ++root->myNumDescendents, #endif // EXPR_COMPILE this, myNumChildren, name); return *myChildren[myNumChildren++]; } void Net::addPlaces (const class Transition& t) { unsigned i; for (i = t.getNumInputs (); i--; ) { unsigned p = t.getInput (i).getPlace ().getIndex (); assert (p < myNumPlaces); assert (p < myParent->myNumPlaces); assert (!myPlaces[p] || myPlaces[p] == myParent->myPlaces[p]); myPlaces[p] = myParent->myPlaces[p]; } for (i = t.getNumOutputs (); i--; ) { unsigned p = t.getOutput (i).getPlace ().getIndex (); assert (p < myNumPlaces); assert (p < myParent->myNumPlaces); assert (!myPlaces[p] || myPlaces[p] == myParent->myPlaces[p]); myPlaces[p] = myParent->myPlaces[p]; } } void Net::addFunction (class Function& function) { assert (!getFunction (function.getName ())); myFunctionMap[function.getName ()] = &function; } bool Net::addConstraint (class Expression& qualifier, enum CKind kind) { unsigned id = UINT_MAX; switch (kind) { case Weak: id = myNumWeaklyFair; break; case Strong: id = myNumStronglyFair; break; case Enabled: id = myNumEnabled; break; } assert (id != UINT_MAX); if (qualifier.getKind () == Expression::eMarking) { class Valuation valuation; for (const class Marking* m = static_cast(qualifier).first (); m; m = m->next ()) { if (m->getMultiplicity (valuation)) { for (unsigned tr = myNumTransitions; tr--; ) { if (class Expression* expr = m->getToken ()->disqualify (*myTransitions[tr])) { switch (kind) { unsigned n; case Weak: case Strong: n = myTransitions[tr]->addFairness (*expr, id, kind == Strong); if (n > myNumMaxFair) myNumMaxFair = n; break; case Enabled: myTransitions[tr]->addEnabledness (*expr, id); break; } } } } else if (!valuation.isOK ()) { qualifier.destroy (); return false; } switch (kind) { case Weak: id = ++myNumWeaklyFair; break; case Strong: id = ++myNumStronglyFair; break; case Enabled: id = ++myNumEnabled; break; } } } else { for (unsigned tr = myNumTransitions; tr--; ) { if (class Expression* expr = qualifier.disqualify (*myTransitions[tr])) { switch (kind) { unsigned n; case Weak: case Strong: n = myTransitions[tr]->addFairness (*expr, id, kind == Strong); if (n > myNumMaxFair) myNumMaxFair = n; break; case Enabled: myTransitions[tr]->addEnabledness (*expr, id); break; } } } switch (kind) { case Weak: ++myNumWeaklyFair; break; case Strong: ++myNumStronglyFair; break; case Enabled: ++myNumEnabled; break; } } qualifier.destroy (); return true; } bool Net::addConstraint (class Expression& qualifier, class Transition& transition, enum CKind kind) { unsigned id = UINT_MAX; switch (kind) { case Weak: id = myNumWeaklyFair; break; case Strong: id = myNumStronglyFair; break; case Enabled: id = myNumEnabled; break; } assert (id != UINT_MAX); if (qualifier.getKind () == Expression::eMarking) { class Valuation valuation; for (const class Marking* m = static_cast(qualifier).first (); m; m = m->next ()) { if (m->getMultiplicity (valuation)) { if (class Expression* expr = m->getToken ()->disqualify (transition)) { switch (kind) { unsigned n; case Weak: case Strong: n = transition.addFairness (*expr, id, kind == Strong); if (n > myNumMaxFair) myNumMaxFair = n; break; case Enabled: transition.addEnabledness (*expr, id); break; } } } else if (!valuation.isOK ()) { qualifier.destroy (); return false; } switch (kind) { case Weak: id = ++myNumWeaklyFair; break; case Strong: id = ++myNumStronglyFair; break; case Enabled: id = ++myNumEnabled; break; } } qualifier.destroy (); } else { switch (kind) { unsigned n; case Weak: ++myNumWeaklyFair; goto fair; case Strong: ++myNumStronglyFair; fair: n = transition.addFairness (qualifier, id, kind == Strong); if (n > myNumMaxFair) myNumMaxFair = n; break; case Enabled: transition.addEnabledness (qualifier, id); ++myNumEnabled; break; } } return true; } static bool flagVisible (const class Expression& expr, void*) { if (expr.getKind () == Expression::ePlaceContents) const_cast(static_cast (expr).getPlace ()).flagVisible (); return true; } void Net::addReject (class Expression& expr) { assert (!expr.isTemporal ()); assert (expr.getKind () == Expression::eUndefined || expr.getType () && expr.getType ()->getKind () == Type::tBool); if (!expr.forExpressions (&::flagVisible, 0)) assert (false); if (myReject) myReject = BooleanBinop::construct (false, *myReject, expr); else myReject = &expr; } void Net::addDeadlock (class Expression& expr) { assert (!expr.isTemporal ()); assert (expr.getKind () == Expression::eUndefined || expr.getType () && expr.getType ()->getKind () == Type::tBool); if (!expr.forExpressions (&::flagVisible, 0)) assert (false); if (myDeadlock) myDeadlock = BooleanBinop::construct (false, *myDeadlock, expr); else myDeadlock = &expr; } class Place& Net::addPlace (char* name, class Constraint* capacity, const class Type& type) { assert (!myInitMarking); assert (name && myPlaceMap.find (name) == myPlaceMap.end ()); class Place* place = new class Place (*this, myNumPlaces, name, capacity, type); myPlaceMap[place->getName ()] = place; // copy the place also to the parent nets for (class Net* net = this; net; net = net->myParent) { if (!(net->myNumPlaces & (net->myNumPlaces + 1))) { class Place** p = new class Place*[(net->myNumPlaces + 1) << 1]; memcpy (p, net->myPlaces, sizeof (*net->myPlaces) * net->myNumPlaces); delete[] net->myPlaces; net->myPlaces = p; } net->myPlaces[net->myNumPlaces++] = place; } return *place; } class Transition& Net::addTransition (char* name, bool callee) { assert (!!name); assert (callee ? myCalleeMap.find (name) == myCalleeMap.end () : myTransitionMap.find (name) == myTransitionMap.end ()); assert (myNumTransitions == myNumAllTransitions); class Transition* transition = new class Transition (*this, callee ? myNumCallees : myNumTransitions, name); if (callee) { myCalleeMap.insert (TransitionMap::value_type (transition->getName (), transition)); if (!(myNumCallees & (myNumCallees + 1))) { class Transition** t = new class Transition*[(myNumCallees + 1) << 1]; memcpy (t, myCallees, sizeof (*myCallees) * myNumCallees); delete[] myCallees; myCallees = t; } return *(myCallees[myNumCallees++] = transition); } else { myTransitionMap.insert (TransitionMap::value_type (transition->getName (), transition)); if (!(myNumAllTransitions & (myNumAllTransitions + 1))) { class Transition** t = new class Transition*[(myNumAllTransitions + 1) << 1]; memcpy (t, myTransitions, sizeof (*myTransitions) * myNumAllTransitions); delete[] myTransitions; myTransitions = t; } myNumAllTransitions++; return *(myTransitions[myNumTransitions++] = transition); } } void Net::addType (class Type& t, char* name) { assert (!myInitMarking); class Type* type = &t; if (name) { if (type->getName ()) { assert (strcmp (type->getName (), name)); type = type->copy (); } type->setName (name); assert (myTypeMap.find (type->getName ()) == myTypeMap.end ()); myTypeMap[type->getName ()] = type; } if (!hasType (*type)) myTypeList.push_back (type); } bool Net::addProp (char* name, class Expression& prop) { assert (name && !prop.isTemporal ()); assert (prop.getType () && prop.getType ()->getKind () == Type::tBool); for (unsigned i = myNumProps; i--; ) if (!strcmp (name, myPropNames[i])) return false; if (!(myNumProps & (myNumProps + 1))) { char** propNames = new char*[(myNumProps + 1) << 1]; memcpy (propNames, myPropNames, myNumProps * sizeof *myPropNames); delete[] myPropNames; myPropNames = propNames; class Expression** props = new class Expression*[(myNumProps + 1) << 1]; memcpy (props, myProps, myNumProps * sizeof *myProps); delete[] myProps; myProps = props; } myPropNames[myNumProps] = name; myProps[myNumProps++] = ∝ return true; } bool Net::checkProps (const class GlobalMarking& m, bool (*operation) (unsigned, const void*), const void* data) const { if (myNumProps) { class Valuation valuation; valuation.setGlobalMarking (&m); bool hold; for (unsigned i = 0; i < myNumProps; i++) { if (class Value* value = myProps[i]->eval (valuation)) { assert (value->getKind () == Value::vLeaf); hold = bool (static_cast(*value)); delete value; if (hold && !(*operation) (i, data)) return false; } else valuation.clearErrors (); } } return true; } bool Net::addConstant (char* name, class Constant& constant) { assert (name && constant.getType () && !constant.getType ()->isLeaf ()); for (unsigned i = myNumConstants; i--; ) if (!strcmp (name, myConstantNames[i])) return false; if (!(myNumConstants & (myNumConstants + 1))) { char** constantNames = new char*[(myNumConstants + 1) << 1]; memcpy (constantNames, myConstantNames, myNumConstants * sizeof *myConstantNames); delete[] myConstantNames; myConstantNames = constantNames; class Constant** constants = new class Constant*[(myNumConstants + 1) << 1]; memcpy (constants, myConstants, myNumConstants * sizeof *myConstants); delete[] myConstants; myConstants = constants; } myConstantNames[myNumConstants] = name; myConstants[myNumConstants++] = &constant; return true; } const class Constant* Net::getConstant (const char* name) const { for (unsigned i = myNumConstants; i--; ) if (!strcmp (name, myConstantNames[i])) return myConstants[i]; return 0; } bool Net::addSyncTrans (const class Printer& printer) { /** flag: did the operation succeed? */ bool ok = true; unsigned i; if (myParent) { // copy the referred places from the parent nets for (i = myNumTransitions; i--; ) addPlaces (*myTransitions[i]); for (i = myNumCallees; i--; ) if (myCallees[i]->getNumChildren ()) addPlaces (*myCallees[i]); } // recursively process the subnets for (i = myNumChildren; i--; ) if (!myChildren[i]->addSyncTrans (printer)) ok = false; // adjust myUnif->place numbers in the synchronisation transitions if (myParent) for (i = myNumTransitions; ok && i--; ) if (myTransitions[i]->getNumParents () && !myTransitions[i]->isUnifiable (Transition::uIgnore, printer)) ok = false; // instantiate a transition for each synchronisation label /** buffer for instantiated transition names */ class StringBuffer name; for (i = myNumCallees; i--; ) { /** the callee transition */ const class Transition& t = *myCallees[i]; if (!t.getNumChildren ()) continue; // create an unique name name.create (0); name.append (':', 1), name.append (t.getName ()); // ensure that the name is unique if (myTransitionMap.find (name.getString ()) != myTransitionMap.end ()) { const unsigned namelen = name.getLength (); for (unsigned k = 0;; k++) { name.append (':', 1), name.append (k); if (myTransitionMap.find (name.getString ()) == myTransitionMap.end ()) break; name.chop (name.getLength () - namelen); } } /** the instantiated transition where all the children are fused */ class Transition& trans = addTransition (name.copy (), false); for (unsigned p = t.getNumParents (); p--; ) const_cast(t.getParent (p)).addChild (trans); unsigned k; for (k = 0; k < t.getNumChildren (); k++) { const class Transition& u = t.getChild (k); if (u.getLocalIndex () < u.getNet ()->myNumCallees && u.getNet ()->myCallees[u.getLocalIndex ()] == &u) continue; // do not fuse callee transitions in the child net // copy the arcs to the global synchronisation transition if (!trans.fuse (u, printer, true)) ok = false; else { class Transition& child = const_cast(u); trans.addChild (child); child.changeParent (t, trans); if (!child.isUnifiable (Transition::uRemove, printer)) ok = false; } } // see that the fused synchronisation transition is unifiable if (ok && !trans.isUnifiable (t.getNumParents () ? Transition::uIgnore : Transition::uNormal, printer)) ok = false; } return ok; } void Net::addLocalTransitions (class Net& root) const { assert (myParent && !root.myParent); unsigned i; for (i = 0; i < myNumTransitions; i++) { if (!myTransitions[i]->getNumParents ()) { // add the transition to the root net if (!(root.myNumAllTransitions & (root.myNumAllTransitions + 1))) { class Transition** t = new class Transition*[(root.myNumAllTransitions + 1) << 1]; memcpy (t, root.myTransitions, root.myNumAllTransitions * sizeof (*root.myTransitions)); delete[] root.myTransitions; root.myTransitions = t; } myTransitions[i]->setRootIndex (root.myNumAllTransitions); root.myTransitions[root.myNumAllTransitions++] = myTransitions[i]; } } for (i = 0; i < myNumChildren; i++) myChildren[i]->addLocalTransitions (root); } bool Net::prepareModular (const class Printer& printer) { assert (!myParent); if (!addSyncTrans (printer)) return false; for (unsigned i = 0; i < myNumChildren; i++) myChildren[i]->addLocalTransitions (*this); return true; } bool Net::computeInitMarking (const class Printer& printer) { bool ok = true; assert (!myInitMarking); if (myInitMarking) return ok; myInitMarking = new class GlobalMarking (*this); class Valuation v; unsigned i; // non-implicit places for (i = 0; i < myNumPlaces; i++) { if (const class Marking* m = myPlaces[i] ? myPlaces[i]->getInitMarking () : 0) { if (!myPlaces[i]->isImplicit ()) { v.clearErrors (); if (!m->add ((*myInitMarking)[i], 1u, v)) { assert (!v.isOK ()); printer.printRaw ("place "); printer.print (myPlaces[i]->getName ()); printer.printRaw (": error in the initial marking expression:"); printer.finish (); v.display (printer); printer.finish (); ok = false; } } } } // implicit places v.setGlobalMarking (myInitMarking); for (i = 0; i < myNumPlaces; i++) { if (const class Marking* m = myPlaces[i] ? myPlaces[i]->getInitMarking () : 0) { if (myPlaces[i]->isImplicit ()) { v.clearErrors (); if (!m->add ((*myInitMarking)[i], 1u, v)) { assert (!v.isOK ()); printer.printRaw ("place "); printer.print (myPlaces[i]->getName ()); printer.printRaw (": error in the initial marking expression:"); printer.finish (); v.display (printer); printer.finish (); ok = false; } } } } if (isReject (*myInitMarking, true)) ok = false; return ok; } const class BoolType& Net::getBoolType () { return boolType; } const class IntType& Net::getIntType () { return intType; } const class CardType& Net::getCardType () { return cardType; } const class CharType& Net::getCharType () { return charType; } enum Net::Status Net::isReject (const class GlobalMarking& m, bool flattened) const { enum Status status = myReject ? ::isFatal (m, *myReject) : OK; if (flattened && status != Fatal) { for (unsigned i = myNumChildren; i--; ) { switch (myChildren[i]->isReject (m, true)) { case Fatal: return Fatal; case Error: status = Error; case OK: break; } } } return status; } enum Net::Status Net::isDeadlock (const class GlobalMarking& m, bool flattened) const { enum Status status = myDeadlock ? ::isFatal (m, *myDeadlock) : OK; if (flattened && status != Fatal) { for (unsigned i = myNumChildren; i--; ) { switch (myChildren[i]->isDeadlock (m, true)) { case Fatal: return Fatal; case Error: status = Error; case OK: break; } } } return status; } bool Net::isPredefinedType (const class Type& type) { return ::isPredefinedType (&type); } void Net::encode (class BitPacker& buf, const class Transition& transition, const class Valuation& valuation, bool flattened) const { assert (flattened ? &getTransition (transition.getRootIndex ()) == &transition : &getTransition (transition.getLocalIndex ()) == &transition); assert (valuation.isOK ()); if (flattened && myNumAllTransitions > 1) buf.append (transition.getRootIndex (), log2 (myNumAllTransitions)); else if (myNumTransitions > 1) { assert (!flattened); buf.append (transition.getLocalIndex (), log2 (myNumTransitions)); } else assert (flattened ? myNumAllTransitions == 1 : myNumTransitions == 1); for (Transition::const_iterator i = transition.begin (); i != transition.end (); i++) { const class Value* value = valuation.getValue (*i->second); if (i->second->isUndefined ()) buf.append (!value, 1); else assert (!!value); if (value) buf.append (*value); } } void Net::decode (class BitUnpacker& buf, const class Transition*& transition, class Valuation& valuation, bool flattened) const { const unsigned numTransitions = flattened ? myNumAllTransitions : myNumTransitions; transition = &getTransition (numTransitions > 1 ? buf.extract (log2 (numTransitions)) : 0); for (Transition::const_iterator i = transition->begin (); i != transition->end (); i++) if (!i->second->isUndefined () || !buf.extract (1)) valuation.setValue (*i->second, *buf.extract (i->second->getType ())); } #ifdef EXPR_COMPILE # include "Compilation.h" # include "CExpression.h" /** Start generating a block specific to a child net and all its parents * @param out the output stream * @param indent indentation level * @param child the child net */ static void compileNetStart (class StringBuffer& out, unsigned& indent, const class Net& child) { out.indent (indent); out.append ("if (!net"); for (const class Net* n = &child; n->getParent (); n = n->getParent ()) { out.append (" ||\n"); out.indent (indent + 4); out.append ("net == "), out.append (n->getIndex ()); } out.append (") {\n"); indent += 2; } /** Finish generating a block specific to a child net and all its parents * @param out the output stream * @param indent indentation level */ static void compileNetEnd (class StringBuffer& out, unsigned& indent) { out.indent (indent -= 2); out.append ("}\n"); } void Net::compileEncoder (class CExpression& cexpr) const { unsigned i; class StringBuffer& out = cexpr.getOut (); class StringBuffer itemname; unsigned indent = 2; cexpr.setFatalError ("FREE(p); return *fatal=1, errFatal;\n"); if (myNumChildren) out.append (" if (flattened) net = 0;\n"); /** flag: are there any implicit places? */ bool hasImplicit = false; for (i = myNumPlaces; i--; ) { if (!myPlaces[i]->isImplicit ()) continue; if (!hasImplicit) { hasImplicit = true; out.append ("#ifndef NO_INVARIANT_CHECK\n" "# define NO_INVARIANT_CHECK(p) 0\n" "#endif\n"); out.indent (indent), out.append ("struct tree* p = 0;\n"); } out.append ("#if !NO_INVARIANT_CHECK("); out.append (i), out.append (")\n"); out.append ("# define ERROR(err){FREE(p);return err;}\n"); if (myNumChildren) ::compileNetStart (out, indent, myPlaces[i]->getNet ()); if (myPlaces[i]->getMaxNumTokens () == 1) { out.indent (indent); out.append ("{\n"); out.indent (indent += 2); myPlaces[i]->getType ().appendName (out); out.append ("* item;\n"); myPlaces[i]->getInitMarking ()->compileScalarMset (cexpr, indent, "item", 0, false); itemname.append ("(*"); itemname.append (cexpr.getMultiset ()); itemname.append (".p"); itemname.append (i); itemname.append (")"); if (!myPlaces[i]->getCapacityBits ()) { out.indent (indent); out.append ("if (!item)\n"); cexpr.compileError (indent + 2, errConst); } out.indent (indent); out.append ("if ("); if (myPlaces[i]->getCapacityBits ()) { out.append ("item != "); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (i); out.append (" &&\n"); out.indent (indent + 4); } if (!myPlaces[i]->getType (). compileEqual (out, indent + 4, "(*item)", itemname.getString (), false, true, true, false)) out.append ("0"); out.append (")\n"); cexpr.compileError (indent + 2, errComp); out.indent (indent -= 2); out.append ("}\n"); } else { itemname.append ("("); myPlaces[i]->getType ().appendMSetName (itemname); itemname.append ("*)"); myPlaces[i]->getInitMarking ()->compileMset (cexpr, indent, itemname.getString (), "p", 0); out.indent (indent); out.append ("if (!equal"); myPlaces[i]->getType ().appendIndex (out); out.append (" ("); out.append (itemname); out.append ("p, "); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (i); out.append ("))\n"); cexpr.compileError (indent + 2, errComp); } cexpr.compileCleanup (indent); itemname.create (0); if (myChildren) ::compileNetEnd (out, indent); out.append ("# undef ERROR\n" " FREE (p);\n" "#endif /* NO_INVARIANT_CHECK */\n"); } cexpr.setFatalError ("return *fatal=1, errFatal;\n"); out.indent (indent); out.append ("FCN (clear) ();\n"); for (i = myNumPlaces; i--; ) { if (myPlaces[i]->isImplicit ()) continue; if (myNumChildren) ::compileNetStart (out, indent, myPlaces[i]->getNet ()); out.append ("#define ERROR(err)return err\n"); if (myPlaces[i]->getMaxNumTokens () == 1) { out.indent (indent); out.append ("if (!"); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (i); out.append (")\n"); if (myPlaces[i]->getCapacityBits ()) { out.indent (indent + 2); out.append ("FCN (enc) (0, 1);\n"); out.indent (indent); out.append ("else {\n"); out.indent (indent += 2); out.append ("FCN (enc) (1, 1);\n"); } else cexpr.compileError (indent + 2, errConst); itemname.append ("(*"); itemname.append (cexpr.getMultiset ()); itemname.append (".p"); itemname.append (i); itemname.append (")"); myPlaces[i]->getType ().compileEncoder (cexpr, indent, "FCN (enc)", itemname.getString ()); itemname.create (0); if (myPlaces[i]->getCapacityBits ()) { out.indent (indent -= 2); out.append ("}\n"); } out.append ("#undef ERROR\n"); if (myChildren) ::compileNetEnd (out, indent); continue; } const char* total = cexpr.getVarTmpCount (); out.indent (indent); out.append (total); out.append (" = msort ("); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (i); out.append (");\n"); out.indent (indent); out.append ("if ("); out.append (total); out.append (" == CARD_T_MAX)\n"); cexpr.compileError (indent + 2, errCard); if (const class Constraint* c = myPlaces[i]->getCapacity ()) { c->compileCheck (cexpr, indent, total); if (unsigned cap = myPlaces[i]->getCapacityBits ()) { const char* number = cexpr.getVarCount (); if (cap > 2 && !myPlaces[i]->isNonempty ()) { out.indent (indent); out.append ("if ("), out.append (total), out.append (") {\n"); out.indent (indent + 2); out.append ("FCN (enc) (1, 1);\n"); CardType::compileConv (out, indent, *c, total, number); out.indent (indent + 2); out.append ("FCN (enc) ("), out.append (number), out.append (", "); out.append (cap), out.append (");\n"); out.indent (indent); out.append ("}\n"); out.indent (indent); out.append ("else FCN (enc) (0, 1);\n"); } else { CardType::compileConv (out, indent, *c, total, number); out.indent (indent); out.append ("FCN (enc) ("); out.append (number); out.append (", "); out.append (cap); out.append (");\n"); } } } else { out.indent (indent); out.append ("encc ("), out.append (total), out.append (");\n"); } out.indent (indent); out.append ("if ("), out.append (total), out.append (") {\n"); out.indent (indent + 2); out.append ("if ("), out.append (total); out.append (" > 1) FCN (enc) (distinct - 1, log2 ("); out.append (total), out.append ("));\n"); out.indent (indent + 2), out.append ("while (distinct--) {\n"); out.indent (indent + 4), out.append ("register card_t low = ("); out.append (total), out.append (" + distinct) / (distinct + 1);\n"); out.indent (indent + 4), out.append ("register card_t high = "); out.append (total), out.append (" - distinct;\n"); out.indent (indent + 4), out.append (total); out.append (" -= histogram[distinct]->count;\n"); out.indent (indent + 4), out.append ("if (high != low)\n"); out.indent (indent + 6); out.append ("FCN (enc) (histogram[distinct]->count - low, " "log2 (high - low + 1));\n"); itemname.append ("(("); myPlaces[i]->getType ().appendMSetName (itemname); itemname.append ("*)histogram[distinct])->item"); myPlaces[i]->getType ().compileEncoder (cexpr, indent + 4, "FCN (enc)", itemname.getString ()); itemname.create (0); out.indent (indent + 2); out.append ("}\n"); out.indent (indent); out.append ("}\n" "#undef ERROR\n"); if (myChildren) ::compileNetEnd (out, indent); } out.append (" if (propBits) {\n" " const unsigned* p = propSucc + *propSucc;\n" " const enum Error err = reject (net);\n" " for (;;) {\n" " FCN (enc) (*p, propBits);\n" " FCN (deflate) ();\n" " (*addstate) (ENCVAR (buf), NUM_BYTES (ENCVAR (bits)),\n" " err, tr, ftr, hide, ctx);\n" " if (--p <= propSucc || *intr || *fatal) break;\n" " FCN (inflate) (ENCVAR (buf), NUM_BYTES (ENCVAR (bits)));\n" " FCN (del) (propBits);\n" " }\n" " }\n" " else {\n" " FCN (deflate) ();\n" " (*addstate) (ENCVAR (buf), NUM_BYTES (ENCVAR (bits)),\n" " reject (net), tr, ftr, hide, ctx);\n" " }\n" " return errNone;\n"); cexpr.setFatalError (0); } void Net::compileDecoder (class CExpression& cexpr) const { unsigned i; class StringBuffer& out = cexpr.getOut (); unsigned indent = 2; /** flag: are there any implicit places? */ bool hasImplicit = false; class StringBuffer itemname; out.indent (indent); out.append ("FCN (inflate) ((word_t*) buf, size);\n"); for (i = myNumPlaces; i--; ) { if (myPlaces[i]->isImplicit ()) { hasImplicit = true; continue; } if (myNumChildren) ::compileNetStart (out, indent, myPlaces[i]->getNet ()); if (myPlaces[i]->getMaxNumTokens () == 1) { out.indent (indent); out.append ("free ("); out.append (cexpr.getMultiset ()), out.append (".p"), out.append (i); out.append ("); "); out.append (cexpr.getMultiset ()); out.append (".p"), out.append (i), out.append (" = 0;\n"); out.indent (indent); if (myPlaces[i]->getCapacityBits ()) { out.append ("if ((numTokens["), out.append (i); out.append ("]=FCN (dec) (1))) {\n"); out.indent (indent += 2); } else { out.append ("numTokens["), out.append (i), out.append ("]=1;\n"); out.indent (indent); } out.append (cexpr.getMultiset ()); out.append (".p"); out.append (i); out.append (" = malloc (sizeof ("); myPlaces[i]->getType ().appendName (out); out.append ("));\n"); itemname.append ("(*"); itemname.append (cexpr.getMultiset ()); itemname.append (".p"); itemname.append (i); itemname.append (")"); myPlaces[i]->getType ().compileDecoder (cexpr, indent, "FCN (dec)", itemname.getString ()); if (myPlaces[i]->getCapacityBits ()) { out.indent (indent -= 2); out.append ("}\n"); } itemname.create (0); if (myChildren) ::compileNetEnd (out, indent); continue; } const char* total = cexpr.getVarTmpCount (); if (const class Constraint* c = myPlaces[i]->getCapacity ()) { if (unsigned cap = myPlaces[i]->getCapacityBits ()) { const char* number = cexpr.getVarCount (); if (cap > 2 && !myPlaces[i]->isNonempty ()) { out.indent (indent), out.append ("if (FCN (dec) (1)) {\n"); out.indent (indent + 2); out.append (number); out.append (" = FCN (dec) ("), out.append (cap), out.append (");\n"); CardType::compileReverseConv (out, indent + 2, *c, number, total); out.indent (indent), out.append ("}\n"); out.indent (indent), out.append ("else\n"); out.indent (indent + 2), out.append (total), out.append (" = 0;\n"); } else { out.indent (indent); out.append (number); out.append (" = FCN (dec) ("), out.append (cap), out.append (");\n"); CardType::compileReverseConv (out, indent, *c, number, total); } } else { out.indent (indent), out.append (total), out.append (" = "); out.append (CardType::convert (0, *c)); out.append (";\n"); } } else out.indent (indent), out.append (total), out.append (" = decc ();\n"); out.indent (indent); out.append (" FREE ("); out.append (cexpr.getMultiset ()); out.append (".p"), out.append (i), out.append (");\n"); out.indent (indent); out.append ("if ((numTokens["), out.append (i); out.append ("]="), out.append (total), out.append (")) {\n"); out.indent (indent + 2); out.append ("for (distinct = "), out.append (total); out.append (" > 1 ? FCN (dec) (log2 ("), out.append (total); out.append (")) + 1 : 1;\n"); out.indent (indent + 7); out.append ("distinct--; ) {\n"); out.indent (indent + 4); myPlaces[i]->getType ().appendName (out); out.append (" item;\n"); out.indent (indent + 4), out.append ("register card_t low = ("); out.append (total), out.append (" + distinct) / (distinct + 1);\n"); out.indent (indent + 4), out.append ("register card_t high = "); out.append (total), out.append (" - distinct;\n"); out.indent (indent + 4); out.append ("register card_t amount = low != high\n"); out.indent (indent + 6); out.append ("? low + FCN (dec) (log2 (high - low + 1))\n"); out.indent (indent + 6); out.append (": low;\n"); out.indent (indent + 4), out.append (total), out.append (" -= amount;\n"); myPlaces[i]->getType ().compileDecoder (cexpr, indent + 4, "FCN (dec)", "item"); out.indent (indent + 4), out.append (cexpr.getMultiset ()); out.append (".p"), out.append (i); out.append (" = insert"), myPlaces[i]->getType ().appendIndex (out); out.append (" ("), out.append (cexpr.getMultiset ()); out.append (".p"), out.append (i); out.append (", &item, amount);\n"); out.indent (indent + 2); out.append ("}\n"); out.indent (indent); out.append ("}\n"); if (myChildren) ::compileNetEnd (out, indent); } if (hasImplicit) { out.append ("#define ERROR(err) abort ()\n"); for (i = 0; i < myNumPlaces; i++) { if (!myPlaces[i]->isImplicit ()) continue; if (myNumChildren) ::compileNetStart (out, indent, myPlaces[i]->getNet ()); itemname.append (cexpr.getMultiset ()); itemname.append (".p"), itemname.append (i); if (myPlaces[i]->getMaxNumTokens () == 1) { myPlaces[i]->getInitMarking ()-> compileScalarMset (cexpr, indent, itemname.getString (), 0, false); out.indent (indent); out.append ("if ((numTokens["), out.append (i), out.append ("]=!!"); out.append (itemname); out.append ("))\n"); out.indent (indent + 2); out.append (itemname); out.append (" = memcpy (malloc (sizeof *"); out.append (itemname); out.append ("), "); out.append (itemname); out.append (", sizeof *"); out.append (itemname); out.append (");\n"); if (!myPlaces[i]->getCapacityBits ()) { out.indent (indent); out.append ("else\n"); cexpr.compileError (indent + 2, errConst); } } else { myPlaces[i]->getInitMarking ()-> compileMset (cexpr, indent, 0, itemname.getString (), 0); out.indent (indent), out.append ("{\n"); out.indent (indent + 2), myPlaces[i]->getType ().appendMSetName (out); out.append ("* t = "), out.append (itemname), out.append (";\n"); out.indent (indent + 2); out.append ("FIRST (t);\n"); out.indent (indent + 2); out.append ("for (numTokens["), out.append (i), out.append ("]=0; "); out.append ("t; ) {\n"); out.indent (indent + 4); out.append ("numTokens["), out.append (i), out.append ("] += "); out.append (itemname), out.append ("->count;\n"); out.indent (indent + 4); out.append ("NEXT (t);\n"); out.indent (indent + 2); out.append ("}\n"); out.indent (indent); out.append ("}\n"); } cexpr.compileCleanup (indent); itemname.create (0); if (myChildren) ::compileNetEnd (out, indent); } out.append ("#undef ERROR\n"); } out.append (" if (propBits) *propSucc = FCN (dec) (propBits);\n"); } void Net::compileProjection (class CExpression& cexpr) const { unsigned i; class StringBuffer& out = cexpr.getOut (); class StringBuffer itemname; unsigned indent = 2; out.indent (indent); out.append ("FCN (clear) ();\n"); for (i = myNumPlaces; i--; ) { if (myPlaces[i]->isImplicit ()) continue; if (myNumChildren) ::compileNetStart (out, indent, myPlaces[i]->getNet ()); if (myPlaces[i]->getMaxNumTokens () == 1) { if (myPlaces[i]->getCapacityBits ()) { out.indent (indent); out.append ("if (!"); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (i); out.append (")\n"); out.indent (indent + 2); out.append ("FCN (enc) (0, 1);\n"); out.indent (indent); out.append ("else {\n"); out.indent (indent += 2); out.append ("FCN (enc) (1, 1);\n"); } itemname.append ("(*"); itemname.append (cexpr.getMultiset ()); itemname.append (".p"); itemname.append (i); itemname.append (")"); myPlaces[i]->getType ().compileEncoder (cexpr, indent, "FCN (enc)", itemname.getString ()); itemname.create (0); if (myPlaces[i]->getCapacityBits ()) { out.indent (indent -= 2); out.append ("}\n"); } if (myChildren) ::compileNetEnd (out, indent); continue; } const char* total = cexpr.getVarTmpCount (); out.indent (indent); out.append (total); out.append (" = msort ("); out.append (cexpr.getMultiset ()); out.append (".p"); out.append (i); out.append (");\n"); if (const class Constraint* c = myPlaces[i]->getCapacity ()) { if (unsigned cap = myPlaces[i]->getCapacityBits ()) { const char* number = cexpr.getVarCount (); if (cap > 2 && !myPlaces[i]->isNonempty ()) { out.indent (indent); out.append ("if ("), out.append (total), out.append (") {\n"); out.indent (indent + 2); out.append ("FCN (enc) (1, 1);\n"); CardType::compileConv (out, indent, *c, total, number); out.indent (indent + 2); out.append ("FCN (enc) ("), out.append (number), out.append (", "); out.append (cap), out.append (");\n"); out.indent (indent); out.append ("}\n"); out.indent (indent); out.append ("else FCN (enc) (0, 1);\n"); } else { CardType::compileConv (out, indent, *c, total, number); out.indent (indent); out.append ("FCN (enc) ("); out.append (number); out.append (", "); out.append (cap); out.append (");\n"); } } } else { out.indent (indent); out.append ("encc ("), out.append (total), out.append (");\n"); } out.indent (indent); out.append ("if ("), out.append (total), out.append (") {\n"); out.indent (indent + 2); out.append ("if ("), out.append (total); out.append (" > 1) FCN (enc) (distinct - 1, log2 ("); out.append (total), out.append ("));\n"); out.indent (indent + 2), out.append ("while (distinct--) {\n"); out.indent (indent + 4), out.append ("register card_t low = ("); out.append (total), out.append (" + distinct) / (distinct + 1);\n"); out.indent (indent + 4), out.append ("register card_t high = "); out.append (total), out.append (" - distinct;\n"); out.indent (indent + 4), out.append (total); out.append (" -= histogram[distinct]->count;\n"); out.indent (indent + 4), out.append ("if (high != low)\n"); out.indent (indent + 6); out.append ("FCN (enc) (histogram[distinct]->count - low, " "log2 (high - low + 1));\n"); itemname.append ("(("); myPlaces[i]->getType ().appendMSetName (itemname); itemname.append ("*)histogram[distinct])->item"); myPlaces[i]->getType ().compileEncoder (cexpr, indent + 4, "FCN (enc)", itemname.getString ()); itemname.create (0); out.indent (indent + 2); out.append ("}\n"); out.indent (indent); out.append ("}\n"); if (myChildren) ::compileNetEnd (out, indent); } out.append (" FCN (enc) (d, dbits);\n" " FCN (deflate) ();\n" " *size = NUM_BYTES (ENCVAR (bits));\n" " return ENCVAR (buf);\n"); } /** Compile a Boolean expression * @param cexpr the compilation * @param indent indentation level * @param expr the expression to be compiled */ inline static void compileExpression (class CExpression& cexpr, unsigned indent, const class Expression& expr) { class StringBuffer& out = cexpr.getOut (); out.append ("#define ERROR(err)return err\n"); const char* result = cexpr.getFlag (); expr.compile (cexpr, indent, result, 0); cexpr.compileCleanup (indent); out.append ("#undef ERROR\n"); out.indent (indent); out.append ("if ("); out.append (result); out.append (") return errComp;\n"); } void Net::compileReject (class CExpression& cexpr) const { class StringBuffer& out = cexpr.getOut (); unsigned indent = 2; if (myReject) { if (myParent || myNumChildren) ::compileNetStart (out, indent, *this); ::compileExpression (cexpr, indent, *myReject); if (myParent || myNumChildren) ::compileNetEnd (out, indent); } for (unsigned i = 0; i < myNumChildren; i++) myChildren[i]->compileReject (cexpr); if (!myParent) out.append (" return errNone;\n"); } void Net::compileDeadlock (class CExpression& cexpr) const { class StringBuffer& out = cexpr.getOut (); unsigned indent = 2; if (myDeadlock) { if (myParent || myNumChildren) ::compileNetStart (out, indent, *this); ::compileExpression (cexpr, indent, *myDeadlock); if (myParent || myNumChildren) ::compileNetEnd (out, indent); } for (unsigned i = 0; i < myNumChildren; i++) myChildren[i]->compileDeadlock (cexpr); if (!myParent) out.append (" return errNone;\n"); } void Net::compileProps (class CExpression& cexpr, const char* operation, const char* data) const { class StringBuffer& out = cexpr.getOut (); if (myNumProps) { out.append ("#define ERROR(err) continue\n"); for (unsigned i = 0; i < myNumProps; i++) { out.append (" do {\n"); const char* result = cexpr.getFlag (); myProps[i]->compile (cexpr, 4, result, 0); out.append (" if ("); out.append (result); out.append (" && !"); out.append (operation); out.append (" ("); out.append (i); out.append (", "); out.append (data); out.append (")) return 0;\n"); out.append (" } while (0);\n"); } cexpr.compileCleanup (2); out.append ("#undef ERROR\n"); } out.append (" return 1;\n"); } void Net::compileConstantDecl (class StringBuffer& out, const char* ext) const { class Printer printer; printer.setOutput (&out); for (unsigned i = 0; i < myNumConstants; i++) { if (ext) out.append (ext); else { out.append ("#if 0\n"); printer.printQuoted (myConstantNames[i]); out.append ("\n" "#endif\n"); } myConstants[i]->getType ()->appendName (out); out.append (" c"); out.append (i); out.append (";\n"); } } void Net::compileConstantInit (class StringBuffer& out) const { char name[22]; for (unsigned i = 0; i < myNumConstants; i++) { snprintf (name, sizeof name, "c%u", i); myConstants[i]->getValue ().compileInit (name, 2, out); } } #endif // EXPR_COMPILE void Net::display (const class Printer& printer) const { if (myName) { printer.printRaw ("/* net "); printer.printQuoted (myName); printer.printRaw ("*/"); printer.finish (); } for (TypeList::const_iterator t = myTypeList.begin (); t != myTypeList.end (); t++) { const class Type& type = **t; if (!type.getName ()) continue; printer.printRaw ("typedef "); type.display (printer); printer.delimiter (' '); printer.print (type.getName ()); printer.delimiter (';'); printer.finish (); } for (unsigned p = 0; p < myNumPlaces; p++) if (myPlaces[p]) myPlaces[p]->display (printer); for (unsigned tr = 0; tr < myNumTransitions; tr++) myTransitions[tr]->display (printer); if (myReject) { printer.printRaw ("reject "); myReject->display (printer); printer.delimiter (';'); printer.finish (); } if (myDeadlock) { printer.printRaw ("deadlock "); myDeadlock->display (printer); printer.delimiter (';'); printer.finish (); } for (unsigned prop = 0; prop < myNumProps; prop++) { printer.printRaw ("prop "); printer.print (myPropNames[prop]); printer.delimiter (':')++; myProps[prop]->display (printer); printer--; printer.delimiter (';'); printer.finish (); } } maria-1.3.5/Net/Net.h0000644000175000017500000004506207643247642014431 0ustar msmakelamsmakela// Net class -*- c++ -*- #ifndef NET_H_ # define NET_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include # include # include # include "util.h" # include "BitBuffer.h" /** @file Net.h * Nested modular algebraic system net */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Nested modular algebraic system net */ class Net { public: /** Map from names to functions */ typedef std::map FunctionMap; /** Map from names to places */ typedef std::map PlaceMap; /** Map from names to transitions */ typedef std::map TransitionMap; /** Map from names to data types */ typedef std::map TypeMap; /** List of all data types (named and nameless ones) */ typedef std::list TypeList; /** Constructor * @param ix index number (0 for root net) * @param parent parent net (optional) * @param parentix the child index number in the parent net * @param name the name of the net (optional) */ Net ( # ifdef EXPR_COMPILE unsigned ix = 0, # endif // EXPR_COMPILE class Net* parent = 0, unsigned parentix = 0, char* name = 0); private: /** Copy constructor */ Net (const class Net& old); /** Assignment operator */ class Net& operator= (const class Net& old); public: /** Destructor */ ~Net (); # ifdef EXPR_COMPILE /** Get the index number of this net */ unsigned getIndex () const { return myIndex; } /** Get the number of callee transitions in this net */ unsigned getNumCallees () const { return myNumCallees; } /** Get a callee transition by number */ class Transition& getCallee (unsigned i) const { assert (i < myNumCallees); return *myCallees[i]; } /** Get the number of compiled transitions */ unsigned getNumCompiled () const { return myNumCompiled; } /** Set the number of compiled transitions */ void setNumCompiled (unsigned n) const { assert (n >= myNumAllTransitions); myNumCompiled = n; } # endif // EXPR_COMPILE /** Get the optional name of this net */ const char* getName () const { return myName; } /** Get the parent of this net (0 if this is not a child net) */ class Net* getParent () { return myParent; } /** Get the parent of this net (0 if this is not a child net) */ const class Net* getParent () const { return myParent; } /** Get the index number of a child net in its parent */ unsigned getParentIndex () const { return myParentIndex; } /** Get the number of children in the net */ unsigned getNumChildren () const { return myNumChildren; } /** Get a child net by index */ const class Net& getChild (unsigned i) const { assert (i < myNumChildren); return *myChildren[i]; } /** Add a child net to this net * @param name optional name of the child net * @return a reference to the newly created subnet */ class Net& addChild (char* name); private: /** Import needed places from parent nets * @param t the transition to be processed */ void addPlaces (const class Transition& t); public: /** Get the highest available priority level */ unsigned getMaxPriority () { return --myMaxPriority; } /** Get a function definition by name * @param name Name of the function * @return The function definition */ class Function* getFunction (const char* name) { FunctionMap::const_iterator i = myFunctionMap.find (name); return i == myFunctionMap.end () ? NULL : i->second; } /** Add a function definition * @param function The function */ void addFunction (class Function& function); /** Fairness or enabledness constraint kind */ enum CKind { Weak, Strong, Enabled }; /** Add a fairness or enabledness constraint * @param qualifier transition qualifier expression * @param kind type of the constraint * @return true if everything succeeded */ bool addConstraint (class Expression& qualifier, enum CKind kind); /** Add a fairness or an enabledness constraint to a transition * @param qualifier transition instance qualifier expression * @param transition the transition * @param kind type of the constraint * @return true if everything succeeded */ bool addConstraint (class Expression& qualifier, class Transition& transition, enum CKind kind); /** Determine the number of weak fairness sets */ unsigned getNumWeaklyFair () const { return myNumWeaklyFair; } /** Determine the number of strong fairness sets */ unsigned getNumStronglyFair () const { return myNumStronglyFair; } /** Determine the maximum number of fairness constraints per transition */ unsigned getNumMaxFair () const { return myNumMaxFair; } /** Determine the number of enabledness sets */ unsigned getNumEnabled () const { return myNumEnabled; } /** Add a reject condition (assertion) * @param expr the reject condition */ void addReject (class Expression& expr); /** Add a deadlock monitor condition * @param expr the deadlock condition */ void addDeadlock (class Expression& expr); /** Get the reject condition */ class Expression* getReject () const { return myReject; } /** Get the deadlock condition */ class Expression* getDeadlock () const { return myDeadlock; } /** Get the number of places in the net */ unsigned getNumPlaces () const { return myNumPlaces; } /** Get a place * @param i Index number of the place */ const class Place* getPlace (unsigned i) const { assert(i < myNumPlaces); return myPlaces[i]; } /** Get a place * @param name Name of the place */ const class Place* getPlace (const char* name) const { PlaceMap::const_iterator i = myPlaceMap.find (name); return i == myPlaceMap.end () ? NULL : i->second; } /** Get the number of local transitions in the net */ unsigned getNumTransitions () const { return myNumTransitions; } /** Get the number of local and flattened transitions in the net */ unsigned getNumAllTransitions () const { return myNumAllTransitions; } /** Get a transition * @param i Index number of the transition */ const class Transition& getTransition (unsigned i) const { assert(i < myNumAllTransitions); return *myTransitions[i]; } /** Get a transition * @param name Name of the transition */ class Transition* getTransition (const char* name) { TransitionMap::const_iterator i = myTransitionMap.find (name); return i == myTransitionMap.end () ? NULL : i->second; } /** Get a callee * @param name name of the transition * @param except do not return this transition, search in parent instead * @return the transition, or 0 if not found */ class Transition* getCallee (const char* name, const class Transition* except) { for (const class Net* net = this;;) { TransitionMap::const_iterator i = net->myCalleeMap.find (name); if (i != net->myCalleeMap.end () && i->second != except) return i->second; else if (except && net == this && myParent) net = myParent; else break; } return 0; } /** Get a type * @param name Name of the type */ const class Type* getType (const char* name) const { TypeMap::const_iterator i = myTypeMap.find (name); return i == myTypeMap.end () ? NULL : i->second; } /** @name Accessors to the type list */ /*@{*/ TypeList::const_iterator begin () const { return myTypeList.begin (); } TypeList::const_iterator end () const { return myTypeList.end (); } /*@}*/ /** Determine whether the net contains a type * @param type Type to be sought * @return true if the net contains the type */ bool hasType (const class Type& type) const { for (TypeList::const_iterator i = begin (); i != end (); i++) if ((*i) == &type) return true; return false; } /** @name Accessors to the type name map */ /*@{*/ TypeMap::const_iterator beginTypename () const { return myTypeMap.begin (); } TypeMap::const_iterator endTypename () const { return myTypeMap.end (); } /*@}*/ /** Get the initial marking of the net */ const class GlobalMarking* getInitMarking () const { return myInitMarking; } /** Get the initial marking of the net */ class GlobalMarking* getInitMarking () { return myInitMarking; } /** Add a place to the net * @param name Name of the place * @param capacity Capacity constraint of the place * @param type Type of the place * @return reference to the place */ class Place& addPlace (char* name, class Constraint* capacity, const class Type& type); /** Add a transition to the net * @param name Name of the transition * @param callee Flag: is this a callee transition? * @return reference to the transition */ class Transition& addTransition (char* name, bool callee); /** Add a type to the net * @param type Type to be added * @param name Name of the type */ void addType (class Type& type, char* name = 0); /** Add a state proposition * @param name name of the state proposition * @param prop the state proposition * @return true if the proposition had a unique name */ bool addProp (char* name, class Expression& prop); /** Check the state propositions in a state * @param m the state * @param operation operation to invoke on propositions that hold * @param data extra data to pass to the operation * @return true if all operations succeeded */ bool checkProps (const class GlobalMarking& m, bool (*operation) (unsigned, const void*), const void* data) const; /** Get the number of state propositions */ unsigned getNumProps () const { return myNumProps; } /** Get the name of a state proposition * @param i index number of the state proposition * @return the name of the state proposition */ const char* getPropName (unsigned i) const { assert (i < myNumProps); return myPropNames[i]; } /** Get a state proposition * @param i index number of the state proposition * @return the state proposition */ const class Expression& getProp (unsigned i) const { assert (i < myNumProps); return *myProps[i]; } /** Add a constant * @param name name of the constant * @param constant the constant * @return true if the constant had a unique name */ bool addConstant (char* name, class Constant& constant); /** Retrieve a constant by name * @param name name of the constant * @return the constant, or NULL if none found */ const class Constant* getConstant (const char* name) const; /** Get the number of constants */ unsigned getNumConstants () const { return myNumConstants; } /** Get the name of a constant * @param i index number of the constant * @return the name of the constant */ const char* getConstantName (unsigned i) const { assert (i < myNumConstants); return myConstantNames[i]; } /** Get a constant * @param i index number of the constant * @return the constant */ const class Constant& getConstant (unsigned i) const { assert (i < myNumConstants); return *myConstants[i]; } private: /** Create fused transitions for all sync transitions in all subnets * @param printer The printer object for diagnostic output * @return true if the operation succeeded */ bool addSyncTrans (const class Printer& printer); /** Add local transitions to the flattened root net * @param root the root net */ void addLocalTransitions (class Net& root) const; public: /** Prepare a modular net for analysis * @param printer The printer object for diagnostic output * @return true if the system was successfully translated */ bool prepareModular (const class Printer& printer); /** Compute the initial marking of the net (@see getInitMarking) * @param printer The printer object for diagnostic output * @return true if the operation succeeded */ bool computeInitMarking (const class Printer& printer); /** Get the boolean type */ static const class BoolType& getBoolType (); /** Get the signed integer type */ static const class IntType& getIntType (); /** Get the unsigned integer type */ static const class CardType& getCardType (); /** Get the character type */ static const class CharType& getCharType (); /** Rejection or deadlock status */ enum Status { OK = 0, //< No error Error, //< Non-fatal error (report and continue the search) Fatal //< Fatal error (abort the search) }; /** Determine whether a state is rejected * @param m the state * @param flattened flag: consider the reject statements in subnets * @return true if the state is rejected */ enum Status isReject (const class GlobalMarking& m, bool flattend) const; /** Check and whethera a deadlock state should be reported * @param m the deadlock state * @param flattened flag: consider the deadlock statements in subnets * @return true if the deadlock should be reported */ enum Status isDeadlock (const class GlobalMarking& m, bool flattened) const; /** Determine whether a type is predefined * @param type type to be checked * @return true if the type is predefined */ static bool isPredefinedType (const class Type& type); /** Encode a transition instance * @param buf buffer for the encoded data * @param transition the high-level transition * @param valuation variable definitions * @param flattened consider the flattened net */ void encode (class BitPacker& buf, const class Transition& transition, const class Valuation& valuation, bool flattened) const; /** Decode a transition instance * @param buf the encoded data buffer * @param transition (output parameter) the transition * @param valuation (output parameter) the variable bindings * @param flattened consider the flattened net */ void decode (class BitUnpacker& buf, const class Transition*& transition, class Valuation& valuation, bool flattened) const; # ifdef EXPR_COMPILE /** Compile an encoding function * @param cexpr the compilation */ void compileEncoder (class CExpression& cexpr) const; /** Compile an decoding function * @param cexpr the compilation */ void compileDecoder (class CExpression& cexpr) const; /** Compile a projection function * @param cexpr the compilation */ void compileProjection (class CExpression& cexpr) const; /** Compile the reject tester formula * @param cexpr the compilation */ void compileReject (class CExpression& cexpr) const; /** Compile the deadlock tester formula * @param cexpr the compilation */ void compileDeadlock (class CExpression& cexpr) const; /** Compile the state properties * @param cexpr the compilation * @param operation name of the "operation" parameter * @param data name of the "data" parameter */ void compileProps (class CExpression& cexpr, const char* operation, const char* data) const; /** Compile constant declarations * @param out the output stream * @param ext the "extern" prefix, or NULL if this not a header entry */ void compileConstantDecl (class StringBuffer& out, const char* ext) const; /** Compile constant initializations * @param out the output stream */ void compileConstantInit (class StringBuffer& out) const; # endif // EXPR_COMPILE /** Display this net * @param printer the printer object */ void display (const class Printer& printer) const; private: # ifdef EXPR_COMPILE /** Index number of the net (0=parent) */ const unsigned myIndex; /** Number of descendent nets (for the root net) */ unsigned myNumDescendents; /** Number of compiled transitions (at least myNumAllTransitions) */ mutable unsigned myNumCompiled; # endif // EXPR_COMPILE /** Name of the net (for child nets) */ char* const myName; /** Parent net (for child nets) */ class Net* const myParent; /** Index in the parent (for child nets) */ const unsigned myParentIndex; /** Number of child nets */ unsigned myNumChildren; /** Child nets */ class Net** myChildren; /** Highest available priority level */ unsigned myMaxPriority; /** Number of places in the net */ unsigned myNumPlaces; /** Places in the net */ class Place** myPlaces; /** Number of transitions in the net */ unsigned myNumTransitions; /** Number of flattened transitions in the net */ unsigned myNumAllTransitions; /** Transitions in the net */ class Transition** myTransitions; /** Number of callee transitions in the net */ unsigned myNumCallees; /** Callee transitions in the net */ class Transition** myCallees; /** Functions indexed by name */ FunctionMap myFunctionMap; /** Places indexed by name */ PlaceMap myPlaceMap; /** Transitions indexed by name */ TransitionMap myTransitionMap; /** Callee transitions indexed by name */ TransitionMap myCalleeMap; /** Types indexed by name */ TypeMap myTypeMap; /** All types in the net (also nameless ones) */ TypeList myTypeList; /** Initial marking of the net */ class GlobalMarking* myInitMarking; /** Condition for reject tester */ class Expression* myReject; /** Condition for deadlock tester */ class Expression* myDeadlock; /** Number of weak fairness sets */ unsigned myNumWeaklyFair; /** Number of strong fairness sets */ unsigned myNumStronglyFair; /** Maximum number of fairness constraints per transition */ unsigned myNumMaxFair; /** Number of enabledness sets */ unsigned myNumEnabled; /** Number of state propositions */ unsigned myNumProps; /** Names of state propositions */ char** myPropNames; /** State propositions */ class Expression** myProps; /** Number of constants */ unsigned myNumConstants; /** Names of constants */ char** myConstantNames; /** Constants */ class Constant** myConstants; }; #endif // NET_H_ maria-1.3.5/Net/Place.C0000644000175000017500000000570707643247642014664 0ustar msmakelamsmakela// Place class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Place.h" #include "Constraint.h" #include "Arc.h" #include "Marking.h" #include "CardType.h" #include "LeafValue.h" #include "PlaceMarking.h" #include "Printer.h" #include "util.h" /** @file Place.C * Place in an algebraic system net */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Place::Place (const class Net& net, unsigned i, char* name, class Constraint* capacity, const class Type& type) : myNet (net), myIndex (i), myName (name), myCapacity (capacity), myCapacityBits (CARD_T_BIT), myType (&type), myInitMarking (0), myIsImplicit (false), myIsVisible (false), myIsNonempty (false), myIsConstant (false), myIsSuppressed (false), myMaxNumTokens (CARD_T_MAX) { if (myCapacity) { myCapacityBits = log2 (myCapacity->getNumValues ()); card_t n; if (!CardType::convert (n, 0, *myCapacity)) myIsNonempty = true; const class Value& v = myCapacity->getLastValue (); assert (v.getKind () == Value::vLeaf); myMaxNumTokens = card_t (static_cast(v)); } } Place::~Place () { delete[] myName; delete myCapacity; myInitMarking->destroy (); } void Place::setInitMarking (class Marking& initMarking) { assert (!myInitMarking && !myIsImplicit); myInitMarking = &initMarking; if ((myIsImplicit = myIsConstant)) return; class Valuation v; if (class PlaceMarking* p = myInitMarking->meval (v)) delete p; else myIsImplicit = true; } void Place::display (const class Printer& printer) const { printer.printRaw ("place"); printer.delimiter (' '); printer.print (myName); if (myCapacity) { printer.delimiter (' '); myCapacity->display (printer); } printer.delimiter (' '); if (const char* name = myType->getName ()) printer.print (name); else myType->display (printer); if (myIsConstant) { printer.delimiter (' '); printer.printRaw ("const"); } if (myInitMarking) { printer.delimiter (':'); myInitMarking->display (printer); } printer.delimiter (';'); printer.finish (); } maria-1.3.5/Net/Place.h0000644000175000017500000001116607643247642014725 0ustar msmakelamsmakela// Place class -*- c++ -*- #ifndef PLACE_H_ # define PLACE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "typedefs.h" /** @file Place.h * Place in an algebraic system net */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Place class */ class Place { protected: /** Constructor * @param net The net containing the place * @param i Index number of the place (ask Net) * @param name Name of the place * @param capacity Capacity constraint * @param type Type of the place */ Place (const class Net& net, unsigned i, char* name, class Constraint* capacity, const class Type& type); private: /** Copy constructor */ explicit Place (const class Place& old); /** Assignment operator */ class Place& operator= (const class Place& old); public: /** Destructor */ ~Place (); /** Get the net the place was created in */ const class Net& getNet () const { return myNet; } /** Get the index number of the place */ unsigned getIndex () const { return myIndex; } /** Get the name of the place */ const char* getName () const { return myName; } /** Get the type of the place */ const class Type& getType () const { return *myType; } /** Determine the capacity constraint */ const class Constraint* getCapacity () const { return myCapacity; } /** Determine the number of bits needed for storing the capacity */ unsigned getCapacityBits () const { return myCapacityBits; } /** Get the initial marking expression */ const class Marking* getInitMarking () const { return myInitMarking; } /** Set the initial marking expression */ void setInitMarking (class Marking& initMarking); /** Determine whether this is an implicit place */ bool isImplicit () const { return myIsImplicit; } /** Flag the place visible */ void flagVisible () { myIsVisible = true; } /** Determine whether this place is used in deadlock or reject formulae */ bool isVisible () const { return myIsVisible; } /** Determine whether the place is always nonempty */ bool isNonempty () const { return myIsNonempty; } /** Determine whether the place is constant */ bool isConstant () const { return myIsConstant; } /** Specify whether the place is constant */ void setConstant (bool constant) { myIsConstant = constant; } /** Determine whether the place is suppressed when displaying markings */ bool isSuppressed () const { return myIsSuppressed; } /** Specify whether the place is suppressed when displaying markings */ void setSuppressed (bool suppressed) const { myIsSuppressed = suppressed; } /** Determine the maximum number of tokens the place can contain */ card_t getMaxNumTokens () const { return myMaxNumTokens; } /** Display the place definition * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The net the place was created in */ const class Net& myNet; /** Index number of the place */ const unsigned myIndex; /** Name of the place */ char* myName; /** Capacity constraint */ class Constraint* myCapacity; /** Number of bits required to store the capacity */ unsigned myCapacityBits; /** Type of the place */ const class Type* myType; /** Initial marking of the place */ class Marking* myInitMarking; /** Flag: is this an implicit place */ bool myIsImplicit; /** Flag: is this place used in deadlock or reject formulae */ bool myIsVisible; /** Flag: is this place always nonempty */ bool myIsNonempty; /** Flag: is this place constant */ bool myIsConstant; /** Flag: is this place suppressed when displaying markings */ mutable bool myIsSuppressed; /** Number of tokens always contained in this place (0 if variable) */ card_t myMaxNumTokens; /** The constructor can only be called by Net */ friend class Net; }; #endif // PLACE_H_ maria-1.3.5/Net/PlaceMarking.C0000644000175000017500000002060207643247642016164 0ustar msmakelamsmakela// Place marking class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "PlaceMarking.h" #include "Place.h" #include "BitBuffer.h" #include "Marking.h" #include "CardType.h" #include #include /** @file PlaceMarking.C * Assignment of a place to a multi-set */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifndef NDEBUG void PlaceMarking::setPlace (const class Place* place) { assert (!place || !myPlace); if (place) setType (&place->getType ()); myPlace = place; } void PlaceMarking::setType (const class Type* type) { assert (!myPlace && !myType); myType = type; } #endif // NDEBUG bool PlaceMarking::add (class Value& value, card_t amount) { assert (myType->isConstrained (value)); assert (amount > 0); std::pair result = myTokens.insert (TokenMap::value_type (&value, amount)); if (!result.second) { delete &value; if (amount >= CARD_T_MAX - result.first->second) return false; result.first->second += amount; } return true; } void PlaceMarking::remove (const class Value& value, card_t amount) { assert (myType->isConstrained (value)); assert (amount > 0); iterator i = find (&value); assert (i != end ()); assert (i->second >= amount); i->second -= amount; } bool PlaceMarking::encode (class BitPacker& buf, const class Valuation* valuation) const { assert (myPlace && !myPlace->isConstant ()); if (myPlace->isImplicit ()) { if (!valuation) return true; const class Marking* marking = myPlace->getInitMarking (); assert (!!marking); class PlaceMarking p; p.setPlace (myPlace); return marking->add (p, 1, *valuation) && p == *this; } /** Number of distinct tokens */ size_t distinct = size (); /** Array of sorted cardinality,value pairs */ class card_value* histogram = distinct ? new class card_value[distinct] : 0; /** Total cardinality */ card_t total = distinct ? sort (histogram) : 0; if (total == CARD_T_MAX) { capacity: delete[] histogram; return false; } // Encode the total number of tokens if (const class Constraint* c = myPlace->getCapacity ()) { card_t n; if (!CardType::convert (n, total, *c)) goto capacity; if (unsigned cap = myPlace->getCapacityBits ()) { if (cap > 2 && !myPlace->isNonempty ()) { if (!total) goto empty; buf.append (1, 1); } buf.append (n, cap); } if (!total) goto none; } else { assert (!myPlace->isNonempty ()); // variable-length code: // 0 0 // 1..8 10xxx // 9..264 110xxxxxxxx // 265..65800 1110xxxxxxxxxxxxxxxx // 65801.. 1111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx if (!total) { empty: buf.append (0, 1); goto none; } else { buf.append (1, 1); if (total <= 8) buf.append (0, 1), buf.append (total - 1, 3); else { buf.append (1, 1); if (total <= 8 + 256) buf.append (0, 1), buf.append (total - (1 + 8), 8); else { buf.append (1, 1); if (total <= 8 + 256 + 65536) buf.append (0, 1), buf.append (total - (1 + 8 + 256), 16); else buf.append (1, 1), buf.append (total, CARD_T_BIT); } } } } // Encode the number of distinct tokens assert (distinct && distinct <= total); if (total > 1) buf.append (distinct - 1, log2 (total)); // Encode each distinct token in descending order of multiplicity while (distinct--) { // Encode the multiplicity (distinct has been decremented by one) assert (total >= distinct + 1); /** Lower multiplicity bound, inclusive */ const card_t low = (total + distinct) / (distinct + 1); /** Higher multiplicity bound, inclusive */ const card_t high = total - distinct; assert (low <= high); // Update the total cardinality of remaining tokens assert (total >= histogram[distinct].card); total -= histogram[distinct].card; assert (histogram[distinct].card >= low && histogram[distinct].card <= high); // Finally encode the multiplicity if (high != low) buf.append (histogram[distinct].card - low, log2 (high - low + 1)); // Encode the value buf.append (*histogram[distinct].value); } none: assert (!total); delete[] histogram; return true; } void PlaceMarking::decode (class BitUnpacker& buf) { assert (!!myPlace); if (myPlace->isImplicit () || myPlace->isConstant ()) return; /** Total cardinality */ card_t total; // Decode the total number of tokens if (const class Constraint* c = myPlace->getCapacity ()) { if (unsigned cap = myPlace->getCapacityBits ()) { if (cap > 2 && !myPlace->isNonempty () && !buf.extract (1)) return; total = CardType::convert (buf.extract (cap), *c); } else total = CardType::convert (0, *c); if (!total) return; } else { if (!buf.extract (1)) // 0: 0 return; else if (!buf.extract (1)) // 10xxx: 1..8 total = 1 + buf.extract (3); else if (!buf.extract (1)) // 110xxxxxxxx: 9..264 total = (1 + 8) + buf.extract (8); else if (!buf.extract (1)) // 1110xxxxxxxxxxxxxxxx: 265..65800 total = (1 + 8 + 256) + buf.extract (16); else { // 1111...: 65801.. total = buf.extract (CARD_T_BIT); assert (total > 8 + 256 + 65536); } } /** Number of distinct tokens */ card_t distinct = total > 1 ? buf.extract (log2 (total)) + 1 : 1; // Decode each distinct token in descending order of multiplicity while (distinct--) { // Decode the multiplicity (distinct has been decremented by one) assert (total >= distinct + 1); /** Lower multiplicity bound, inclusive */ const card_t low = (total + distinct) / (distinct + 1); /** Higher multiplicity bound, inclusive */ const card_t high = total - distinct; assert (low <= high); /** Multiplicity */ const card_t count = low != high ? buf.extract (log2 (high - low + 1)) + low : low; // Update the total cardinality of remaining tokens assert (total >= count); total -= count; // Decode the value if (!add (*buf.extract (myPlace->getType ()), count)) assert (false); } assert (!total); } #include "Printer.h" void PlaceMarking::display (const class Printer& printer) const { if (empty ()) return; if (myPlace) { printer.print (myPlace->getName ()); printer.delimiter (':')++; } bool comma = false; for (const_iterator i = myTokens.begin (); i != myTokens.end (); i++) { if (!i->second) continue; if (!comma) { if (myPlace) printer.linebreak (); comma = true; } else printer.delimiter (','); if (i->second > 1) { printer.print (i->second); printer.delimiter ('#'); } i->first->display (printer); } if (myPlace) printer--; } card_t PlaceMarking::sort (class PlaceMarking::card_value* histogram) const { assert (histogram && !empty ()); card_t total = 0; unsigned num = 0, pos = 0; for (const_iterator i = myTokens.begin (); i != myTokens.end (); i++, num++) { card_t card = i->second; if (!card) continue; if (total > CARD_T_MAX - card) return CARD_T_MAX; total += card; if (num) { for (unsigned low = 0, high = num; low != high; ) { pos = (low + high) >> 1; assert (pos < num && pos < high); if (histogram[pos].card > card) high = pos; else if (++pos == high) break; else { assert (high > pos); low = pos; } } memmove (histogram + pos + 1, histogram + pos, (num - pos) * sizeof *histogram); } histogram[pos] = card_value (card, i->first); } assert (num == size ()); return total; } maria-1.3.5/Net/PlaceMarking.h0000644000175000017500000003220707643247642016235 0ustar msmakelamsmakela// Place marking class -*- c++ -*- #ifndef PLACEMARKING_H_ # define PLACEMARKING_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Value.h" # include /** @file PlaceMarking.h * Assignment of a place to a multi-set */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Place marking */ class PlaceMarking { public: /** Comparison operator for values */ struct vcmp { /** Less-than comparison */ bool operator() (const class Value* v1, const class Value* v2) const { return *v1 < *v2; } }; /** The marking, mapping token values to non-zero multiplicities */ typedef std::map TokenMap; /** Iterator to the token map */ typedef TokenMap::iterator iterator; /** Constant iterator to the token map */ typedef TokenMap::const_iterator const_iterator; /** (cardinality,value) pair for sort () */ class card_value { public: /** Default constructor */ card_value () : card (0), value (0) {} /** Constructor * @param c cardinality * @param v value */ card_value (card_t c, const class Value* v) : card (c), value (v) { assert (c && v); } /** Copy constructor */ card_value (const class card_value& other) : card (other.card), value (other.value) {} /** Assignment operator */ class card_value& operator= (const class card_value& other) { card = other.card; value = other.value; return *this; } /** Destructor */ ~card_value () {} /** Three-way comparison * @param v1 first object * @param v2 second object * @return less than, equal to, or greater than zero */ static int cmp (const class card_value& v1, const class card_value& v2) { return v1.card - v2.card; } /** Cardinality */ card_t card; /** Value */ const class Value* value; }; /** Constructor */ PlaceMarking () : myPlace (NULL), # ifndef NDEBUG myType (NULL), # endif // NDEBUG myTokens () {} /** Copy constructor */ explicit PlaceMarking (const class PlaceMarking& old) : myPlace (old.myPlace), # ifndef NDEBUG myType (old.myType), # endif // NDEBUG myTokens () { for (const_iterator i = old.begin (); i != old.end (); i++) if (i->second) myTokens.insert (TokenMap::value_type (i->first->copy (), i->second)); } /** Assignment operator */ class PlaceMarking& operator= (const class PlaceMarking& other) { assert (!myPlace || myPlace == other.myPlace); myPlace = other.myPlace; assert (!myType || myType == other.myType); #ifndef NDEBUG myType = other.myType; #endif // NDEBUG clear (); for (const_iterator i = other.myTokens.begin (); i != other.myTokens.end (); i++) if (i->second) myTokens.insert (TokenMap::value_type (i->first->copy (), i->second)); return *this; } /** Destructor */ ~PlaceMarking () { for (const_iterator i = begin (); i != end (); i++) delete i->first; } /** Determine the Place associated with the PlaceMarking */ const class Place* getPlace () const { return myPlace; } # ifndef NDEBUG /** Set the Place associated with the PlaceMarking * @param place The place whose marking this is */ void setPlace (const class Place* place); /** Set the Type associated with the PlaceMarking * @param type The type of this marking */ void setType (const class Type* type); /** Determine the Type associated with the PlaceMarking */ const class Type* getType () const { return myType; } # else // NDEBUG void setPlace (const class Place* place) { myPlace = place; } # endif // NDEBUG /** Get the value of tokens pointed by an iterator * @param i an iterator pointing to the value */ static const class Value& getValue (const_iterator i) { return *i->first; } /** Get the number of tokens having the specified value * @param i an iterator pointing to the value */ static card_t getCount (const_iterator i) { return i->second; } /** Set the number of tokens having the specified value * @param i an iterator pointing to the value * @param cnt new count */ void setCount (iterator i, card_t cnt) { assert (i != end ()); assert (i->first && i->second); i->second = cnt; } /** Accessors to the token map */ /*@{*/ const_iterator begin () const { return myTokens.begin (); } const_iterator end () const { return myTokens.end (); } iterator begin () { return myTokens.begin (); } iterator end () { return myTokens.end (); } const_iterator find (const class Value* value) const { return myTokens.find (const_cast(value)); } iterator find (const class Value* value) { return myTokens.find (const_cast(value)); } size_t size () const { return myTokens.size (); } bool empty () const { return myTokens.empty (); } void clear () { for (const_iterator i = begin (); i != end (); i++) delete i->first; myTokens.clear (); } /*@}*/ /** Equality comparison * @param other multi-set to be compared with * @return true if the multi-sets are equal */ bool operator== (const class PlaceMarking& other) const { const_iterator i, j; assert (getType () == other.getType () || empty () || other.empty ()); for (i = begin (), j = other.begin (); i != end () && j != other.end (); i++, j++) { if (!i->second) while (++i != end ()) if (i->second) break; if (!j->second) while (++j != other.end ()) if (j->second) break; if (i == end () || j == other.end ()) break; assert (i->first && j->first); if (j->second != i->second || !(*j->first == *i->first)) return false; } if (i != end () && !i->second) while (++i != end ()) if (i->second) break; if (j != other.end () && !j->second) while (++j != other.end ()) if (j->second) break; return i == end () && j == other.end (); } /** Subset comparison * @param other a superset candidate * @return true if this is a subset of other */ bool operator<= (const class PlaceMarking& other) const { assert (getType () == other.getType () || empty () || other.empty ()); const_iterator i = begin (), j; if (i == end ()) return true; for (j = other.begin (); j != other.end (); j++) { if (!i->second) { while (++i != end ()) if (i->second) break; if (i == end ()) return true; } if (!j->second) { while (++j != other.end ()) if (j->second) break; if (j == other.end ()) break; } assert (i->first && j->first); if (*i->first < *j->first) return false; else if (*j->first < *i->first); else if (j->second < i->second) return false; else if (++i == end ()) return true; } if (!i->second) while (++i != end ()) if (i->second) break; return i == end (); } /** Subset comparison, ignoring multiplicities * @param other a superset candidate * @return true if this is a subset of other */ bool isSubset (const class PlaceMarking& other) const { assert (getType () == other.getType () || empty () || other.empty ()); const_iterator i = begin (), j; if (i == end ()) return true; for (j = other.begin (); j != other.end (); j++) { if (!i->second) { while (++i != end ()) if (i->second) break; if (i == end ()) return true; } if (!j->second) { while (++j != other.end ()) if (j->second) break; if (j == other.end ()) break; } assert (i->first && j->first); if (*i->first < *j->first) return false; else if (*j->first < *i->first); else if (++i == end ()) return true; } if (!i->second) while (++i != end ()) if (i->second) break; return i == end (); } /** Multiset intersection * @param other a set to be intersected with this * @return the intersection */ class PlaceMarking& operator&= (const class PlaceMarking& other) { assert (getType () == other.getType () || other.empty ()); iterator i; const_iterator j; for (j = other.begin (); j != other.end (); j++) if (j->second && (i = find (j->first)) != end () && i->second) if (i->second > j->second) i->second = j->second; for (i = begin (); i != end (); i++) if (i->second && (j = other.find (i->first)) == other.end ()) i->second = 0; return *this; } /** Multiset difference * @param other a set to be subtracted from this * @return the difference */ class PlaceMarking& operator-= (const class PlaceMarking& other) { assert (getType () == other.getType () || other.empty ()); iterator i; const_iterator j; for (j = other.begin (); j != other.end (); j++) { if (j->second && (i = find (j->first)) != end () && i->second) { if (i->second > j->second) i->second -= j->second; else i->second = 0; } } return *this; } /** Multiset union (or sum) * @param other a set to be added to this * @param count token multiplier * @return whether the operation this+=count*other succeeded */ bool add (const class PlaceMarking& other, card_t count) { assert (getType () == other.getType () || other.empty ()); assert (count > 0); for (const_iterator j = other.begin (); j != other.end (); j++) { card_t p = j->second; if (!p) continue; if (p >= CARD_T_MAX / count) return false; p *= count; class Value* v = j->first->copy (); std::pair result = myTokens.insert (TokenMap::value_type (v, p)); if (!result.second) { delete v; if (p >= CARD_T_MAX - result.first->second) return false; result.first->second += p; } } return true; } /** Set union (initialize all non-zero multiplicities to 1) * @param other a set to be added to this */ void setUnion (const class PlaceMarking& other) { assert (getType () == other.getType () || other.empty ()); for (const_iterator j = other.begin (); j != other.end (); j++) { if (!j->second) continue; class Value* v = j->first->copy (); std::pair result = myTokens.insert (TokenMap::value_type (v, 1)); if (!result.second) { delete v; result.first->second = 1; } } } /** Add a number of specified tokens to the place marking. * @param value Value of the tokens * @param amount Number of tokens to be added * @return false on cardinality overflow; normally true */ bool add (class Value& value, card_t amount); /** Remove a number of specified tokens from the place marking. * @param value Value of the tokens * @param amount Number of tokens to be removed */ void remove (const class Value& value, card_t amount); /** Remove a value from the place marking * @param i Iterator to the value to be removed */ void remove (iterator i) { assert (i != end () && i->second); i->second = 0; } /** Reserve a number of tokens having the specified value. * @param i Iterator to the value to be reserved * @param amount Amount of tokens to reserve */ void reserve (iterator i, card_t amount) { assert (i != end () && amount > 0); assert (i->second >= amount); i->second -= amount; } /** Free a number of previously reserved tokens * @param i Iterator to the value to be freed * @param amount Amount of tokens to be freed */ void free (iterator i, card_t amount) { assert (i != end () && amount > 0); assert (i->second <= CARD_T_MAX - amount); i->second += amount; } /** Encode this marking * @param buf buffer to receive the encoded marking * @param valuation valuation for verifying implicit places (optional) * @return false in case of an integrity violation */ bool encode (class BitPacker& buf, const class Valuation* valuation) const; /** Decode a marking to this * @param buf buffer containing the encoded marking */ void decode (class BitUnpacker& buf); /** Display this object * @param printer The printer object */ void display (const class Printer& printer) const; /** Sort the distinct values of the marking by multiplicity * @param histogram size()-element array for the results * @return total cardinality of the marking; CARD_T_MAX=overflow */ card_t sort (class card_value* histogram) const; private: /** The place */ const class Place* myPlace; # ifndef NDEBUG /** The type */ const class Type* myType; # endif // NDEBUG /** The tokens */ TokenMap myTokens; }; #endif // PLACEMARKING_H_ maria-1.3.5/Net/Transition.h0000644000175000017500000004312710232531627016020 0ustar msmakelamsmakela// Transition class -*- c++ -*- #ifndef TRANSITION_H_ # define TRANSITION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include # include # include # include "util.h" # include "Error.h" /** @file Transition.h * Transition in an algebraic system net */ /* Copyright © 1998-2003,2005 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Transition class */ class Transition { public: /** Kind of the transition */ enum Kind { tNormal = 0, //< Regular transition tUndefined, //< A safety assertion that does not abort analysis tFatal //< A safety assertion that aborts the analysis }; /** Actions for unifiability test */ enum Unif { uNormal = 0,//< Report variables that cannot be unified uIgnore, //< Ignore gates and outputs uRemove //< Remove gates depending on un-unifiable variables }; /** List of gate expressions */ typedef std::list GateList; /** Map from names to variables defined in the transition */ typedef std::map VariableMap; /** Iterator to the variable name map */ typedef VariableMap::iterator iterator; /** Constant iterator to the variable name map */ typedef VariableMap::const_iterator const_iterator; /** Map from names to functions defined in the transition */ typedef std::map FunctionMap; /** Constructor for anonymous transitions */ Transition (); /** Constructor * @param net the net this transition belongs to * @param i index number of the transition (in the net) * @param name name of the transition */ Transition (class Net& net, unsigned i, char* name); private: /** Copy constructor */ Transition (const class Transition& old); /** Assignment operator */ class Transition& operator= (const class Transition& old); public: /** Destructor */ ~Transition (); /** Get the net of the transition */ const class Net* getNet () const { return myNet; } /** Get the index number of the transition in the local net */ unsigned getLocalIndex () const { return myLocalIndex; } /** Get the index number of the transition in the root net */ unsigned getRootIndex () const { return myRootIndex; } /** Set the index number of the transition in the root net */ void setRootIndex (unsigned root) { myRootIndex = root; } /** Get the name of the transition */ const char* getName () const { return myName; } /** Get the number of parents (0 if this is not a sync transition) */ unsigned getNumParents () const { return myNumParents; } /** Get a parent of this transition by index number */ const class Transition& getParent (unsigned i) const { assert (i < myNumParents); return *myParents[i]; } # ifndef NDEBUG /** Determine whether the transition has a specific parent * @param parent parent transition to look for */ bool hasParent (const class Transition& parent) const; /** Determine whether the transition has a specific child * @param child child transition to look for */ bool hasChild (const class Transition& child) const; # endif // NDEBUG /** Change the parent transition to indicate synchronisation label * @param old the old parent transition * @param fused the new (fused) parent transition */ void changeParent (const class Transition& old, const class Transition& fused); /** Get the number of children the transition has */ unsigned getNumChildren () const { return myNumChildren; } /** Get a child transition by index number */ const class Transition& getChild (unsigned i) const { assert (i < myNumChildren); return *myChildren[i]; } /** Register a sync transition in a child net * @param child the child transition */ void addChild (class Transition& child); /** Get the priority level (0=none) */ unsigned getPriority () const { return myPriority; } /** Set the priority level (0=none) */ void setPriority (unsigned priority) { myPriority = priority; } /** Get the kind of the transition */ enum Kind getKind () const { return myKind; } /** Flag the transition an assertion * @param fatal flag: is this a fatal assertion? */ void setAssertion (bool fatal); /** Determine if a transition instance should be hidden * @param valuation the valuation */ bool isHidden (const class Valuation& valuation) const; /** Add an enabling condition (conjunct with existing condition) * @param gate the enabling condition */ void addGate (class Expression& gate); /** Add a hide condition (disjunct with existing condition) * @param qualifier the hiding condition */ void addHide (class Expression& qualifier); /** Add a fairness constraint * @param qualifier transition instance qualifier expression * @param id identifier of the fairness set * @param isStrong flag: is this a strong fairness constraint * @return number of fairness constraints */ unsigned addFairness (class Expression& qualifier, unsigned id, bool isStrong); /** Add an enabledness constraint * @param qualifier transition instance qualifier expression * @param id identifier of the enabledness set * @return number of fairness constraints */ unsigned addEnabledness (class Expression& qualifier, unsigned id); /** Get a variable by name * @param name Name of the variable * @return the VariableDefinition object; NULL if there is none */ const class VariableDefinition* getVariable (const char* name) const { const_iterator i = myVariables.find (name); return i != myVariables.end () ? i->second : NULL; } /** Determine whether a variable is present on any of the input arcs * @param variable variable to look for (NULL=PlaceContents) * @return true if it is an input variable */ bool isInput (const class VariableDefinition* variable) const; /** Determine whether a variable is present on any of the output arcs * @param variable variable to look for (NULL=PlaceContents) * @return true if it is an output variable */ bool isOutput (const class VariableDefinition* variable) const; /** Determine whether a variable is present on a gate expression * @param variable variable to look for (NULL=PlaceContents) * @return true if the variable is used in a gate expression */ bool isGate (const class VariableDefinition* variable) const; /** @name Accessors to the variable map */ /*@{*/ const_iterator begin () const { return myVariables.begin (); } const_iterator end () const { return myVariables.end (); } iterator begin () { return myVariables.begin (); } iterator end () { return myVariables.end (); } size_t size () const { return myVariables.size (); } /*@}*/ /** @name Accessors to the gate expression list */ /*@{*/ GateList::const_iterator beginG () const { return myGates.begin (); } GateList::const_iterator endG () const { return myGates.end (); } /*@}*/ /** Add an output variable * @param type Type of the variable * @param name Name of the variable (may be NULL) * @param expr Condition expression for the quantification * @return reference to the VariableDefinition object */ const class VariableDefinition& addOutputVariable (const class Type& type, char* name, class Expression* expr); /** Get the quantifier list for the output variables of the transition */ const class QuantifierList* getOutputVariables () const { return myOutputVariables; } /** Add a variable * @param name Name of the variable * @param type Type of the variable * @param aggregate flag: is this an output variable (quantifier)? * @param hidden flag: should the variable be hidden? * @return reference to the VariableDefinition object */ const class VariableDefinition& addVariable (char* name, const class Type& type, bool aggregate, bool hidden); /** Get a function definition by name * @param name Name of the function * @return The function definition */ class Function* getFunction (const char* name) { FunctionMap::const_iterator i = myFunctions.find (name); return i == myFunctions.end () ? NULL : i->second; } /** Add a function definition * @param function The function */ void addFunction (class Function& function); /** Check the gates * @param valuation Valuation for evaluating the gate expressions * @param err error code to accept (typically errVar or errNone) * @return true if the gates allow the transition to be fired */ bool checkGates (const class Valuation& valuation, enum Error err = errVar) const; /** Add an arc * @param arc The arc to be added */ void addArc (class Arc& arc); /** Determine whether the transition has an arc from/to a place * @param output specifies the type of arcs to look for * @param place identifies the place * @return the arc, or NULL */ class Arc* getArc (bool output, const class Place& place); /** Determine whether the transition has input arcs */ bool hasInputs () const { return myNumInputs != 0; } /** Determine whether the transition has output arcs */ bool hasOutputs () const { return myNumOutputs != 0; } /** Determine the number of input arcs */ unsigned getNumInputs () const { return myNumInputs; } /** Determine the number of output arcs */ unsigned getNumOutputs () const { return myNumOutputs; } /** Get an input arc * @param i index number of the arc */ const class Arc& getInput (unsigned i) const { assert (i < myNumInputs); return *myInputs[i]; } /** Get an output arc * @param i index number of the arc */ const class Arc& getOutput (unsigned i) const { assert (i < myNumOutputs); return *myOutputs[i]; } /** Determine the number of weak fairness sets the transition belongs to */ unsigned getNumWeaklyFair () const { return myNumWeaklyFair; } /** Determine the number of strong fairness sets the transition belongs to */ unsigned getNumStronglyFair () const { return myNumStronglyFair; } /** Determine the number of enabledness sets the transition belongs to */ unsigned getNumEnabled () const { return myNumEnabled; } /** Add a constant * @param name name of the constant * @param constant the constant * @return true if the constant had a unique name */ bool addConstant (char* name, class Constant& constant); /** Retrieve a constant by name * @param name name of the constant * @return the constant, or NULL if none found */ const class Constant* getConstant (const char* name) const; /** Get the number of constants */ unsigned getNumConstants () const { return myNumConstants; } /** Get the name of a constant * @param i index number of the constant * @return the name of the constant */ const char* getConstantName (unsigned i) const { assert (i < myNumConstants); return myConstantNames[i]; } /** Get a constant * @param i index number of the constant * @return the constant */ const class Constant& getConstant (unsigned i) const { assert (i < myNumConstants); return *myConstants[i]; } /** Fuse a callee transition to this one * @param callee the transition to be fused * @param printer the printer object for diagnostics * @param warn flag: issue warnings * @return true if the operation was successful */ bool fuse (const class Transition& callee, const class Printer& printer, bool warn); /** Determine whether the transition can be unified * @param action additional actions to take * @param printer the printer object for diagnostics * @return true if the transition can be unified */ bool isUnifiable (enum Unif action, const class Printer& printer); /** Determine all enabled instances of the transition for a marking * @param m the marking to be analyzed * @param reporter the interface for reporting successors or errors */ void analyze (class GlobalMarking& m, class StateReporter& reporter) const; /** Report a rejected successor state * @param valuation the transition binding * @param marking the erroneous successor state * @param reason reason for failure (optional) * @param place the place whose marking could not be encoded (optional) * @param printer the output stream for the message */ void report (const class Valuation& valuation, const class GlobalMarking& marking, const char* reason, const class Place* place, const class Printer& printer) const; /** Display an edge to a successor state * @param valuation the transition binding * @param marking the successor state * @param printer the output stream for the message */ void displayEdge (const class Valuation& valuation, const class GlobalMarking& marking, const class Printer& printer) const; /** Unfold the transition with the help of a coverable marking * @param cover (input/output) the coverable marking * @param lnet the low-level net being generated * @param reporter the reporting interface */ void unfold (class GlobalMarking& cover, class LNet& lnet, class DummyReporter& reporter) const; /** Unfold the transition by iterating the variable domains * @param lnet the low-level net being generated * @param reporter the reporting interface */ void unfold (class LNet& lnet, class DummyReporter& reporter) const; /** Determine which weak fairness sets a transition instance belongs to * @param valuation variable substitutions * @param sets (output) sets[1..*sets]: weak fairness sets */ void computeWeaklyFair (const class Valuation& valuation, unsigned* sets) const; /** Determine which strong fairness sets a transition instance belongs to * @param valuation variable substitutions * @param sets (output) sets[1..*sets]: strong fairness sets */ void computeStronglyFair (const class Valuation& valuation, unsigned* sets) const; /** Log the enabled enabledness sets * @param valuation variable substitutions * @param log the enabledness sets */ void logEnabled (const class Valuation& valuation, char* log) const; # ifdef EXPR_COMPILE private: /** Compile transition instance analysis * @param cexpr compilation output * @param inputPlaces the input places * @param numOptVars number of optional variables */ void compileAnalysis (class CExpression& cexpr, const std::list& inputPlaces, unsigned numOptVars) const; public: /** Compile the expressions of the transition * @param out the output stream */ void compile (class StringBuffer& out) const; # endif // EXPR_COMPILE /** Display the transition definition * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The net this transition belongs to */ class Net* myNet; /** Index number of the transition in myNet */ unsigned myLocalIndex; /** Index number of the transition in the root net */ unsigned myRootIndex; /** Name of the transition */ char* myName; /** Number of parent transitions */ unsigned myNumParents; /** Parent transitions (for transitions in child nets) */ const class Transition** myParents; /** Number of child transitions */ unsigned myNumChildren; /** Child transitions in child nets */ const class Transition** myChildren; /** Priority level (0=none) */ unsigned myPriority; /** Kind of the transition */ enum Kind myKind; /** Number of input arcs */ unsigned myNumInputs; /** Input arcs */ class Arc** myInputs; /** Number of output arcs */ unsigned myNumOutputs; /** Output arcs */ class Arc** myOutputs; /** Flag: do the outputs depend on the input marking? */ bool myOutputMarking; /** List of tokens to be unified */ struct unif* myUnif; /** Number of weak fairness sets */ unsigned myNumWeaklyFair; /** Number of strong fairness sets */ unsigned myNumStronglyFair; /** Number of enabledness sets */ unsigned myNumEnabled; /** Weak fairness conditions */ class Expression** myWeaklyFairCond; /** Strong fairness conditions */ class Expression** myStronglyFairCond; /** Enabledness conditions */ class Expression** myEnabledCond; /** Weak fairness sets */ unsigned* myWeaklyFairSet; /** Strong fairness sets */ unsigned* myStronglyFairSet; /** Enabledness sets */ unsigned* myEnabledSet; /** Gate expressions */ GateList myGates; /** Hiding condition */ class Expression* myHide; /** Output variables */ class QuantifierList* myOutputVariables; /** Transition variables indexed by name */ VariableMap myVariables; /** Functions indexed by name */ FunctionMap myFunctions; /** Number of constants */ unsigned myNumConstants; /** Names of constants */ char** myConstantNames; /** Constants */ class Constant** myConstants; }; #endif // TRANSITION_H_ maria-1.3.5/Net/VariableDefinition.C0000644000175000017500000000652207643247643017373 0ustar msmakelamsmakela// Variable definition class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "VariableDefinition.h" #include "Marking.h" #include "VectorType.h" #include "VectorValue.h" #include "StructType.h" #include "StructValue.h" #include "UnionType.h" #include "UnionValue.h" #include #include "util.h" /** @file VariableDefinition.C * A variable that can be assigned a value in a Valuation */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ VariableDefinition::VariableDefinition () : myName (0), myType (0), myIsAggregate (false), myIsUndefined (false), myIsReferenced (false), myIsHidden (false), #ifdef EXPR_COMPILE myNumber (0), #endif // EXPR_COMPILE myChildMap (), myFather (0) { } VariableDefinition::VariableDefinition (char* name, const class Type& type, bool aggregate, bool hidden) : myName (name), myType (&type), myIsAggregate (aggregate), myIsUndefined (false), myIsReferenced (false), myIsHidden (hidden), #ifdef EXPR_COMPILE myNumber (0), #endif // EXPR_COMPILE myChildMap (), myFather (0) { assert (myName && myType); } VariableDefinition::VariableDefinition (const class VariableDefinition& old) : myName (old.myName ? newString (old.myName) : 0), myType (old.myType), myIsAggregate (old.myIsAggregate), myIsUndefined (old.myIsUndefined), myIsReferenced (old.myIsReferenced), myIsHidden (old.myIsHidden), #ifdef EXPR_COMPILE myNumber (0), #endif // EXPR_COMPILE myChildMap (), myFather (0) { #ifdef EXPR_COMPILE assert (!old.myNumber); #endif // EXPR_COMPILE } VariableDefinition::~VariableDefinition () { delete[] myName; for (ChildMap::iterator i = myChildMap.begin (); i != myChildMap.end (); i++) delete i->second; } const class VariableDefinition* VariableDefinition::findChild (const char* name) const { assert (isAggregate ()); ChildMap::const_iterator i = myChildMap.find (const_cast(name)); return i == myChildMap.end () ? 0 : i->second; } const class VariableDefinition* VariableDefinition::addChild (char* name, const class Type& type) const { assert (isAggregate ()); ChildMap::iterator i = myChildMap.find (name); class VariableDefinition* child; if (i == myChildMap.end ()) { child = new class VariableDefinition (name, type, false, myIsHidden); child->myFather = this; myChildMap.insert (ChildMap::value_type (name, child)); return child; } else { child = i->second; delete[] name; if (child->myType != &type) return 0; return child; } } maria-1.3.5/Net/VariableDefinition.h0000644000175000017500000001102407643247643017431 0ustar msmakelamsmakela// Variable definition class -*- c++ -*- #ifndef VARIABLEDEFINITION_H_ # define VARIABLEDEFINITION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include "typedefs.h" /** @file VariableDefinition.h * A variable that can be assigned a value in a Valuation */ /* Copyright © 1999-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Variable definition */ class VariableDefinition { public: /** Map of quantifier variables associated with an aggregate variable */ typedef std::map ChildMap; /** Default constructor */ VariableDefinition (); /** Constructor * @param name Name of the variable * @param type Type of the variable * @param aggregate Flag: is this an aggregate variable (quantifier) * @param hidden Flag: is the variable hidden */ VariableDefinition (char* name, const class Type& type, bool aggregate, bool hidden = false); /** Copy constructor */ VariableDefinition (const class VariableDefinition& old); private: /** Assignment operator */ class VariableDefinition& operator= (const class VariableDefinition& old); public: /** Destructor */ ~VariableDefinition (); /** Determine the name of the variable */ const char* getName () const { return myName; } /** Determine the type of the variable */ const class Type& getType () const { return *myType; } /** Determine the father of the variable */ const class VariableDefinition* getFather () const { return myFather; } /** Determine whether this is an aggregate variable */ bool isAggregate () const { return myIsAggregate; } /** Determine whether this variable may be undefined */ bool isUndefined () const { return myIsUndefined; } /** Determine whether this variable has been referenced */ bool isReferenced () const { return myIsReferenced; } /** Determine whether this variable is hidden */ bool isHidden () const { return myIsHidden; } /** Flag that the variable may be undefined */ void flagUndefined () { myIsUndefined = true; } /** Set the "referenced" flag of the variable */ void flagReferenced (bool referenced) const { myIsReferenced = referenced; } /** Set the "hidden" flag of the variable */ void flagHidden (bool hidden) { myIsHidden = hidden; } /** Find a child variable to a quantified variable * @param name name of the child variable * @return the variable, or NULL if not found */ const class VariableDefinition* findChild (const char* name) const; /** Add a child variable to a quantified variable * @param name name of the child variable * @param type type of the child variable * @return the variable, or NULL if contradictory definition */ const class VariableDefinition* addChild (char* name, const class Type& type) const; # ifdef EXPR_COMPILE /** Determine the number of the compiled variable */ unsigned getNumber () const { return myNumber; } /** Set the number of the compiled variable */ void setNumber (unsigned number) { myNumber = number; } # endif // EXPR_COMPILE private: /** Name of the variable */ char* myName; /** Type of the variable */ const class Type* myType; /** Flag: is this an aggregate variable? */ const bool myIsAggregate; /** Flag: may the variable be undefined? */ bool myIsUndefined; /** Flag: has the variable been referenced? */ mutable bool myIsReferenced; /** Flag: has the variable been hidden? */ bool myIsHidden; # ifdef EXPR_COMPILE /** Number of the compiled variable */ unsigned myNumber; # endif // EXPR_COMPILE /** The child variables of an aggregate variable */ mutable ChildMap myChildMap; /** The father of a child variable */ const class VariableDefinition* myFather; }; #endif // VARIABLEDEFINITION_H_ maria-1.3.5/Type/0000755000175000017500000000000010272511404013674 5ustar msmakelamsmakelamaria-1.3.5/Type/BoolType.C0000644000175000017500000000522207643253074015554 0ustar msmakelamsmakela// Boolean type class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BoolType.h" #include "LeafValue.h" #include "Constraint.h" #include "Range.h" /** @file BoolType.C * Boolean data type */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class Value& BoolType::getFirstValue () const { const class Value* v = myConstraint ? &myConstraint->getFirstValue () : NULL; assert (!v || &v->getType () == this); return v ? *static_cast(v->copy ()) : *new class LeafValue (*this, false); } class Value& BoolType::getLastValue () const { const class Value* v = myConstraint ? &myConstraint->getLastValue () : NULL; assert (!v || &v->getType () == this); return v ? *static_cast(v->copy ()) : *new class LeafValue (*this, true); } card_t BoolType::do_getNumValues () const { assert (!myConstraint); return 2; } card_t BoolType::convert (const class Value& value) const { assert (value.getKind () == Value::vLeaf); if (myConstraint) return Type::convert (value); return bool (static_cast(value)) ? 1 : 0; } class Value* BoolType::convert (card_t number) const { assert (number < getNumValues ()); if (myConstraint) return Type::convert (number); return new class LeafValue (*this, number ? true : false); } #ifdef EXPR_COMPILE # include "StringBuffer.h" void BoolType::compileDefinition (class StringBuffer& out, unsigned indent) const { out.indent (indent); out.append ("bool_t"); } void BoolType::do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { out.indent (indent); out.append (number); out.append (add ? "+=" : "="); out.append (value); out.append (";\n"); } #endif // EXPR_COMPILE maria-1.3.5/Type/BoolType.h0000644000175000017500000000567207767301450015631 0ustar msmakelamsmakela// Boolean type class -*- c++ -*- #ifndef BOOLTYPE_H_ # define BOOLTYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Type.h" /** @file BoolType.h * Boolean data type */ /* Copyright © 1998-2001,2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Boolean type */ class BoolType : public Type { public: /** Constructor */ BoolType () : Type (true) {} /** Copy constructor */ BoolType (const class BoolType& old) : Type (old) {} private: /** Assignment operator */ class BoolType& operator= (const class BoolType& old); public: /** Destructor */ ~BoolType () {} /** Copy the Type */ class Type* copy () const { return new class BoolType (*this); } /** Determine the kind of the type */ enum Kind getKind () const { return tBool; } /** Get the first value of this type */ class Value& getFirstValue () const; /** Get the last value of this type */ class Value& getLastValue () const; /** Get the number of possible values for this type. */ card_t do_getNumValues () const; /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ class Value* convert (card_t number) const; # ifdef EXPR_COMPILE /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ void compileDefinition (class StringBuffer& out, unsigned indent) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; # endif // EXPR_COMPILE }; #endif // BOOLTYPE_H_ maria-1.3.5/Type/BufferType.C0000644000175000017500000004762607767301450016107 0ustar msmakelamsmakela// Buffer type class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BufferType.h" #include "BufferValue.h" #include "Constraint.h" #include "Printer.h" #include /** @file BufferType.C * Variable-length queue or stack with maximum length */ /* Copyright © 1999-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ BufferType::BufferType (const class Type& itemType, card_t size, bool stack) : Type (itemType.isOrdered ()), myItemType (&itemType), mySize (size), myStack (stack) { assert (myItemType && size); } BufferType::BufferType (const class BufferType& old) : Type (old), myItemType (old.myItemType), mySize (old.mySize), myStack (old.myStack) { } BufferType::~BufferType () { } class Value& BufferType::getFirstValue () const { if (myConstraint) return *myConstraint->getFirstValue ().copy (); return *new class BufferValue (*this); } class Value& BufferType::getLastValue () const { if (myConstraint) return *myConstraint->getLastValue ().copy (); else { class BufferValue& w = *new class BufferValue (*this); w.top (); return w; } } bool BufferType::isAssignable (const class Type& type) const { if (&type == this) return true; if (type.getKind () != getKind ()) return Type::isAssignable (type); const class BufferType& v = static_cast(type); return myItemType->isAssignable (*v.myItemType); } bool BufferType::isAlwaysAssignable (const class Type& type) const { if (&type == this) return true; if (type.getKind () != getKind ()) return false; const class BufferType& v = static_cast(type); return mySize == v.mySize && myItemType->isAlwaysAssignable (*v.myItemType); } bool BufferType::isConstrained (const class Value& value) const { assert (value.getType ().isAssignable (*this)); const class BufferValue& b = static_cast(value); for (card_t i = 0; i < getSize () && b[i]; i++) if (!myItemType->isConstrained (*b[i])) return false; return Type::isConstrained (value); } card_t BufferType::do_getNumValues () const { assert (!myConstraint); card_t numValues = 1; const card_t numItemValues = myItemType->getNumValues (); if (numItemValues == CARD_T_MAX) return CARD_T_MAX; for (card_t i = 1; i <= mySize; i++) { card_t product = 1; for (card_t j = 0; j < i; j++) { if (numItemValues < CARD_T_MAX / product) product *= numItemValues; else return CARD_T_MAX; } if (product < CARD_T_MAX - numValues) numValues += product; else return CARD_T_MAX; } return numValues; } card_t BufferType::convert (const class Value& value) const { assert (value.getKind () == Value::vBuffer); assert (isConstrained (value)); assert (getNumValues () < CARD_T_MAX); if (myConstraint) return Type::convert (value); card_t number = 0; const class BufferValue& v = static_cast(value); card_t numItemValues = myItemType->getNumValues (); card_t offset = 0, i = 0; for (card_t mult = 1; i < mySize && v[i]; mult *= numItemValues, i++) offset += mult; while (i--) (number *= numItemValues) += myItemType->convert (*v[i]); number += offset; assert (number < getNumValues ()); return number; } class Value* BufferType::convert (card_t number) const { assert (number < getNumValues ()); assert (getNumValues () < CARD_T_MAX); if (myConstraint) return Type::convert (number); class BufferValue* value = new class BufferValue (*this); if (!number) return value; card_t numItemValues = myItemType->getNumValues (); card_t size = 0; for (card_t mult = 1; number >= mult; size++, mult *= numItemValues) number -= mult; for (card_t i = 0; i < size; i++) { card_t num = number % numItemValues; number /= numItemValues; (*value)[i] = myItemType->convert (num); } assert (isConstrained (*value)); return value; } #ifdef EXPR_COMPILE # include "CExpression.h" # include "util.h" # include void BufferType::compile (class StringBuffer& out) { const_cast(myItemType)->compile (out); Type::compile (out); } void BufferType::compileDefinition (class StringBuffer& out, unsigned indent) const { out.indent (indent), out.append ("struct {\n"); out.indent (indent + 2), out.append ("unsigned s;\n"); out.indent (indent + 2), myItemType->appendName (out); out.append (" a["); out.append (mySize); out.append ("];\n"); out.indent (indent), out.append ("}"); } void BufferType::compileExtraDefinitions (class StringBuffer& out, unsigned indent, bool interface) const { if (getNumValues () < CARD_T_MAX) { // offsets for value<->number conversions out.indent (indent); if (interface) out.append ("extern "); out.append ("const card_t o"), appendIndex (out); out.append ("[]"); if (!interface) { out.append (" = { 0"); card_t numItemValues = myItemType->getNumValues (); card_t offset = 0, i = 0; for (card_t mult = 1; i < mySize; mult *= numItemValues, i++) { offset += mult; out.append (", "), out.append (offset); } out.append (" }"); } out.append (";\n"); } Type::compileExtraDefinitions (out, indent, interface); } bool BufferType::compileEqual (class StringBuffer& out, unsigned indent, const char* left, const char* right, bool equal, bool first, bool last, bool backslash) const { size_t llen = strlen (left), rlen = strlen (right); char* l = new char[llen + 25]; char* r = new char[rlen + 25]; memcpy (l, left, llen); memcpy (r, right, rlen); if (!first) out.indent (indent); out.append (left), out.append (".s"); out.append (equal ? "==" : "!="); out.append (right), out.append (".s"); if (myItemType->getNumValues () != 1) { out.append (backslash ? (equal ? "&&\\\n" : "||\\\n") : (equal ? "&&\n" : "||\n")); for (card_t i = getSize (); i--; ) { out.indent (indent); out.append ("("); out.append (left), out.append (".s"); out.append (equal ? "<=" : ">"); out.append (i); out.append (backslash ? (equal ? "||\\\n" : "&&\\\n") : (equal ? "||\n" : "&&\n")); out.indent (indent + 1); out.append ("("); snprintf (l + llen, 25, ".a[%u]", i); snprintf (r + rlen, 25, ".a[%u]", i); if (!myItemType->compileEqual (out, indent + 2, l, r, equal, true, true, backslash)) out.append (equal ? "1" : "0"); out.append ("))"); if (i || !last) out.append (backslash ? (equal ? "&&\\\n" : "||\\\n") : (equal ? "&&\n" : "||\n")); } } else if (!last) out.append (backslash ? (equal ? "&&\\\n" : "||\\\n") : (equal ? "&&\n" : "||\n")); delete[] l; delete[] r; return true; } void BufferType::compileCompare3 (class StringBuffer& out, const char* condition, const char* component) const { const size_t len = strlen (component); char* const newcomp = new char[len + 25]; char* const offset = newcomp + len; memcpy (newcomp, component, len); memcpy (offset, ".s", 3); compileLeafCompare3 (out, condition, newcomp); const size_t condlen = condition ? strlen (condition) : 0; char* const newcond = new char[condlen ? len + condlen + 27 : len + 25]; char* const coffset = condlen ? newcond + condlen + len + 3 : newcond + len + 1; if (condlen) { memcpy (newcond, condition, condlen); memcpy (newcond + condlen, "&&l", 3); } else *newcond = 'l'; memcpy (&newcond[condlen ? condlen + 3 : 1], component, len); for (card_t i = mySize; i--; ) { snprintf (coffset, 24, ".s>%u", i); snprintf (offset, 25, ".a[%u]", i); myItemType->compileCompare3 (out, newcond, newcomp); } delete[] newcond; delete[] newcomp; } void BufferType::do_compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { size_t llen = strlen (lvalue), rlen = strlen (rvalue); char* lval = new char[llen + 25]; char* rval = new char[rlen + 25]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); memcpy (lval + llen, ".a[0]", 6); out.indent (indent); out.append ("do {\n"); if (!wrap) { wrap = "wrap"; out.indent (indent + 2); out.append ("bool_t "); out.append (wrap); out.append ("=0;\n"); } out.indent (indent + 2); out.append (lvalue), out.append (".s="); out.append (rvalue), out.append (".s;\n"); for (card_t i = 0;; ) { snprintf (rval + rlen, 25, ".a[%u]", i); out.indent (indent + 2); out.append ("if ("), out.append (lvalue), out.append (".s=="); out.append (i), out.append (") {\n"); out.indent (indent + 4); out.append (lvalue), out.append (".s++;\n"); snprintf (lval + llen, 25, ".a[%u]", i); myItemType->compileBottom (out, indent + 4, lval); out.indent (indent + 4); out.append ("continue;\n"); out.indent (indent + 2); out.append ("}\n"); myItemType->compileSuccessor (out, indent + 2, lval, rval, wrap); if (++i < mySize) { out.indent (indent + 2); out.append ("if (!"); out.append (wrap); out.append (") {\n"); if (lvalue != rvalue && strcmp (lvalue, rvalue)) { for (card_t j = i; j < getSize (); j++) { out.indent (indent + 4); out.append (lvalue); out.append (".a["); out.append (j); out.append ("]="); out.append (rvalue); out.append (".a["); out.append (j); out.append ("];\n"); } } out.indent (indent + 4); out.append ("continue;\n"); out.indent (indent + 2); out.append ("}\n"); out.indent (indent + 2); out.append (wrap); out.append ("=0;\n"); } else break; } out.indent (indent); out.append ("} while (0);\n"); delete[] lval; delete[] rval; } void BufferType::do_compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { size_t llen = strlen (lvalue), rlen = strlen (rvalue); char* lval = new char[llen + 25]; char* rval = new char[rlen + 25]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); out.indent (indent); out.append ("do {\n"); if (!wrap) { wrap = "wrap"; out.indent (indent + 2); out.append ("bool_t "); out.append (wrap); out.append ("=0;\n"); } out.indent (indent + 2); out.append (lvalue), out.append (".s="); out.append (rvalue), out.append (".s;\n"); for (card_t i = 0; i < mySize; i++) { snprintf (lval + llen, 25, ".a[%u]", i); snprintf (rval + rlen, 25, ".a[%u]", i); myItemType->compilePredecessor (out, indent + 2, lval, rval, wrap); out.indent (indent + 2); out.append ("if (!"); out.append (wrap); out.append (") {\n"); if (lvalue != rvalue && strcmp (lvalue, rvalue)) { for (card_t j = i + 1; j < getSize (); j++) { out.indent (indent + 4); out.append (lvalue); out.append (".a["); out.append (j); out.append ("]="); out.append (rvalue); out.append (".a["); out.append (j); out.append ("];\n"); } } out.indent (indent + 4); out.append ("continue;\n"); out.indent (indent + 2); out.append ("}\n"); out.indent (indent + 2); out.append (wrap); out.append ("=0;\n"); out.indent (indent + 2); out.append ("if ("); out.append (lvalue); out.append (".s=="); out.append (i + 1); out.append (") {\n"); out.indent (indent + 4); out.append (lvalue); out.append (".s--;\n"); out.indent (indent + 4); out.append ("continue;\n"); out.indent (indent + 2); out.append ("}\n"); } out.indent (indent); out.append ("} while (0);\n"); delete[] lval; delete[] rval; } void BufferType::compileCast (class CExpression& cexpr, unsigned indent, const class Type& target, const char* lvalue, const char* rvalue) const { assert (isAssignable (target)); if (target.getKind () != Type::tBuffer) Type::compileCast (cexpr, indent, target, lvalue, rvalue); else { class StringBuffer& out = cexpr.getOut (); const class BufferType& bt = static_cast(target); out.indent (indent); out.append (lvalue); out.append (".s="); out.append (rvalue); out.append (".s;\n"); card_t i = getSize (); if (i > bt.getSize ()) { i = bt.getSize (); out.indent (indent); out.append ("if ("); out.append (lvalue); out.append (".s>"); out.append (bt.getSize ()); out.append (")\n"); cexpr.compileError (indent + 2, errConst); } size_t llen = strlen (lvalue); size_t rlen = strlen (rvalue); char* lval = new char[llen + 25]; char* rval = new char[llen + 25]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); while (i--) { snprintf (lval + llen, 25, ".a[%u]", i); snprintf (rval + rlen, 25, ".a[%u]", i); myItemType->compileCast (cexpr, indent, *bt.myItemType, lval, rval); } delete[] lval; delete[] rval; if (const class Constraint* c = target.getConstraint ()) c->compileCheck (cexpr, indent, lvalue); } } void BufferType::do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { card_t i = getSize (); assert (getNumValues () < CARD_T_MAX && i); size_t length = strlen (value); char* val = new char[length + 25]; char* offset = val + length; memcpy (val, value, length); const char* num = number; if (add) { out.indent (indent), out.append ("{\n"); out.indent (indent += 2), out.append ("card_t "); length = strlen (number); char* nbr = new char[length + 2]; memcpy (nbr, number, length); memcpy (nbr + length, "_", 2); num = nbr; out.append (num), out.append ("=0;\n"); } else out.indent (indent), out.append (num), out.append ("=0;\n"); const card_t numValues = myItemType->getNumValues (); for (bool next = false; i--; next = true) { out.indent (indent); out.append ("if ("), out.append (value), out.append (".s"); if (i) out.append (">"), out.append (i); out.append (") {\n"); snprintf (offset, 25, ".a[%u]", i); myItemType->compileConversion (out, indent + 2, val, num, next); if (i) { out.indent (indent + 2), out.append (num), out.append ("*="); out.append (numValues), out.append (";\n"); } out.indent (indent); out.append ("}\n"); } out.indent (indent), out.append (num); out.append ("+=o"), appendIndex (out); out.append ("["), out.append (value), out.append (".s];\n"); if (add) { out.indent (indent), out.append (number), out.append ("+="); out.append (num), out.append (";\n"); out.indent (indent -= 2), out.append ("}\n"); delete[] num; } delete[] val; } void BufferType::compileReverseConversion (class StringBuffer& out, unsigned indent, const char* number, const char* value) const { if (myConstraint) Type::compileReverseConversion (out, indent, number, value); else if (getNumValues () == 1) compileBottom (out, indent, value); else { size_t length = strlen (value); char* val = new char[length + 25]; char* offset = val + length; memcpy (val, value, length); out.indent (indent); out.append ("for ("), out.append (value); out.append (".s="), out.append (getSize ()); out.append ("; "); out.append (number), out.append ("getNumValues (); for (card_t i = 0; i < getSize (); i++) { out.indent (indent + 2); out.append ("if ("), out.append (value), out.append (".s=="); out.append (i), out.append (") continue;\n"); snprintf (offset, 25, ".a[%u]", i); out.indent (indent + 2); out.append (num), out.append ("="), out.append (number); out.append ("%"), out.append (numValues); out.append (", "); out.append (number), out.append ("/="); out.append (numValues); out.append (";\n"); myItemType->compileReverseConversion (out, indent + 2, num, val); } out.indent (indent), out.append ("} while (0);\n"); delete[] num; delete[] val; } } void BufferType::compileEncoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const { if (getNumValues () < CARD_T_MAX) Type::compileEncoder (cexpr, indent, func, value); else { size_t length = strlen (value); char* val = new char[length + 6]; memcpy (val, value, length); memcpy (val + length, ".a[i]", 6); class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append (func); out.append (" ("); out.append (value), out.append (".s, "); out.append (log2 (getSize () + 1)); out.append (");\n"); out.indent (indent); out.append ("{\n"); out.indent (indent + 2); out.append ("card_t i;\n"); out.indent (indent + 2); out.append ("for (i="); out.append (value); out.append (".s; i--; ) {\n"); myItemType->compileEncoder (cexpr, indent + 4, func, val); out.indent (indent + 2); out.append ("}\n"); out.indent (indent); out.append ("}\n"); delete[] val; } } void BufferType::compileDecoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const { if (getNumValues () < CARD_T_MAX) Type::compileDecoder (cexpr, indent, func, value); else { size_t length = strlen (value); char* val = new char[length + 6]; memcpy (val, value, length); memcpy (val + length, ".a[i]", 6); class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append (value); out.append (".s = "); out.append (func); out.append (" ("); out.append (log2 (getSize () + 1)); out.append (");\n"); out.indent (indent); out.append ("{\n"); out.indent (indent + 2); out.append ("card_t i;\n"); out.indent (indent + 2); out.append ("for (i="); out.append (value); out.append (".s; i--; ) {\n"); myItemType->compileDecoder (cexpr, indent + 4, func, val); out.indent (indent + 2); out.append ("}\n"); out.indent (indent); out.append ("}\n"); delete[] val; } } #endif // EXPR_COMPILE void BufferType::display (const class Printer& printer) const { if (const char* name = myItemType->getName ()) printer.print (name); else myItemType->display (printer); printer.delimiter ('['); printer.printRaw (myStack ? "stack" : "queue"); printer.delimiter (' '); printer.print (mySize); printer.delimiter (']'); if (myConstraint) myConstraint->display (printer); } maria-1.3.5/Type/BufferType.h0000644000175000017500000002050107643253074016134 0ustar msmakelamsmakela// Buffer (queue or stack) type class -*- c++ -*- #ifndef BUFFERTYPE_H_ # define BUFFERTYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Type.h" /** @file BufferType.h * Variable-length queue or stack with maximum length */ /* Copyright © 1999-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Buffer (variable-length array with queue or stack discipline) */ class BufferType : public Type { public: /** Constructor * @param itemType The buffer item type * @param size The buffer size * @param stack Flag: true=stack, false=queue */ BufferType (const class Type& itemType, card_t size, bool stack); /** Copy constructor */ BufferType (const class BufferType& old); private: /** Assignment operator */ class BufferType& operator= (const class BufferType& old); public: /** Destructs BufferType */ ~BufferType (); /** Copy the Type */ class Type* copy () const { return new class BufferType (*this); } /** Determine the kind of the type */ enum Kind getKind () const { return tBuffer; } /** Get the item type */ const class Type& getItemType () const { return *myItemType; } /** Get the size */ card_t getSize () const { return mySize; } /** Determine whether this is a stack */ bool isStack () const { return myStack; } /** Get the first value of this type */ class Value& getFirstValue () const; /** Get the last value of this type */ class Value& getLastValue () const; /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ class Value* convert (card_t number) const; /** See if the type is assignable to another type * @param type the type this type should be assignable to * @return true if this type is assignable to the type */ bool isAssignable (const class Type& type) const; /** See if the type is always assignable to another type * @param type the type this type should always be assignable to * @return true if this type always is assignable to the type */ bool isAlwaysAssignable (const class Type& type) const; /** Determine whether a value is compatible with the constraints of this type * @param value value to check * @return true if the value passes the constraint check */ bool isConstrained (const class Value& value) const; /** Get the number of possible values for this type */ card_t do_getNumValues () const; # ifdef EXPR_COMPILE /** Generate a C type declaration and auxiliary functions * @param out output stream for the declarations */ void compile (class StringBuffer& out); /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ void compileDefinition (class StringBuffer& out, unsigned indent) const; /** Generate auxiliary definitions * @param out output stream for the declarations * @param indent indentation level * @param interface flag: generate interface declarations */ void compileExtraDefinitions (class StringBuffer& out, unsigned indent, bool interface) const; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param left left-hand-side C expression to be compared * @param right right-hand-side C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @param backslash flag: prepend all newlines with backslashes * @return true if any code was generated */ bool compileEqual (class StringBuffer& out, unsigned indent, const char* left, const char* right, bool equal, bool first, bool last, bool backslash) const; /** Generate three-way comparison statements * @param out output stream * @param condition additional condition for the comparison (NULL=none) * @param component component to be compared */ void compileCompare3 (class StringBuffer& out, const char* condition, const char* component) const; /** Generate statements for incrementing an unconstrained value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose successor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ void do_compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Generate statements for decrementing an unconstrained value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose predecessor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ void do_compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Emit code for converting a value of this type to another * @param cexpr the compilation * @param indent indentation level * @param target target type * @param lvalue left-hand-side value of the assignment * @param rvalue C expression for the value to be converted */ void compileCast (class CExpression& cexpr, unsigned indent, const class Type& target, const char* lvalue, const char* rvalue) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; /** Emit code for converting a number to a value * @param out output stream * @param indent indentation level * @param number number to be converted * @param value value to be computed */ void compileReverseConversion (class StringBuffer& out, unsigned indent, const char* number, const char* value) const; /** Emit code for encoding a value * @param cexpr the compilation * @param indent indentation level * @param func name of the encoding function * @param value value to be encoded */ void compileEncoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const; /** Emit code for decoding a value * @param cexpr the compilation * @param indent indentation level * @param func name of the decoding function * @param value value to be decoded */ void compileDecoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const; # endif // EXPR_COMPILE /** Display the type definition * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The item type */ const class Type* myItemType; /** The size */ card_t mySize; /** Flag: true=stack, false=queue */ bool myStack; }; #endif // BUFFERTYPE_H_ maria-1.3.5/Type/CardType.C0000644000175000017500000001541107643253074015533 0ustar msmakelamsmakela// Unsigned integer (cardinality) type class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "CardType.h" #include "LeafValue.h" #include "Constraint.h" #include "Range.h" /** @file CardType.C * Unsigned integer data type */ /* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class Value& CardType::getFirstValue () const { const class Value* v = myConstraint ? &myConstraint->getFirstValue () : NULL; assert (!v || &v->getType () == this); return v ? *static_cast(v->copy ()) : *new class LeafValue (*this, 0); } class Value& CardType::getLastValue () const { const class Value* v = myConstraint ? &myConstraint->getLastValue () : NULL; assert (!v || &v->getType () == this); return v ? *static_cast(v->copy ()) : *new class LeafValue (*this, CARD_T_MAX); } card_t CardType::do_getNumValues () const { return myConstraint ? myConstraint->getNumValues () : CARD_T_MAX; } card_t CardType::convert (const class Value& value) const { assert (value.getKind () == Value::vLeaf); card_t v = card_t (static_cast(value)); if (myConstraint) { card_t number; if (!convert (number, v, *myConstraint)) assert (false); return number; } else return v; } class Value* CardType::convert (card_t number) const { assert (number < static_cast(this)->getNumValues ()); return new class LeafValue (*this, myConstraint ? convert (number, *myConstraint) : number); } bool CardType::convert (card_t& number, card_t value, const class Constraint& c) { number = 0; for (Constraint::const_iterator i = c.begin (); !(i == c.end ()); i++) { const class Range* r = *i; card_t lowLimit = card_t (static_cast(r->getLow ())); card_t highLimit = card_t (static_cast(r->getHigh ())); assert (lowLimit <= highLimit); if (value < lowLimit || value > highLimit) { if (card_t diff = highLimit - lowLimit + 1) number += diff; else return false; } else { number += value - lowLimit; assert (number <= c.getNumValues ()); return true; } } return false; } card_t CardType::convert (card_t number, const class Constraint& c) { for (Constraint::const_iterator i = c.begin (); !(i == c.end ()); i++) { const class Range* r = *i; card_t lowLimit = card_t (static_cast(r->getLow ())); card_t highLimit = card_t (static_cast(r->getHigh ())); assert (lowLimit <= highLimit); card_t diff = highLimit - lowLimit; if (number <= diff) return lowLimit + number; else number -= diff, number--; } assert (false); return 0; } #ifdef EXPR_COMPILE # include "StringBuffer.h" void CardType::compileDefinition (class StringBuffer& out, unsigned indent) const { out.indent (indent); out.append ("unsigned"); } void CardType::do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { out.indent (indent); out.append (number); out.append (add ? "+=" : "="); out.append (value); out.append (";\n"); } void CardType::compileConv (class StringBuffer& out, unsigned indent, const class Constraint& c, const char* value, const char* number) { bool next = false; for (Constraint::const_iterator i = c.end ();; next = true) { const class Range* range = *--i; const class Value& low = range->getLow (); const class Value& high = range->getHigh (); const bool notfirst = i != c.begin (); card_t num; if (!convert (num, card_t (static_cast(low)), c)) assert (false); if (notfirst) { out.indent (indent); if (next) out.append ("else "); out.append ("if ("); if (&low == &high) low.compileEqual (out, next ? indent + 9 : indent + 4, value, true, true, true); else low.compileOrder (out, next ? indent + 9 : indent + 4, value, false, true, true, true); out.append (")\n"); indent += 2; } else if (next) out.indent (indent), out.append ("else\n"), indent += 2; out.indent (indent); if (&low == &high) { out.append (number), out.append ("="), out.append (num); out.append (";\n"); } else { out.append (number), out.append ("="); out.append ("(card_t) ("), out.append (value); out.append (" - "); low.compile (out); out.append (")"); if (num) out.append ("+"), out.append (num); out.append (";\n"); } if (notfirst || next) indent -= 2; if (!notfirst) break; } } void CardType::compileReverseConv (class StringBuffer& out, unsigned indent, const class Constraint& c, const char* number, const char* value) { bool next = false; for (Constraint::const_iterator i = c.end (); i != c.begin (); next = true) { const class Range* range = *--i; const class Value& low = range->getLow (); const class Value& high = range->getHigh (); card_t num; if (!convert (num, card_t (static_cast(low)), c)) assert (false); if (num) { out.indent (indent); if (next) out.append ("else "); out.append ("if ("), out.append (number); out.append (&low == &high ? "==" : ">="), out.append (num); out.append (")"); } else if (next) out.indent (indent), out.append ("else"); if (num || next) out.append (" {\n"), indent += 2; low.compileInit (value, indent, out); if (&low != &high) { out.indent (indent); out.append (value); out.append ("+="); out.append (number); if (num) out.append ("-"), out.append (num); out.append (";\n"); } if (num || next) out.indent (indent -= 2), out.append ("}\n"); } } #endif // EXPR_COMPILE maria-1.3.5/Type/CardType.h0000644000175000017500000001064607767301450015604 0ustar msmakelamsmakela// Unsigned integer (cardinality) type class -*- c++ -*- #ifndef CARDTYPE_H_ # define CARDTYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Type.h" /** @file CardType.h * Unsigned integer data type */ /* Copyright © 2000-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Unsigned integer (cardinality) type */ class CardType : public Type { public: /** Constructor */ CardType () : Type (true) {} /** Copy constructor */ CardType (const class CardType& old) : Type (old) {} private: /** Assignment operator */ class CardType& operator= (const class CardType& old); public: /** Destructor */ ~CardType () {} /** Copy the Type */ class Type* copy () const { return new class CardType (*this); } /** Determine the kind of the type */ enum Kind getKind () const { return tCard; } /** Get the first value of this type */ class Value& getFirstValue () const; /** Get the last value of this type */ class Value& getLastValue () const; /** Get the number of possible values for this type */ card_t do_getNumValues () const; /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ class Value* convert (card_t number) const; /** Convert a constrained unsigned integer value to a number * @param number placeholder: number between 0 and getNumValues (c) - 1 * @param value value to be converted * @param c the constraint * @return true if the integer actually is constrained */ static bool convert (card_t& number, card_t value, const class Constraint& c); /** Convert a number to a value of this type * @param number number between 0 and getNumValues (c) - 1 * @param c the constraint * @return the corresponding unsigned integer value */ static card_t convert (card_t number, const class Constraint& c); # ifdef EXPR_COMPILE /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ void compileDefinition (class StringBuffer& out, unsigned indent) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; /** Emit code for converting a constrained cardinality to a number * @param out output stream * @param indent indentation level * @param c the constraint * @param value value to be converted * @param number number to be computed */ static void compileConv (class StringBuffer& out, unsigned indent, const class Constraint& c, const char* value, const char* number); /** Emit code for converting a number to a constrained cardinality * @param out output stream * @param indent indentation level * @param c the constraint * @param number number to be converted * @param value value to be computed */ static void compileReverseConv (class StringBuffer& out, unsigned indent, const class Constraint& c, const char* number, const char* value); # endif // EXPR_COMPILE }; #endif // CARDTYPE_H_ maria-1.3.5/Type/CharType.C0000644000175000017500000000522707767301450015542 0ustar msmakelamsmakela// Character type class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "CharType.h" #include "LeafValue.h" #include "Constraint.h" #include "Range.h" /** @file CharType.C * Character data type */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class Value& CharType::getFirstValue () const { const class Value* v = myConstraint ? &myConstraint->getFirstValue () : NULL; assert (!v || &v->getType () == this); return v ? *static_cast(v->copy ()) : *new class LeafValue (*this, 0); } class Value& CharType::getLastValue () const { const class Value* v = myConstraint ? &myConstraint->getLastValue () : NULL; assert (!v || &v->getType () == this); return v ? *static_cast(v->copy ()) : *new class LeafValue (*this, CHAR_T_MAX); } card_t CharType::do_getNumValues () const { assert (!myConstraint); return CHAR_T_MAX + 1; } card_t CharType::convert (const class Value& value) const { assert (value.getKind () == Value::vLeaf); if (myConstraint) return Type::convert (value); return char_t (static_cast(value)); } class Value* CharType::convert (card_t number) const { assert (number < getNumValues ()); if (myConstraint) return Type::convert (number); return new class LeafValue (*this, number); } #ifdef EXPR_COMPILE # include "StringBuffer.h" void CharType::compileDefinition (class StringBuffer& out, unsigned indent) const { out.indent (indent); out.append ("unsigned char"); } void CharType::do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { out.indent (indent); out.append (number); out.append (add ? "+=" : "="); out.append (value); out.append (";\n"); } #endif // EXPR_COMPILE maria-1.3.5/Type/CharType.h0000644000175000017500000000570507767301450015610 0ustar msmakelamsmakela// Character type class -*- c++ -*- #ifndef CHARTYPE_H_ # define CHARTYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Type.h" /** @file CharType.h * Character data type */ /* Copyright © 1998-2001,2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Character type */ class CharType : public Type { public: /** Constructor */ CharType () : Type (true) {} /** Copy constructor */ CharType (const class CharType& old) : Type (old) {} private: /** Assignment operator */ class CharType& operator= (const class CharType& old); public: /** Destructor */ ~CharType () {} /** Copy the Type */ class Type* copy () const { return new class CharType (*this); } /** Determine the kind of the type */ enum Kind getKind () const { return tChar; } /** Get the first value of this type */ class Value& getFirstValue () const; /** Get the last value of this type */ class Value& getLastValue () const; /** Determine the number of possible values for this type */ card_t do_getNumValues () const; /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ class Value* convert (card_t number) const; # ifdef EXPR_COMPILE /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ void compileDefinition (class StringBuffer& out, unsigned indent) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; # endif // EXPR_COMPILE }; #endif // CHARTYPE_H_ maria-1.3.5/Type/ComponentList.C0000644000175000017500000001055707643253074016624 0ustar msmakelamsmakela// Struct or union component list class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include #include "ComponentList.h" #include "util.h" #include "Printer.h" /** @file ComponentList.C * List of struct or union components */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ ComponentList::ComponentList () : mySize (0), myNames (NULL), myTypes (NULL) { } ComponentList::ComponentList (const class ComponentList& old) : mySize (old.mySize), myNames (NULL), myTypes (NULL) { if (mySize) { myNames = new char*[mySize]; for (card_t i = 0; i < mySize; i++) myNames[i] = newString (old.myNames[i]); myTypes = new const class Type*[mySize]; memcpy (myTypes, old.myTypes, mySize * sizeof *myTypes); } } ComponentList::~ComponentList () { for (card_t i = 0; i < mySize; i++) delete[] myNames[i]; delete[] myNames; delete[] myTypes; } const class Type* ComponentList::operator[] (const char* name) const { assert (name != NULL); // This is inefficient but rarely used for (card_t i = 0; i < mySize; i++) if (!strcmp (name, myNames[i])) return myTypes[i]; return NULL; } card_t ComponentList::getIndex (const char* name) const { for (card_t i = 0; i < mySize; i++) if (!strcmp (name, myNames[i])) return i; assert (false); return 0; } bool ComponentList::isAssignable (const class ComponentList& other) const { if (&other == this) return true; if (other.getSize () != getSize ()) return false; for (card_t i = 0; i < mySize; i++) if (strcmp (myNames[i], other.myNames[i]) || !myTypes[i]->isAssignable (*other.myTypes[i])) return false; return true; } bool ComponentList::isAlwaysAssignable (const class ComponentList& other) const { if (&other == this) return true; if (other.getSize () != getSize ()) return false; for (card_t i = 0; i < mySize; i++) if (strcmp (myNames[i], other.myNames[i]) || !myTypes[i]->isAlwaysAssignable (*other.myTypes[i])) return false; return true; } bool ComponentList::isAssignable (const class Type& type) const { for (card_t i = 0; i < mySize; i++) if (myTypes[i]->isAssignable (type)) return true; return false; } bool ComponentList::isAssignableFrom (const class Type& type) const { for (card_t i = 0; i < mySize; i++) if (type.isAssignable (*myTypes[i])) return true; return false; } bool ComponentList::isAlwaysAssignableFrom (const class Type& type) const { for (card_t i = 0; i < mySize; i++) if (type.isAlwaysAssignable (*myTypes[i])) return true; return false; } void ComponentList::addComponent (char* name, const class Type& type) { assert (!(*this)[name]); if (mySize) { char** names = new char*[mySize + 1]; memcpy (names, myNames, mySize * sizeof *myNames); delete[] myNames; myNames = names; const class Type** types = new const class Type*[mySize + 1]; memcpy (types, myTypes, mySize * sizeof *myTypes); delete[] myTypes; myTypes = types; } else { assert (!myNames); assert (!myTypes); myNames = new char*[1]; myTypes = new const class Type*[1]; } myNames[mySize] = name; myTypes[mySize] = &type; mySize++; } void ComponentList::display (const class Printer& printer) const { for (card_t i = 0; i < mySize; i++) { if (const char* name = myTypes[i]->getName ()) printer.printRaw (name); else myTypes[i]->display (printer); printer.delimiter (' '); printer.print (myNames[i]); printer.delimiter (';'); printer.linebreak (); } } maria-1.3.5/Type/ComponentList.h0000644000175000017500000001045207767301374016667 0ustar msmakelamsmakela// Struct or union component list class -*- c++ -*- #ifndef COMPONENTLIST_H_ # define COMPONENTLIST_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include "Type.h" /** @file ComponentList.h * List of struct or union components */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Struct or union component list */ class ComponentList { public: /** Constructor */ ComponentList (); /** Copy constructor */ ComponentList (const class ComponentList& old); private: /** Assignment operator */ class ComponentList& operator= (const class ComponentList& old); public: /** Destructor */ ~ComponentList (); /** Determine the number of components in the list */ card_t getSize () const { return mySize; } /** Determine whether all components are ordered types */ bool isOrdered () const { for (card_t i = mySize; i--; ) if (!(*this)[i].isOrdered ()) return false; return true; } /** Get a component by name * @param name name of the component * @return pointer to the component, or NULL if not found */ const class Type* operator[] (const char* name) const; /** Get a component by index number * @param i index to the component * @return reference to the component */ const class Type& operator[] (card_t i) const { assert (i < getSize ()); return *myTypes[i]; } /** Get the index number of a component * @param name name of the component * @return index of the component */ card_t getIndex (const char* name) const; /** Get the name of a component * @param i index of the component */ const char* getName (card_t i) const { assert (i < getSize ()); return myNames[i]; } /** See if the component list is assignable to another component list * @param other the list this list should be assignable to * @return true if this list is assignable to the list */ bool isAssignable (const class ComponentList& other) const; /** See if the component list is always assignable to another component list * @param other the list this list should always be assignable to * @return true if this list always is assignable to the list */ bool isAlwaysAssignable (const class ComponentList& other) const; /** See if a component in the list is assignable to a type * @param type the type this list should be assignable to * @return true if this list is assignable to the type */ bool isAssignable (const class Type& type) const; /** See if a component in the list is assignable from a type * @param type the type this list should be assignable from * @return true if a component is assignable from the type */ bool isAssignableFrom (const class Type& type) const; /** See if a component in the list is always assignable from a type * @param type the type the list should always be assignable from * @return true if a component always is assignable from the type */ bool isAlwaysAssignableFrom (const class Type& type) const; /** Add a component * @param name name of the component * @param type type of the component */ void addComponent (char* name, const class Type& type); /** Display the component list * @param printer the printer object */ void display (const class Printer& printer) const; private: /** Number of components in the list */ card_t mySize; /** Component names */ char** myNames; /** Component types */ const class Type** myTypes; }; #endif // COMPONENTLIST_H_ maria-1.3.5/Type/Constraint.C0000644000175000017500000002650407727023530016144 0ustar msmakelamsmakela// Type constraint class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Constraint.h" #include "Range.h" #include "LeafValue.h" #include "Type.h" #include "Printer.h" /** @file Constraint.C * Constraint that limits the domain of a data type */ /* Copyright © 1999-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Constraint::Constraint () : myList () { } Constraint::Constraint (const class Constraint& old, const class Type& type) : myList () { assert (!type.getConstraint () || this == type.getConstraint ()); for (const_iterator i = old.begin (); i != old.end (); i++) { class Range* range = new class Range (**i); myList.push_back (range); range->setType (type); } } Constraint::~Constraint () { for (iterator i = begin (); i != end (); i++) delete *i; } void Constraint::setType (const class Type& type) { for (iterator i = begin (); i != end (); i++) (*i)->setType (type); } const class Value& Constraint::getFirstValue () const { assert (!empty ()); return (*begin ())->getLow (); } const class Value& Constraint::getLastValue () const { assert (!empty ()); return (*--end ())->getHigh (); } const class Value& Constraint::getNextHigh (const class Value& value) const { const_iterator i; for (i = begin (); assert (i != end ()), !(*i)->check (value); i++); return (*i)->getHigh (); } const class Value* Constraint::getNextLow (const class Value& value) const { const_iterator i; for (i = begin (); assert (i != end ()), !((*i)->getHigh () == value); i++); return ++i == end () ? 0 : &(*i)->getLow (); } const class Value& Constraint::getPrevLow (const class Value& value) const { const_iterator i; for (i = begin (); assert (i != end ()), !(*i)->check (value); i++); return (*i)->getLow (); } const class Value* Constraint::getPrevHigh (const class Value& value) const { const_iterator i = begin (), j = end (); for (; assert (i != end ()), !((*i)->getLow () == value); j = i++); return j == end () ? 0 : &(*j)->getHigh (); } void Constraint::append (class Range& r) { class Range* range = &r; iterator i; for (i = begin (); i != end (); ) { if (class Range* rn = (*i)->combine (*range)) { delete *i; delete range; range = rn; if (i == begin ()) { myList.erase (i); if ((i = begin ()) == end ()) break; else continue; } else { iterator j = i; j--; myList.erase (i); i = j; } } else if (!((*i)->getHigh () < range->getHigh ())) break; i++; } if (range->getLow ().getKind () == Value::vLeaf) { const class LeafValue& low = static_cast(range->getLow ()); const class LeafValue& high = static_cast(range->getHigh ()); switch (low.getType ().getKind ()) { case Type::tInt: if (int_t (low) == INT_T_MIN && int_t (high) == INT_T_MAX) { redundant: assert (empty ()); delete range; return; } break; case Type::tCard: if (!card_t (low) && card_t (high) == CARD_T_MAX) goto redundant; break; case Type::tBool: if (!bool (low) && bool (high)) goto redundant; break; case Type::tChar: if (card_t (low) && card_t (high) == CHAR_T_MAX) goto redundant; break; default: break; } } myList.insert (i, range); } void Constraint::restrict (const class Constraint& constraint, const class Type& type) { assert (!type.getConstraint () || this == type.getConstraint ()); assert (!isDisjoint (constraint) || !constraint.isDisjoint (*this)); List l = myList; myList.clear (); for (iterator j = l.begin (); j != l.end (); j++) { for (const_iterator k = constraint.begin (); k != constraint.end (); k++) { if (class Range* range = (*j)->cut (**k)) { range->setType (type); myList.push_back (range); } } delete *j; } } bool Constraint::isSuperset (const class Constraint& other) const { // This is an ugly O(n^2) algorithm, // but it's only used during static analysis. // The algorithm does not consider (1..3,4,5) to be a superset of (2..4). // Neighbouring ranges will have been combined by Constraint::append (). for (const_iterator i = other.begin (); i != other.end (); i++) { const class Value& low = (*i)->getLow (); const class Value& high = (*i)->getHigh (); for (const_iterator j = begin (); j != end (); j++) if (!(low < (*j)->getLow ()) && !((*j)->getHigh () < high)) goto match; return false; match: continue; } return true; } bool Constraint::isDisjoint (const class Constraint& other) const { // This is an ugly O(n^2) algorithm, // but it's only used during static analysis. for (const_iterator i = other.begin (); i != other.end (); i++) { const class Value& low = (*i)->getLow (); const class Value& high = (*i)->getHigh (); for (const_iterator j = begin (); j != end (); j++) if ((*j)->check (low) || (*j)->check (high)) return false; } return true; } bool Constraint::isConstrained (const class Value& value) const { for (const_iterator i = begin (); i != end (); i++) if ((*i)->check (value)) return true; return false; } card_t Constraint::getNumValues () const { card_t numValues = 0; for (const_iterator i = begin (); i != end (); i++) { const class Range* r = *i; card_t num = r->getHigh () - r->getLow (); if (num != CARD_T_MAX && ++num < CARD_T_MAX - numValues) numValues += num; else return CARD_T_MAX; } return numValues; } #ifdef EXPR_COMPILE # include "CExpression.h" void Constraint::compileCheck (class CExpression& cexpr, unsigned indent, const char* value) const { class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append ("if (!("); /** flag: is this the first generated line? */ bool first = true; for (Constraint::const_iterator i = begin ();; ) { const class Range* range = *i++; const class Value& low = range->getLow (); const class Value& high = range->getHigh (); if (&low != &high) { if (!first) out.indent (indent + 6); out.append ("("); if (low.compileOrder (out, indent + 7, value, false, true, true, true)) assert (false); out.append ("&&\n"); if (high.compileOrder (out, indent + 7, value, true, true, false, true)) assert (false); out.append (")"); } else if (!low.compileEqual (out, indent + 6, value, true, first, true)) continue; first = false; if (i != end ()) out.append ("||\n"); else break; } if (first) out.append ("1"); out.append ("))\n"); cexpr.compileError (indent + 2, errConst); } void Constraint::compileConversion (class StringBuffer& out, unsigned indent, const class Type& type, const char* value, const char* number, bool add, const char* work) const { bool next = false; for (Constraint::const_iterator i = end ();; next = true) { const class Range* range = *--i; const class Value& low = range->getLow (); const class Value& high = range->getHigh (); const bool notfirst = i != begin (); if (notfirst) { out.indent (indent); if (next) out.append ("else "); out.append ("if ("); if (&low == &high) low.compileEqual (out, next ? indent + 9 : indent + 4, value, true, true, true); else low.compileOrder (out, next ? indent + 9 : indent + 4, value, false, true, true, true); out.append (")\n"); indent += 2; } else if (next) out.indent (indent), out.append ("else\n"), indent += 2; out.indent (indent); if (&low == &high) { card_t num = type.convert (low); if (num || !add) out.append (number), out.append (add ? "+=" : "="), out.append (num); out.append (";\n"); } else if (!work) { out.append (number), out.append (add ? "+=" : "="); out.append ("(card_t) ("), out.append (value); out.append (" - "); low.compile (out); out.append (")"); if (card_t num = type.convert (low)) out.append ("+"), out.append (num); out.append (";\n"); } else { out.append ("for ("); if (notfirst) { out.append (number), out.append (add ? "+=" : "="); out.append (type.convert (low)); out.append (", "); } else if (!add) out.append (number), out.append ("=0, "); out.append (work); out.append ("="), out.append (value); out.append (";\n"); low.compileEqual (out, indent + 5, work, false, false, true); out.append (";\n"); out.indent (indent + 5), out.append (number), out.append ("++) {\n"); type.do_compilePredecessor (out, indent + 2, work, work, NULL); out.indent (indent), out.append ("}\n"); } if (notfirst || next) indent -= 2; if (!notfirst) break; } } void Constraint::compileReverseConversion (class StringBuffer& out, unsigned indent, const class Type& type, const char* number, const char* value, bool leaf) const { bool next = false; for (Constraint::const_iterator i = end (); i != begin (); next = true) { const class Range* range = *--i; const class Value& low = range->getLow (); const class Value& high = range->getHigh (); card_t num = type.convert (low); if (num) { out.indent (indent); if (next) out.append ("else "); out.append ("if ("), out.append (number); out.append (&low == &high ? "==" : ">="), out.append (num); out.append (")"); } else if (next) out.indent (indent), out.append ("else"); if (num || next) out.append (" {\n"), indent += 2; low.compileInit (value, indent, out); if (&low != &high) { if (leaf) { out.indent (indent); out.append (value); out.append ("+="); out.append (number); if (num) out.append ("-"), out.append (num); out.append (";\n"); } else { out.indent (indent), out.append ("for ("); if (num) out.append (number), out.append ("-="), out.append (num); out.append ("; "), out.append (number), out.append ("--; ) {\n"); type.do_compileSuccessor (out, indent + 2, value, value, 0); out.indent (indent), out.append ("}\n"); } } if (num || next) out.indent (indent -= 2), out.append ("}\n"); } } #endif // EXPR_COMPILE void Constraint::display (const class Printer& printer) const { if (empty ()) return; printer.delimiter ('(')++; for (const_iterator i = begin ();;) { (*i)->display (printer); if (++i == end ()) break; printer.delimiter (','); } --printer.delimiter (')'); } maria-1.3.5/Type/Constraint.h0000644000175000017500000001435207643253074016214 0ustar msmakelamsmakela// Type constraint class -*- c++ -*- #ifndef CONSTRAINT_H_ # define CONSTRAINT_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include "typedefs.h" /** @file Constraint.h * Constraint that limits the domain of a data type */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Value constraint */ class Constraint { public: /*@{*/ /** List of value ranges that the constraint allows */ typedef std::list List; /** Iterator to the range list */ typedef List::iterator iterator; /** Const iterator to the range list */ typedef List::const_iterator const_iterator; /*@}*/ /** Constructor */ Constraint (); /** Copy constructor * @param old constraint to be copied * @param type type of the new constraint */ Constraint (const class Constraint& old, const class Type& type); private: /** Copy constructor */ Constraint (const class Constraint& old); /** Assignment operator */ class Constraint& operator= (const class Constraint& old); public: /** Destructor */ ~Constraint (); /** Set the type of the constraint */ void setType (const class Type& type); /** Get the first value of the constraint * @return the smallest value */ const class Value& getFirstValue () const; /** Get the last value of the constraint * @return the largest value */ const class Value& getLastValue () const; /** Get the high bound of the value * @param value value whose high bound is to be sought * @return the high bound */ const class Value& getNextHigh (const class Value& value) const; /** Get the smallest high bound greater than the value * @param value value whose successor is to be sought * @return the successor of the value, or NULL */ const class Value* getNextLow (const class Value& value) const; /** Get the low bound of the value * @param value value whose high bound is to be sought * @return the high bound */ const class Value& getPrevLow (const class Value& value) const; /** Get the biggest high bound smaller than the value * @param value value whose predecessor is to be sought * @return the predecessor of the value, or NULL */ const class Value* getPrevHigh (const class Value& value) const; /** @name Accessors to the range list */ /*@{*/ bool empty () const { return myList.empty (); } size_t size () const { return myList.size (); } const_iterator begin () const { return myList.begin (); } const_iterator end () const { return myList.end (); } iterator begin () { return myList.begin (); } iterator end () { return myList.end (); } /*@}*/ /** Append a range to the constraint * @param range Range to be appended */ void append (class Range& range); /** Restrict the constraint by another constraint * @param constraint Constraint to be restricted by * @param type Type of this constraint */ void restrict (const class Constraint& constraint, const class Type& type); /** Determine whether the constraint encloses another constraint * @param other the other constraint to be investigated * @return true if all values accepted by the other constraint * are accepted by this constraint */ bool isSuperset (const class Constraint& other) const; /** Determine whether the two constraints are disjoint * @param other the other constraint * @return true if the constraints are disjoint */ bool isDisjoint (const class Constraint& other) const; /** Determine whether the constraint accepts a value * @param value value to be checked * @return true if the value passes the check */ bool isConstrained (const class Value& value) const; /** * Determine the number of possible values for this constraint * @return number of possible values */ card_t getNumValues () const; #ifdef EXPR_COMPILE /** Generate C code for checking the constraint * @param cexpr the compilation * @param indent indentation level * @param value C expression referring to the value */ void compileCheck (class CExpression& cexpr, unsigned indent, const char* value) const; /** Emit code for converting a value to a number * @param out output stream * @param indent indentation level * @param type the data type of the constraint * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning * @param work auxiliary variable (NULL for leaf types) */ void compileConversion (class StringBuffer& out, unsigned indent, const class Type& type, const char* value, const char* number, bool add, const char* work) const; /** Emit code for converting a number to a value * @param out output stream * @param indent indentation level * @param type the data type of the constraint * @param number number to be converted * @param value value to be computed * @param leaf flag: generate leaf type comparisons and assignments */ void compileReverseConversion (class StringBuffer& out, unsigned indent, const class Type& type, const char* number, const char* value, bool leaf) const; #endif // EXPR_COMPILE /** Display the constraint definition * @param printer the printer object */ void display (const class Printer& printer) const; private: /** List of ranges belonging to the constraint */ List myList; }; #endif // CONSTRAINT_H_ maria-1.3.5/Type/EnumType.C0000644000175000017500000001220707767301450015565 0ustar msmakelamsmakela// Enumerated type class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "EnumType.h" #include "LeafValue.h" #include "util.h" #include "Constraint.h" #include "Printer.h" /** @file EnumType.C * Enumerated data type */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ EnumType::EnumType () : Type (true), myEnums (), myReverseMap (), myNextValue (0) { } EnumType::EnumType (const class EnumType& old) : Type (old), myEnums (), myReverseMap (), myNextValue (old.myNextValue) { for (EnumMap::const_iterator i = old.myEnums.begin (); i != old.myEnums.end (); i++) { char* comp = newString (i->first); myEnums[comp] = i->second; myReverseMap[i->second] = comp; } } EnumType::~EnumType () { for (EnumMap::iterator i = myEnums.begin (); i != myEnums.end (); i++) delete[] i->first; } void EnumType::addEnumeration (char* name, card_t value) { assert (!getValue (name)); assert (!hasValue (value)); myEnums[name] = value; myReverseMap[value] = name; assert (myEnums.size () == myReverseMap.size ()); myNextValue = value + 1; } const card_t* EnumType::getValue (const char* name) const { EnumMap::const_iterator i = myEnums.find (const_cast(name)); return i == myEnums.end () ? NULL : &i->second; } class Value& EnumType::getFirstValue () const { const class Value* v = myConstraint ? &myConstraint->getFirstValue () : NULL; assert (!v || &v->getType () == this); return v ? *static_cast(v->copy ()) : *new class LeafValue (*this, getFirstEnum ()); } class Value& EnumType::getLastValue () const { const class Value* v = myConstraint ? &myConstraint->getLastValue () : NULL; assert (!v || &v->getType () == this); return v ? *static_cast(v->copy ()) : *new class LeafValue (*this, getLastEnum ()); } card_t EnumType::getFirstEnum () const { assert (!myReverseMap.empty ()); return myReverseMap.begin ()->first; } card_t EnumType::getLastEnum () const { assert (!myReverseMap.empty ()); return (--myReverseMap.end ())->first; } bool EnumType::hasValue (card_t value) const { return myReverseMap.find (value) != myReverseMap.end (); } const char* EnumType::getEnumName (card_t value) const { ReverseMap::const_iterator i = myReverseMap.find (value); return (i != myReverseMap.end ()) ? i->second : NULL; } bool EnumType::isConstrained (const class Value& value) const { assert (value.getType ().isAssignable (*this)); if (!myConstraint) { card_t v = card_t (static_cast(value)); return v >= getFirstEnum () && v <= getLastEnum (); } else return Type::isConstrained (value); } card_t EnumType::do_getNumValues () const { assert (!myConstraint); card_t numValues = getLastEnum () - getFirstEnum (); if (numValues < CARD_T_MAX) numValues++; return numValues; } card_t EnumType::convert (const class Value& value) const { assert (value.getKind () == Value::vLeaf); if (myConstraint) return Type::convert (value); return card_t (static_cast(value)) - getFirstEnum (); } class Value* EnumType::convert (card_t number) const { assert (number < getNumValues ()); if (myConstraint) return Type::convert (number); return new class LeafValue (*this, getFirstEnum () + number); } #ifdef EXPR_COMPILE # include "StringBuffer.h" void EnumType::compileDefinition (class StringBuffer& out, unsigned indent) const { out.indent (indent); out.append ("unsigned"); } void EnumType::do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { out.indent (indent); out.append (number); out.append (add ? "+=" : "="); out.append (value); out.append (";\n"); } #endif // EXPR_COMPILE void EnumType::display (const class Printer& printer) const { printer.printRaw ("enum "); printer.delimiter ('{')++; ReverseMap::const_iterator i = myReverseMap.begin (); if (i != myReverseMap.end ()) for (;;) { ReverseMap::const_iterator j = i++; printer.print ((*j).second); printer.delimiter ('='); printer.print ((*j).first); if (i == myReverseMap.end ()) break; printer.delimiter (','); } --printer.delimiter ('}'); if (myConstraint) myConstraint->display (printer); } maria-1.3.5/Type/EnumType.h0000644000175000017500000001172107643253074015633 0ustar msmakelamsmakela// Enumerated type class -*- c++ -*- #ifndef ENUMTYPE_H_ # define ENUMTYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include "Type.h" /** @file EnumType.h * Enumerated data type */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Enumerated type */ class EnumType : public Type { public: /** Constructor */ EnumType (); /** Copy constructor */ EnumType (const class EnumType& old); private: /** Assignment operator */ class EnumType& operator= (const class EnumType& old); public: /** Destructor */ ~EnumType (); /** Copy the Type */ class Type* copy () const { return new class EnumType (*this); } /** Add an enumeration symbol * @param name name of the symbol * @param value numeric value of the symbol */ void addEnumeration (char* name, card_t value); /** Add an enumeration symbol * @param name name of the symbol */ void addEnumeration (char* name) { addEnumeration (name, myNextValue); } /** Get the value of an enumeration symbol * @param name name of the symbol * @return pointer to the value, or NULL if not found */ const card_t* getValue (const char* name) const; /** Get the first enumeration value */ card_t getFirstEnum () const; /** Get the last enumeration value */ card_t getLastEnum () const; /** Determine whether the given value exists in the enumeration * @param value the enumeration value * @return true if the value exists in the enumeration */ bool hasValue (card_t value) const; /** Get the name of an enumeration constant * @param value numeric value of the constant * @return the name, or NULL if not found */ const char* getEnumName (card_t value) const; /** Determine the kind of the type */ enum Kind getKind () const { return tEnum; } /** Get the first value of this type */ class Value& getFirstValue () const; /** Get the last value of this type */ class Value& getLastValue () const; /** See if the type is assignable to another type * @param type the type this type should be assignable to * @return true if this type is assignable to the type */ bool isAssignable (const class Type& type) const { return &type == this; } /** Determine whether a value is compatible with the constraints of this type * @param value value to check * @return true if the value passes the constraint check */ bool isConstrained (const class Value& value) const; /** Get the number of possible values for this type */ card_t do_getNumValues () const; /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ class Value* convert (card_t number) const; # ifdef EXPR_COMPILE /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ void compileDefinition (class StringBuffer& out, unsigned indent) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; # endif // EXPR_COMPILE /** Display the type definition * @param printer the printer object */ void display (const class Printer& printer) const; private: /** Map of enumeration symbol names to enumeration symbol values */ typedef std::map EnumMap; /** Enumeration symbols */ EnumMap myEnums; typedef std::map ReverseMap; /** Reverse map from constants to symbols */ ReverseMap myReverseMap; /** Default value for next enumeration symbol that is declared */ card_t myNextValue; }; #endif // ENUMTYPE_H_ maria-1.3.5/Type/IdType.C0000644000175000017500000000467107643253074015224 0ustar msmakelamsmakela// Identifier type class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "IdType.h" #include "LeafValue.h" #include "Constraint.h" #include "Range.h" #include "Printer.h" /** @file IdType.C * Identifier data type */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class Value& IdType::getFirstValue () const { return *new class LeafValue (*this, 0); } class Value& IdType::getLastValue () const { return *new class LeafValue (*this, mySize - 1); } card_t IdType::do_getNumValues () const { assert (!myConstraint); return mySize; } card_t IdType::convert (const class Value& value) const { assert (&value.getType () == this); assert (!myConstraint); return card_t (static_cast(value)); } class Value* IdType::convert (card_t number) const { assert (number < mySize); assert (!myConstraint); return new class LeafValue (*this, number); } #ifdef EXPR_COMPILE # include "StringBuffer.h" void IdType::compileDefinition (class StringBuffer& out, unsigned indent) const { out.indent (indent); out.append ("unsigned"); } void IdType::do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { out.indent (indent); out.append (number); out.append (add ? "+=" : "="); out.append (value); out.append (";\n"); } #endif // EXPR_COMPILE void IdType::display (const class Printer& printer) const { printer.printRaw ("id"); printer.delimiter ('['); printer.print (mySize); printer.delimiter (']'); assert (!myConstraint); } maria-1.3.5/Type/IdType.h0000644000175000017500000000712707767301450015267 0ustar msmakelamsmakela// Identifier type class -*- c++ -*- #ifndef IDTYPE_H_ # define IDTYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Type.h" /** @file IdType.h * Identifier data type */ /* Copyright © 1998-2001,2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Identifier type */ class IdType : public Type { public: /** Constructor * @param size Number of values in the identifier pool */ IdType (card_t size) : Type (false), mySize (size) {} /** Copy constructor */ IdType (const class IdType& old) : Type (old), mySize (old.mySize) {} private: /** Assignment operator */ class IdType& operator= (const class IdType& old); public: /** Destructor */ ~IdType () {} /** Copy the Type */ class Type* copy () const { return new class IdType (*this); } /** Determine the kind of the type */ enum Kind getKind () const { return tId; } /** Get the first value of this type */ class Value& getFirstValue () const; /** Get the last value of this type */ class Value& getLastValue () const; /** Determine the number of values in the identifier pool */ card_t getSize () const { return mySize; } /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ class Value* convert (card_t number) const; /** See if the type is assignable to another type * @param type the type this type should be assignable to * @return true if this type is assignable to the type */ bool isAssignable (const class Type& type) const { return &type == this; } /** Get the number of possible values for this type */ card_t do_getNumValues () const; # ifdef EXPR_COMPILE /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ void compileDefinition (class StringBuffer& out, unsigned indent) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; # endif // EXPR_COMPILE /** Display the type definition * @param printer the printer object */ void display (const class Printer& printer) const; private: /** Number of values in the identifier pool */ const card_t mySize; }; #endif // IDTYPE_H_ maria-1.3.5/Type/IntType.C0000644000175000017500000000536607643253074015424 0ustar msmakelamsmakela// Integer type class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "IntType.h" #include "LeafValue.h" #include "Constraint.h" #include "Range.h" /** @file IntType.C * Signed integer data type */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class Value& IntType::getFirstValue () const { const class Value* v = myConstraint ? &myConstraint->getFirstValue () : NULL; assert (!v || &v->getType () == this); return v ? *static_cast(v->copy ()) : *new class LeafValue (*this, INT_T_MIN); } class Value& IntType::getLastValue () const { const class Value* v = myConstraint ? &myConstraint->getLastValue () : NULL; assert (!v || &v->getType () == this); return v ? *static_cast(v->copy ()) : *new class LeafValue (*this, INT_T_MAX); } card_t IntType::do_getNumValues () const { assert (!myConstraint); return CARD_T_MAX; } card_t IntType::convert (const class Value& value) const { assert (value.getKind () == Value::vLeaf); if (myConstraint) return Type::convert (value); return card_t (int_t (static_cast(value)) - INT_T_MIN); } class Value* IntType::convert (card_t number) const { assert (number < getNumValues ()); if (myConstraint) return Type::convert (number); return new class LeafValue (*this, int_t (card_t (INT_T_MIN) + number)); } #ifdef EXPR_COMPILE # include "StringBuffer.h" void IntType::compileDefinition (class StringBuffer& out, unsigned indent) const { out.indent (indent); out.append ("signed"); } void IntType::do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { out.indent (indent); out.append (number); out.append (add ? "+=" : "="); out.append ("(card_t) ("); out.append (value); out.append (");\n"); } #endif // EXPR_COMPILE maria-1.3.5/Type/IntType.h0000644000175000017500000000567207767301450015470 0ustar msmakelamsmakela// Integer type class -*- c++ -*- #ifndef INTTYPE_H_ # define INTTYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Type.h" /** @file IntType.h * Signed integer data type */ /* Copyright © 1998-2001,2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Signed integer type */ class IntType : public Type { public: /** Constructor */ IntType () : Type (true) {} /** Copy constructor */ IntType (const class IntType& old) : Type (old) {} private: /** Assignment operator */ class IntType& operator= (const class IntType& old); public: /** Destructor */ ~IntType () {} /** Copy the Type */ class Type* copy () const { return new class IntType (*this); } /** Determine the kind of the type */ enum Kind getKind () const { return tInt; } /** Get the first value of this type */ class Value& getFirstValue () const; /** Get the last value of this type */ class Value& getLastValue () const; /** Get the number of possible values for this type */ card_t do_getNumValues () const; /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ class Value* convert (card_t number) const; # ifdef EXPR_COMPILE /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ void compileDefinition (class StringBuffer& out, unsigned indent) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; # endif // EXPR_COMPILE }; #endif // INTTYPE_H_ maria-1.3.5/Type/Range.C0000644000175000017500000001031407727023574015054 0ustar msmakelamsmakela// Maria range class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Range.h" #include "LeafValue.h" #include "Type.h" #include "Printer.h" /** @file Range.C * Closed range of values, part of a Constraint */ /* Copyright © 1999-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Range::Range (class Value& low, class Value& high) : myLow (&low), myHigh (&high) { if (*myHigh < *myLow) { class Value* v = myLow; myLow = myHigh; myHigh = v; } else if (myLow != myHigh && *myLow == *myHigh) { delete myHigh; myHigh = myLow; } } Range::Range (const class Range& old) : myLow (old.myLow->copy ()), myHigh (old.myHigh->copy ()) { assert (*myLow <= *myHigh); } Range::~Range () { delete myLow; if (myLow != myHigh) delete myHigh; } void Range::setType (const class Type& type) { myLow->setType (type); myHigh->setType (type); } class Range* Range::combine (const class Range& other) const { if (*other.myLow <= *myLow && *myHigh <= *other.myHigh) return new class Range (*other.myLow->copy (), *other.myHigh->copy ()); if (*other.myLow <= *myLow && *myLow <= *other.myHigh) return new class Range (*other.myLow->copy (), *myHigh->copy ()); if (*other.myLow <= *myHigh && *myHigh <= *other.myHigh) return new class Range (*myLow->copy (), *other.myHigh->copy ()); if (*myLow <= *other.myLow && *other.myHigh <= *myHigh) return new class Range (*myLow->copy (), *myHigh->copy ()); class Value* v; bool adjacent; v = myHigh->copy (); adjacent = v->increment () && *v == *other.myLow; delete v; if (adjacent) return new class Range (*myLow->copy (), *other.myHigh->copy ()); v = other.myHigh->copy (); adjacent = v->increment () && *v == *myLow; delete v; if (adjacent) return new class Range (*other.myLow->copy (), *myHigh->copy ()); return 0; } class Range* Range::cut (const class Range& other) const { if (*other.myLow <= *myLow && *myHigh <= *other.myHigh) return new class Range (*myLow->copy (), *myHigh->copy ()); if (*other.myLow <= *myLow && *myLow <= *other.myHigh) return new class Range (*myLow->copy (), *other.myHigh->copy ()); if (*other.myLow <= *myHigh && *myHigh <= *other.myHigh) return new class Range (*other.myLow->copy (), *myHigh->copy ()); if (*myLow <= *other.myLow && *other.myHigh <= *myHigh) return new class Range (*other.myLow->copy (), *other.myHigh->copy ()); return 0; } bool Range::check (const class Value& value) const { return myLow == myHigh ? value == *myLow : *myLow <= value && value <= *myHigh; } void Range::display (const class Printer& printer) const { if (myLow != myHigh && myLow->getKind () == Value::vLeaf) { const class LeafValue& low = static_cast(*myLow); const class LeafValue& high = static_cast(*myHigh); switch (low.getType ().getKind ()) { case Type::tInt: if (int_t (low) != INT_T_MIN) low.display (printer); printer.printRaw (".."); if (int_t (high) != INT_T_MAX) high.display (printer); return; case Type::tCard: if (card_t (low)) low.display (printer); printer.printRaw (".."); if (card_t (high) != CARD_T_MAX) high.display (printer); return; default: break; } } myLow->display (printer); if (myLow != myHigh) { printer.printRaw (".."); myHigh->display (printer); } } maria-1.3.5/Type/Range.h0000644000175000017500000000503107643253074015116 0ustar msmakelamsmakela// Maria range class -*- c++ -*- #ifndef RANGE_H_ # define RANGE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ /** @file Range.h * Closed range of values, part of a Constraint */ /* Copyright © 1999-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Constant range */ class Range { public: /** Constructor * @param low Lower bound of the range * @param high Upper bound of the range */ Range (class Value& low, class Value& high); /** Copy constructor */ Range (const class Range& old); private: /** Assignment operator */ class Range& operator= (const class Range& old); public: /** Destructor */ ~Range (); /** Get the lower bound */ const class Value& getLow () const { return *myLow; } /** Get the higher bound */ const class Value& getHigh () const { return *myHigh; } /** Set the type of the Range * @param type type the limits of the range are to have */ void setType (const class Type& type); /** Combine the two ranges if possible * @return pointer to the union of both ranges, or NULL */ class Range* combine (const class Range& other) const; /** Determine the intersection of the two ranges * @return pointer to the intersection of both ranges, or NULL */ class Range* cut (const class Range& other) const; /** Check whether the value passes the range constraint * @param value Value to be checked * @return whether the value passes */ bool check (const class Value& value) const; /** Display the range * @param printer the printer object */ void display (const class Printer& printer) const; private: /** Lower bound */ class Value* myLow; /** Higher bound */ class Value* myHigh; }; #endif // RANGE_H_ maria-1.3.5/Type/StructType.C0000644000175000017500000003636607643253074016162 0ustar msmakelamsmakela// Struct type class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "StructType.h" #include "StructValue.h" #include "Constraint.h" #include "Printer.h" /** @file StructType.C * Struct data type */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class Value& StructType::getFirstValue () const { if (myConstraint) return *myConstraint->getFirstValue ().copy (); else { class StructValue* v = new class StructValue (*this); for (card_t i = 0; i < getSize (); i++) (*v)[i] = &(*this)[i].getFirstValue (); return *v; } } class Value& StructType::getLastValue () const { if (myConstraint) return *myConstraint->getLastValue ().copy (); else { class StructValue* v = new class StructValue (*this); for (card_t i = 0; i < getSize (); i++) (*v)[i] = &(*this)[i].getLastValue (); return *v; } } bool StructType::isAssignable (const class Type& type) const { if (&type == this) return true; if (type.getKind () != getKind ()) return Type::isAssignable (type); return myComponents.isAssignable (static_cast(type).myComponents); } bool StructType::isAlwaysAssignable (const class Type& type) const { if (&type == this) return true; if (type.getKind () != getKind ()) return false; return myComponents.isAlwaysAssignable (static_cast(type).myComponents); } bool StructType::isConstrained (const class Value& value) const { assert (value.getType ().isAssignable (*this)); const class StructValue& v = static_cast(value); assert (v.getSize () == getSize ()); for (card_t i = getSize (); i--; ) if (!(*this)[i].isConstrained (v[i])) return false; return Type::isConstrained (value); } card_t StructType::do_getNumValues () const { assert (!myConstraint); card_t numValues = 1; for (card_t i = 0; i < myComponents.getSize (); i++) { card_t num = myComponents[i].getNumValues (); if (num != CARD_T_MAX && num < CARD_T_MAX / numValues) numValues *= num; else return CARD_T_MAX; } return numValues; } card_t StructType::convert (const class Value& value) const { assert (value.getKind () == Value::vStruct); assert (isConstrained (value)); assert (getNumValues () < CARD_T_MAX); if (myConstraint) return Type::convert (value); if (!myComponents.getSize ()) return 0; card_t number = 0; const class StructValue& v = static_cast(value); for (card_t i = myComponents.getSize (); --i; ) { number += myComponents[i].convert (v[i]); number *= myComponents[i - 1].getNumValues (); } number += myComponents[0u].convert (v[0]); assert (number < getNumValues ()); return number; } class Value* StructType::convert (card_t number) const { assert (number < getNumValues ()); assert (getNumValues () < CARD_T_MAX); if (myConstraint) return Type::convert (number); class StructValue* value = new class StructValue (*this); if (myComponents.getSize ()) { const card_t size = myComponents.getSize (); for (card_t i = 0; i < size; i++) { const card_t card = myComponents[i].getNumValues (); card_t num = number % card; number /= card; (*value)[i] = myComponents[i].convert (num); } } assert (isConstrained (*value)); return value; } #ifdef EXPR_COMPILE # include "CExpression.h" # include void StructType::compile (class StringBuffer& out) { for (card_t i = 0; i < myComponents.getSize (); i++) const_cast(myComponents[i]).compile (out); Type::compile (out); } void StructType::compileDefinition (class StringBuffer& out, unsigned indent) const { out.indent (indent), out.append ("struct {\n"); for (card_t i = 0; i < myComponents.getSize (); i++) { out.indent (indent + 2), myComponents[i].appendName (out); out.append (" s"), out.append (i), out.append (";\n"); } out.indent (indent), out.append ("}"); } bool StructType::compileEqual (class StringBuffer& out, unsigned indent, const char* left, const char* right, bool equal, bool first, bool last, bool backslash) const { if (!myComponents.getSize ()) return false; size_t llen = strlen (left), rlen = strlen (right); char* l = new char[llen + 23]; char* r = new char[rlen + 23]; memcpy (l, left, llen); memcpy (r, right, rlen); bool gen = false, genAny = false; for (card_t i = myComponents.getSize (); i--; ) { snprintf (l + llen, 23, ".s%u", i); snprintf (r + rlen, 23, ".s%u", i); gen = myComponents[i].compileEqual (out, indent, l, r, equal, first, !i, backslash); if (gen) genAny = true, first = false; } delete[] l; delete[] r; if (gen) { if (!last) out.append (backslash ? (equal ? "&&\\\n" : "||\\\n") : (equal ? "&&\n" : "||\n")); } else if (genAny && last) out.indent (indent); return gen || !last; } void StructType::compileCompare3 (class StringBuffer& out, const char* condition, const char* component) const { const size_t len = strlen (component); char* const newcomp = new char[len + 23]; char* const offset = newcomp + len; memcpy (newcomp, component, len); for (card_t i = myComponents.getSize (); i--; ) { snprintf (offset, 23, ".s%u", i); myComponents[i].compileCompare3 (out, condition, newcomp); } delete[] newcomp; } void StructType::do_compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { if (!myComponents.getSize ()) return; size_t llen = strlen (lvalue), rlen = strlen (rvalue); char* lval = new char[llen + 23]; char* rval = new char[rlen + 23]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); out.indent (indent); out.append ("do {\n"); if (!wrap) { wrap = "wrap"; out.indent (indent + 2); out.append ("bool_t "); out.append (wrap); out.append ("=0;\n"); } for (card_t i = 0;; ) { snprintf (lval + llen, 23, ".s%u", i); snprintf (rval + rlen, 23, ".s%u", i); myComponents[i].compileSuccessor (out, indent + 2, lval, rval, wrap); if (++i < myComponents.getSize ()) { out.indent (indent + 2); out.append ("if (!"); out.append (wrap); out.append (") {\n"); if (lvalue != rvalue && strcmp (lvalue, rvalue)) { for (card_t j = i; j < myComponents.getSize (); j++) { out.indent (indent + 4); out.append (lvalue); out.append (".s"); out.append (j); out.append ("="); out.append (rvalue); out.append (".s"); out.append (j); out.append (";\n"); } } out.indent (indent + 4); out.append ("continue;\n"); out.indent (indent + 2); out.append ("}\n"); out.indent (indent + 2); out.append (wrap); out.append ("=0;\n"); } else break; } out.indent (indent); out.append ("} while (0);\n"); delete[] lval; delete[] rval; } void StructType::do_compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { if (!myComponents.getSize ()) return; size_t llen = strlen (lvalue), rlen = strlen (rvalue); char* lval = new char[llen + 23]; char* rval = new char[rlen + 23]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); out.indent (indent); out.append ("do {\n"); if (!wrap) { wrap = "wrap"; out.indent (indent + 2); out.append ("bool_t "); out.append (wrap); out.append ("=0;\n"); } for (card_t i = 0;; ) { snprintf (lval + llen, 23, ".s%u", i); snprintf (rval + rlen, 23, ".s%u", i); myComponents[i].compilePredecessor (out, indent + 2, lval, rval, wrap); if (++i < myComponents.getSize ()) { out.indent (indent + 2); out.append ("if (!"); out.append (wrap); out.append (") {\n"); if (lvalue != rvalue && strcmp (lvalue, rvalue)) { for (card_t j = i; j < myComponents.getSize (); j++) { out.indent (indent + 4); out.append (lvalue); out.append (".s"); out.append (j); out.append ("="); out.append (rvalue); out.append (".s"); out.append (j); out.append (";\n"); } } out.indent (indent + 4); out.append ("continue;\n"); out.indent (indent + 2); out.append ("}\n"); out.indent (indent + 2); out.append (wrap); out.append ("=0;\n"); } else break; } out.indent (indent); out.append ("} while (0);\n"); delete[] lval; delete[] rval; } void StructType::compileCast (class CExpression& cexpr, unsigned indent, const class Type& target, const char* lvalue, const char* rvalue) const { assert (isAssignable (target)); if (target.getKind () != Type::tStruct) Type::compileCast (cexpr, indent, target, lvalue, rvalue); else { const class StructType& st = static_cast(target); assert (getSize () == st.getSize ()); size_t llen = strlen (lvalue); size_t rlen = strlen (rvalue); char* lval = new char[llen + 23]; char* rval = new char[llen + 23]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); for (card_t i = getSize (); i--; ) { snprintf (lval + llen, 23, ".s%u", i); snprintf (rval + rlen, 23, ".s%u", i); myComponents[i].compileCast (cexpr, indent, st[i], lval, rval); } delete[] lval; delete[] rval; if (const class Constraint* c = target.getConstraint ()) c->compileCheck (cexpr, indent, lvalue); } } void StructType::do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { card_t i = myComponents.getSize (); assert (getNumValues () < CARD_T_MAX && i); size_t length = strlen (value); char* val = new char[length + 23]; char* offset = val + length; memcpy (val, value, length); memcpy (offset, ".s0", 4); if (myComponents[0u].getNumValues () == getNumValues ()) myComponents[0u].compileConversion (out, indent, val, number, add); else if (--i) { const char* num = number; if (add) { out.indent (indent), out.append ("{\n"); out.indent (indent += 2), out.append ("card_t "); length = strlen (number); char* nbr = new char[length + 2]; memcpy (nbr, number, length); memcpy (nbr + length, "_", 2); num = nbr; out.append (num), out.append (";\n"); } for (bool next = false; i; next = true) { snprintf (offset, 23, ".s%u", i); myComponents[i].compileConversion (out, indent, val, num, next); const card_t numValues = myComponents[--i].getNumValues (); if (numValues != 1) { out.indent (indent), out.append (num), out.append ("*="); out.append (numValues), out.append (";\n"); } } memcpy (offset, ".s0", 4); myComponents[0u].compileConversion (out, indent, val, num, true); if (add) { out.indent (indent), out.append (number), out.append ("+="); out.append (num), out.append (";\n"); out.indent (indent -= 2), out.append ("}\n"); delete[] num; } } else myComponents[0u].compileConversion (out, indent, val, number, add); delete[] val; } void StructType::compileReverseConversion (class StringBuffer& out, unsigned indent, const char* number, const char* value) const { if (myConstraint) Type::compileReverseConversion (out, indent, number, value); else if (getNumValues () == 1) compileBottom (out, indent, value); else { size_t length = strlen (value); char* val = new char[length + 23]; char* offset = val + length; memcpy (val, value, length); switch (myComponents.getSize ()) { case 0: assert (false); break; default: if (myComponents[0u].getNumValues () != getNumValues ()) { length = strlen (number); char* num = new char[length + 2]; memcpy (num, number, length); memcpy (num + length, "_", 2); out.indent (indent), out.append ("{\n"); out.indent (indent + 2); out.append ("card_t "), out.append (num), out.append (";\n"); for (card_t i = 0; i < myComponents.getSize (); i++) { snprintf (offset, 23, ".s%u", i); card_t numValues = myComponents[i].getNumValues (); if (numValues != 1) { out.indent (indent + 2); out.append (num), out.append ("="), out.append (number); out.append ("%"), out.append (numValues); out.append (", "); out.append (number), out.append ("/="); out.append (numValues); out.append (";\n"); myComponents[i].compileReverseConversion (out, indent + 2, num, val); } else myComponents[i].compileBottom (out, indent + 2, val); } out.indent (indent), out.append ("}\n"); delete[] num; break; } else { for (card_t i = myComponents.getSize (); --i; ) { snprintf (offset, 23, ".s%u", i); myComponents[i].compileBottom (out, indent, val); } } // fall through case 1: memcpy (offset, ".s0", 4); myComponents[0u].compileReverseConversion (out, indent, number, val); } delete[] val; } } void StructType::compileEncoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const { if (getNumValues () < CARD_T_MAX) Type::compileEncoder (cexpr, indent, func, value); else { size_t length = strlen (value); char* val = new char[length + 23]; char* offset = val + length; memcpy (val, value, length); for (card_t i = 0; i < myComponents.getSize (); i++) { snprintf (offset, 23, ".s%u", i); myComponents[i].compileEncoder (cexpr, indent, func, val); } delete[] val; } } void StructType::compileDecoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const { if (getNumValues () < CARD_T_MAX) Type::compileDecoder (cexpr, indent, func, value); else { size_t length = strlen (value); char* val = new char[length + 23]; char* offset = val + length; memcpy (val, value, length); for (card_t i = 0; i < myComponents.getSize (); i++) { snprintf (offset, 23, ".s%u", i); myComponents[i].compileDecoder (cexpr, indent, func, val); } delete[] val; } } #endif // EXPR_COMPILE void StructType::display (const class Printer& printer) const { printer.printRaw ("struct "); printer.delimiter ('{')++; myComponents.display (printer); --printer.delimiter ('}'); if (myConstraint) myConstraint->display (printer); } maria-1.3.5/Type/StructType.h0000644000175000017500000002116007767301450016210 0ustar msmakelamsmakela// Struct type class -*- c++ -*- #ifndef STRUCTTYPE_H_ # define STRUCTTYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "ComponentList.h" /** @file StructType.h * Struct data type */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Struct type */ class StructType : public Type { public: /** Constructor * @param components Components of the struct */ StructType (class ComponentList& components) : Type (components.isOrdered ()), myComponents (components) { delete &components; } /** Copy constructor */ StructType (const class StructType& old) : Type (old), myComponents (old.myComponents) {} private: /** Assignment operator */ class StructType& operator= (const class StructType& old); public: /** Destructor */ ~StructType () {} /** Copy the Type */ class Type* copy () const { return new class StructType (*this); } /** Determine the kind of the type */ enum Kind getKind () const { return tStruct; } /** Get the first value of this type */ class Value& getFirstValue () const; /** Get the last value of this type */ class Value& getLastValue () const; /** Determine the number of components in the type */ card_t getSize () const { return myComponents.getSize (); } /** Get a component by name * @param name name of the component * @return pointer to the component, or NULL if not found */ const class Type* operator[] (const char* name) const { return myComponents[name]; } /** Get a component by index number * @param i index to the component * @return reference to the component */ const class Type& operator[] (card_t i) const { return myComponents[i]; } /** Get the index number of a component * @param name name of the component * @return index of the component */ card_t getIndex (const char* name) const { return myComponents.getIndex (name); } /** Get the name of a component * @param i index of the component * @return name of the component */ const char* getComponentName (card_t i) const { return myComponents.getName (i); } /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ class Value* convert (card_t number) const; /** See if the type is assignable to another type * @param type the type this type should be assignable to * @return true if this type is assignable to the type */ bool isAssignable (const class Type& type) const; /** See if the type is always assignable to another type * @param type the type this type should always be assignable to * @return true if this type always is assignable to the type */ bool isAlwaysAssignable (const class Type& type) const; /** Determine whether a value is compatible with the constraints of this type * @param value value to check * @return true if the value passes the constraint check */ bool isConstrained (const class Value& value) const; /** Get the number of possible values for this type */ card_t do_getNumValues () const; # ifdef EXPR_COMPILE /** Generate a C type declaration and auxiliary functions * @param out output stream for the declarations */ void compile (class StringBuffer& out); /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ void compileDefinition (class StringBuffer& out, unsigned indent) const; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param left left-hand-side C expression to be compared * @param right right-hand-side C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @param backslash flag: prepend all newlines with backslashes * @return true if any code was generated */ bool compileEqual (class StringBuffer& out, unsigned indent, const char* left, const char* right, bool equal, bool first, bool last, bool backslash) const; /** Generate three-way comparison statements * @param out output stream * @param condition additional condition for the comparison (NULL=none) * @param component component to be compared */ void compileCompare3 (class StringBuffer& out, const char* condition, const char* component) const; /** Generate statements for incrementing an unconstrained value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose successor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ void do_compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Generate statements for decrementing an unconstrained value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose predecessor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ void do_compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Emit code for converting a value of this type to another * @param cexpr the compilation * @param indent indentation level * @param target target type * @param lvalue left-hand-side value of the assignment * @param rvalue C expression for the value to be converted */ void compileCast (class CExpression& cexpr, unsigned indent, const class Type& target, const char* lvalue, const char* rvalue) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; /** Emit code for converting a number to a value * @param out output stream * @param indent indentation level * @param number number to be converted * @param value value to be computed */ void compileReverseConversion (class StringBuffer& out, unsigned indent, const char* number, const char* value) const; /** Emit code for encoding a value * @param cexpr the compilation * @param indent indentation level * @param func name of the encoding function * @param value value to be encoded */ void compileEncoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const; /** Emit code for decoding a value * @param cexpr the compilation * @param indent indentation level * @param func name of the decoding function * @param value value to be decoded */ void compileDecoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const; # endif // EXPR_COMPILE /** Display the type definition * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The struct components */ class ComponentList myComponents; }; #endif // STRUCTTYPE_H_ maria-1.3.5/Type/Type.C0000644000175000017500000004374507767301450014753 0ustar msmakelamsmakela// Data type base class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "UnionType.h" #include "Constraint.h" #include "Range.h" #include "Value.h" #include "Printer.h" /** @file Type.C * Abstract base class for data types */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Type::Type (bool ordered) : myNumValues (0), myName (0), myIsOrdered (ordered), myConstraint (0) #ifdef EXPR_COMPILE , myIndex (0), myGenerated (false), myFather (0) #endif // EXPR_COMPILE { } Type::Type (const class Type& old) : myNumValues (0), myName (0), myIsOrdered (old.myIsOrdered), myConstraint (old.myConstraint ? new class Constraint (*old.myConstraint, *this) : 0) #ifdef EXPR_COMPILE , myIndex (old.myIndex), myGenerated (old.myGenerated), myFather (&old) #endif // EXPR_COMPILE { } Type::~Type () { delete[] myName; delete myConstraint; } const char* Type::getSyntacticName () const { switch (getKind ()) { case tInt: return "int"; case tCard: return "unsigned"; case tBool: return "bool"; case tChar: return "char"; case tEnum: return "enum"; case tId: return "id"; case tStruct: return "struct"; case tVector: return "vector"; case tUnion: return "union"; case tBuffer: return "buffer"; } return ""; } bool Type::isAssignable (const class Type& type) const { if (type.getKind () == getKind ()) return (!type.getConstraint () || !getConstraint () || !type.getConstraint ()->isDisjoint (*getConstraint ())); else return type.getKind () == tUnion && static_cast(type).isAssignableFrom (*this); } bool Type::isAlwaysAssignable (const class Type& type) const { if (type.getKind () == getKind ()) return isAssignable (type) && (!type.getConstraint () || (getConstraint () && type.getConstraint ()->isSuperset (*getConstraint ()))); else return type.getKind () == tUnion && static_cast(type).isAlwaysAssignableFrom (*this); } bool Type::isConstrained (const class Value& value) const { assert (value.getType ().isAssignable (*this)); return !getConstraint () || getConstraint ()->isConstrained (value); } card_t Type::getNumConstrainedValues () const { assert (!!myConstraint); return myConstraint->getNumValues (); } void Type::setConstraint (class Constraint& constraint) { assert (!myConstraint); if (constraint.empty ()) delete &constraint; else (myConstraint = &constraint)->setType (*this); } card_t Type::convert (const class Value& value) const { assert (myConstraint && !myConstraint->empty ()); assert (myNumValues && myNumValues < CARD_T_MAX); card_t number = 0; for (Constraint::const_iterator i = myConstraint->begin (); i != myConstraint->end (); i++) { const class Range* r = *i; const class Value& low = r->getLow (); const class Value& high = r->getHigh (); assert (!(high < low)); if (high < value) number += high - low + 1; else { number += value - low; break; } } assert (number < myNumValues); return number; } class Value* Type::convert (card_t number) const { assert (myConstraint && !myConstraint->empty ()); assert (number < myNumValues); class Value* value = NULL; for (Constraint::const_iterator i = myConstraint->begin (); i != myConstraint->end (); i++) { const class Range* r = *i; const class Value& low = r->getLow (); const class Value& high = r->getHigh (); assert (!(high < low)); card_t diff = high - low + 1; if (number >= diff) number -= diff; else { value = low.copy (); while (number--) if (!value->increment ()) assert (false); break; } } assert (isConstrained (*value)); return value; } #ifdef EXPR_COMPILE # include "Net.h" # include "Range.h" # include "CExpression.h" # include "util.h" # include void Type::uncompile () { myIndex = 0; myGenerated = false; if (myFather) const_cast(myFather)->uncompile (); } bool Type::isGenerated () { assert (!myFather || !myGenerated); if (myFather) return const_cast(myFather)->isGenerated (); bool g = myGenerated; myGenerated = true; return g; } /** Number of compiled types */ static unsigned numCompiled = 0; void Type::uncompileAll () { numCompiled = 0; } void Type::compile (class StringBuffer& out) { if (myIndex) return; else if (myFather) { const_cast(myFather)->compile (out); myIndex = myFather->myIndex; assert (myIndex > 0); return; } myIndex = ++numCompiled; /** add a constraint for an enumeration if there is none yet */ if (!myConstraint && getKind () == tEnum) { class Constraint* c = new class Constraint (); class Value* low = &getFirstValue (); class Value* high = getNumValues () == 1 ? low : &getLastValue (); c->append (*new class Range (*low, *high)); setConstraint (*c); } out.append ("#define ID(id) id##"); out.append (myIndex); out.append ("\ntypedef "); compileDefinition (out, 0); out.append (" TYPE;\nDECLARE_MULTISET_OPS;\n#undef ID\n"); compileExtraDefinitions (out, 0, true); } void Type::compileExtraDefinitions (class StringBuffer& out, unsigned, bool interface) const { if (interface) return; // three-way comparison out.append ("#define CMP3(l,r,L,G)"); compileCompare3 (out); // equality comparison out.append ("\n#define EQ(l,r) "); if (!compileEqual (out, 16, "l", "r", true, true, true, true)) out.append ("1"); out.append ("\n"); } bool Type::compileEqual (class StringBuffer& out, unsigned indent, const char* left, const char* right, bool equal, bool first, bool last, bool backslash) const { assert (isLeaf ()); if (!first) out.indent (indent); out.append (left); out.append (equal ? "==" : "!="); out.append (right); if (last); else if (backslash) out.append (equal ? "&&\\\n" : "||\\\n"); else out.append (equal ? "&&\n" : "||\n"); return true; } void Type::compileCompare3 (class StringBuffer& out, const char* condition, const char* component) const { assert (isLeaf ()); compileLeafCompare3 (out, condition, component); } void Type::compileLeafCompare3 (class StringBuffer& out, const char* condition, const char* component) { out.append ("\\\n "); if (condition) { out.append ("CC3("); out.append (condition); out.append (",l,r,"); out.append (component); out.append (",L,G)"); } else { out.append ("C3(l,r,"); out.append (component); out.append (",L,G)"); } } void Type::compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { if (isLeaf ()) do_compileSuccessor (out, indent, lvalue, rvalue, wrap); else if (getNumValues () == 1) { if (lvalue != rvalue && strcmp (lvalue, rvalue)) { out.indent (indent); out.append (lvalue); out.append ("="); out.append (rvalue); out.append (";\n"); } if (wrap) out.indent (indent), out.append (wrap), out.append ("=1;\n"); } else { out.indent (indent); out.append ("if ("); class Value* max = &getLastValue (); if (!max->compileEqual (out, indent + 4, rvalue, true, true, true)) assert (false); delete max; out.append (") {\n"); compileBottom (out, indent + 2, lvalue); if (wrap) { out.indent (indent + 2); out.append (wrap); out.append ("=1;\n"); } out.indent (indent); out.append ("}\n"); if (myConstraint) { for (Constraint::const_iterator i = myConstraint->begin (); ++i != myConstraint->end (); ) { i--; out.indent (indent); out.append ("else if ("); if (!(*i)->getHigh ().compileEqual (out, indent + 9, rvalue, true, true, true)) assert (false); out.append (") {\n"); i++; (*i)->getLow ().compileInit (lvalue, indent + 2, out); out.indent (indent); out.append ("}\n"); } } out.indent (indent); out.append ("else {\n"); do_compileSuccessor (out, indent + 2, lvalue, rvalue, wrap); out.indent (indent); out.append ("}\n"); } } void Type::compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { if (isLeaf ()) do_compilePredecessor (out, indent, lvalue, rvalue, wrap); else if (getNumValues () == 1) { if (lvalue != rvalue && strcmp (lvalue, rvalue)) { out.indent (indent); out.append (lvalue); out.append ("="); out.append (rvalue); out.append (";\n"); } if (wrap) out.indent (indent), out.append (wrap), out.append ("=1;\n"); } else { out.indent (indent); out.append ("if ("); class Value* min = &getFirstValue (); if (!min->compileEqual (out, indent + 4, rvalue, true, true, true)) assert (false); delete min; out.append (") {\n"); compileTop (out, indent + 2, lvalue); if (wrap) { out.indent (indent + 2); out.append (wrap); out.append ("=1;\n"); } out.indent (indent); out.append ("}\n"); if (myConstraint) { for (Constraint::const_iterator i = myConstraint->begin (); ++i != myConstraint->end (); ) { out.indent (indent); out.append ("else if ("); if (!(*i)->getLow ().compileEqual (out, indent + 9, rvalue, true, true, true)) assert (false); out.append (") {\n"); /** iterator to the previous range */ Constraint::const_iterator j = i; j--; (*j)->getHigh ().compileInit (lvalue, indent + 2, out); out.indent (indent); out.append ("}\n"); } } out.indent (indent); out.append ("else {\n"); do_compilePredecessor (out, indent + 2, lvalue, rvalue, wrap); out.indent (indent); out.append ("}\n"); } } void Type::do_compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { assert (isLeaf ()); out.indent (indent); out.append ("switch ("); out.append (rvalue); out.append (") {\n"); if (myConstraint) { for (Constraint::const_iterator i = myConstraint->begin (); i != myConstraint->end (); ) { out.indent (indent); out.append ("case "); (*i)->getHigh ().compile (out); out.append (":\n"); i++; if (i != myConstraint->end ()) (*i)->getLow ().compileInit (lvalue, indent + 2, out); else { if (wrap) { out.indent (indent + 2); out.append (wrap); out.append ("=1;\n"); } compileBottom (out, indent + 2, lvalue); } out.indent (indent + 2); out.append ("break;\n"); } } else { out.indent (indent); out.append ("case "); class Value* max = &getLastValue (); max->compile (out); delete max; out.append (":\n"); if (wrap) { out.indent (indent + 2); out.append (wrap); out.append ("=1;\n"); } compileBottom (out, indent + 2, lvalue); out.indent (indent + 2); out.append ("break;\n"); } out.indent (indent); out.append ("default:\n"); out.indent (indent + 2); out.append (lvalue); out.append ("="); out.append (rvalue); out.append ("+1;\n"); out.indent (indent); out.append ("}\n"); } void Type::do_compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { assert (isLeaf ()); out.indent (indent); out.append ("switch ("); out.append (rvalue); out.append (") {\n"); if (myConstraint) { for (Constraint::const_iterator i = myConstraint->end (); i != myConstraint->begin (); ) { const class Value* high = i == myConstraint->end () ? NULL : &(*i)->getHigh (); i--; out.indent (indent); out.append ("case "); (*i)->getLow ().compile (out); out.append (":\n"); if (!high && wrap) { out.indent (indent + 2); out.append (wrap); out.append ("=1;\n"); } if (high) high->compileInit (lvalue, indent + 2, out); else compileTop (out, indent + 2, lvalue); out.indent (indent + 2); out.append ("break;\n"); } } else { out.indent (indent); out.append ("case "); class Value* min = &getFirstValue (); min->compile (out); delete min; out.append (":\n"); if (wrap) { out.indent (indent + 2); out.append (wrap); out.append ("=1;\n"); } compileTop (out, indent + 2, lvalue); out.indent (indent + 2); out.append ("break;\n"); } out.indent (indent); out.append ("default:\n"); out.indent (indent + 2); out.append (lvalue); out.append ("="); out.append (rvalue); out.append ("-1;\n"); out.indent (indent); out.append ("}\n"); } void Type::compileBottom (class StringBuffer& out, unsigned indent, const char* value) const { class Value* v = &getFirstValue (); v->compileInit (value, indent, out); delete v; } void Type::compileTop (class StringBuffer& out, unsigned indent, const char* value) const { class Value* v = &getLastValue (); v->compileInit (value, indent, out); delete v; } void Type::appendIndex (class StringBuffer& out) const { out.append (myIndex); } void Type::compileCast (class CExpression& cexpr, unsigned indent, const class Type& target, const char* lvalue, const char* rvalue) const { assert (lvalue && rvalue); if (target.getKind () == tUnion) static_cast(target).compileCastFrom (cexpr, indent, *this, lvalue, rvalue); else { assert (isLeaf ()); class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append (lvalue); out.append ("=("); target.appendName (out); out.append (")"); out.append (rvalue); out.append (";\n"); if (target.myConstraint) target.myConstraint->compileCheck (cexpr, indent, lvalue); } } void Type::compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { if (getNumValues () == 1) { if (!add) { out.indent (indent); out.append (number); out.append ("=0;\n"); } } else if (myConstraint) { if (isLeaf ()) myConstraint->compileConversion (out, indent, *this, value, number, add, 0); else { out.indent (indent), out.append ("{\n"); out.indent (indent + 2), appendName (out), out.append (" w;\n"); myConstraint->compileConversion (out, indent + 2, *this, value, number, add, "w"); out.indent (indent), out.append ("}\n"); } } else do_compileConversion (out, indent, value, number, add); } void Type::compileReverseConversion (class StringBuffer& out, unsigned indent, const char* number, const char* value) const { assert (isLeaf () || myConstraint); if (myConstraint) myConstraint->compileReverseConversion (out, indent, *this, number, value, isLeaf ()); else { out.indent (indent); out.append (value); out.append ("="); if (getKind () == tInt) out.append ("(signed) "); out.append (number); out.append (";\n"); } } void Type::compileEncoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const { assert (isLeaf () || getNumValues () < CARD_T_MAX); if (getNumValues () > 1) { class StringBuffer& out = cexpr.getOut (); const char* number = cexpr.getVarCount (); compileConversion (out, indent, value, number, false); out.indent (indent); out.append (func); out.append (" ("); out.append (number); out.append (", "); out.append (log2 (getNumValues ())); out.append (");\n"); } } void Type::compileDecoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const { assert (isLeaf () || getNumValues () < CARD_T_MAX); if (getNumValues () > 1) { class StringBuffer& out = cexpr.getOut (); const char* number = cexpr.getVarCount (); out.indent (indent); out.append (number); out.append (" = "); out.append (func); out.append (" ("); out.append (log2 (getNumValues ())); out.append (");\n"); compileReverseConversion (out, indent, number, value); } else { class Value* min = &getFirstValue (); min->compileInit (value, indent, cexpr.getOut ()); delete min; } } void Type::appendName (class StringBuffer& out) const { if (myIndex) { out.append ("t"); out.append (myIndex); } else { assert (isLeaf () && !myConstraint); switch (getKind ()) { case tInt: out.append ("signed"); return; case tBool: out.append ("bool_t"); return; case tChar: out.append ("unsigned char"); return; case tCard: case tEnum: case tId: out.append ("unsigned"); return; case tStruct: case tVector: case tUnion: case tBuffer: assert (false); } } } void Type::appendMSetName (class StringBuffer& out) const { assert (myIndex); out.append ("struct tree"); out.append (myIndex); } #endif // EXPR_COMPILE void Type::display (const class Printer& printer) const { printer.printRaw (getSyntacticName ()); if (myConstraint) myConstraint->display (printer); } maria-1.3.5/Type/Type.h0000644000175000017500000003424707767301450015015 0ustar msmakelamsmakela// Data type base class -*- c++ -*- #ifndef TYPE_H_ # define TYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "util.h" # include # include /** @file Type.h * Abstract base class for data types */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Data type base class */ class Type { public: /** Type kinds (@see getKind) */ enum Kind { tInt, tCard, tBool, tChar, tEnum, tId, tStruct, tVector, tUnion, tBuffer }; /** Constructor * @param ordered flag: is this an ordered type? */ Type (bool ordered); protected: /** Copy constructor */ Type (const class Type& old); private: /** Assignment operator */ class Type& operator= (const class Type& old); public: /** Destructor */ virtual ~Type (); /** Copy Type */ virtual class Type* copy () const = 0; /** Determine the kind of the type */ virtual enum Kind getKind () const = 0; /** Set the name of the type */ void setName (char* name) { assert (!myName); myName = name; } /** Determine the name of the type */ const char* getName () const { return myName; } /** Determine the syntactic name of the type */ const char* getSyntacticName () const; /** Determine whether the type is ordered */ bool isOrdered () const { return myIsOrdered; } /** Get the first value of this type (only for ordered types) */ virtual class Value& getFirstValue () const = 0; /** Get the last value of this type (only for ordered types) */ virtual class Value& getLastValue () const = 0; /** See if the type is assignable to another type * @param type the type this type should be assignable to * @return true if this type is assignable to the type */ virtual bool isAssignable (const class Type& type) const; /** See if the type is always assignable to another type * @param type the type this type should always be assignable to * @return true if this type always is assignable to the type */ virtual bool isAlwaysAssignable (const class Type& type) const; /** See if two types are assignable to each other * @param type1 first type to be checked * @param type2 second type to be checked * @return true if the types are compatible with each other */ static bool isCompatible (const class Type& type1, const class Type& type2) { return type1.isAssignable (type2) && type2.isAssignable (type1); } /** See if two types always are assignable to each other * @param type1 first type to be checked * @param type2 second type to be checked * @return true if the types always are compatible with each other */ static bool isAlwaysCompatible (const class Type& type1, const class Type& type2) { return type1.isAlwaysAssignable (type2) && type2.isAlwaysAssignable (type1); } /** Determine whether a value is compatible with the constraints of this type * @param value value to check * @return true if the value passes the constraint check */ virtual bool isConstrained (const class Value& value) const; /** * Determine the number of possible values for this type or CARD_T_MAX, * if there are >= CARD_T_MAX possible values * @return number of possible values */ card_t getNumValues () const { if (myNumValues); else if (myConstraint) myNumValues = getNumConstrainedValues (); else myNumValues = do_getNumValues (); assert (myNumValues); return myNumValues; } private: /** * Determine the number of possible values for this constrained type * @return number of possible values */ card_t getNumConstrainedValues () const; /** Determine the number of possible values for this type or CARD_T_MAX, * if there are >= CARD_T_MAX possible values * @return number of possible values */ virtual card_t do_getNumValues () const = 0; public: /** Set the constraint */ void setConstraint (class Constraint& constraint); /** Get the constraint */ const class Constraint* getConstraint () const { return myConstraint; } /** Get the constraint */ class Constraint* getConstraint () { return myConstraint; } /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ virtual card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ virtual class Value* convert (card_t number) const; /** Determine whether this is a leaf type */ bool isLeaf () const { switch (getKind ()) { case tInt: case tCard: case tBool: case tChar: case tEnum: case tId: return true; case tStruct: case tVector: case tUnion: case tBuffer: return false; } assert (false); return false; } # ifdef EXPR_COMPILE /** Get the type this is derived from, or NULL */ const class Type* getFather () const { return myFather; } /** Cancel the compilation */ void uncompile (); /** Determine if the comparison code for the type has been generated */ bool isGenerated (); /** Reset the counter of compiled types */ static void uncompileAll (); /** Generate a C type declaration and auxiliary functions * @param out output stream for the declarations */ virtual void compile (class StringBuffer& out); /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ virtual void compileDefinition (class StringBuffer& out, unsigned indent) const = 0; /** Generate auxiliary definitions * @param out output stream for the declarations * @param indent indentation level * @param interface flag: generate interface declarations */ virtual void compileExtraDefinitions (class StringBuffer& out, unsigned indent, bool interface) const; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param left left-hand-side C expression to be compared * @param right right-hand-side C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @param backslash flag: prepend all newlines with backslashes * @return true if any code was generated */ virtual bool compileEqual (class StringBuffer& out, unsigned indent, const char* left, const char* right, bool equal, bool first, bool last, bool backslash) const; /** Generate three-way comparison statements * @param out output stream */ void compileCompare3 (class StringBuffer& out) const { compileCompare3 (out, 0, ""); } /** Generate three-way comparison statements * @param out output stream * @param condition additional condition for the comparison (NULL=none) * @param component component to be compared */ virtual void compileCompare3 (class StringBuffer& out, const char* condition, const char* component) const; /** Generate three-way comparison statements for leaf components * @param out output stream * @param condition additional condition for the comparison (NULL=none) * @param component component to be compared */ static void compileLeafCompare3 (class StringBuffer& out, const char* condition, const char* component); /** Generate statements for incrementing a value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose successor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ void compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Generate statements for decrementing a value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose predecessor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ void compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Generate statements for incrementing an unconstrained value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose successor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ virtual void do_compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Generate statements for decrementing an unconstrained value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose predecessor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ virtual void do_compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Emit an assignment to the first value of the compiled type * @param out output stream * @param indent indentation level (0=generate a compound expression) * @param value value to be assigned to */ void compileBottom (class StringBuffer& out, unsigned indent, const char* value) const; /** Emit an assignment to the last value of the compiled type * @param out output stream * @param indent indentation level (0=generate a compound expression) * @param value value to be assigned to */ void compileTop (class StringBuffer& out, unsigned indent, const char* value) const; /** Emit code for converting a value of this type to another * @param cexpr the compilation * @param indent indentation level * @param target target type * @param lvalue left-hand-side value of the assignment * @param rvalue C expression for the value to be converted */ virtual void compileCast (class CExpression& cexpr, unsigned indent, const class Type& target, const char* lvalue, const char* rvalue) const; /** Emit code for converting a value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ virtual void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const = 0; /** Emit code for converting a number to a value * @param out output stream * @param indent indentation level * @param number number to be converted * @param value value to be computed */ virtual void compileReverseConversion (class StringBuffer& out, unsigned indent, const char* number, const char* value) const; /** Emit code for encoding a value * @param cexpr the compilation * @param indent indentation level * @param func name of the encoding function * @param value value to be encoded */ virtual void compileEncoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const; /** Emit code for decoding a value * @param cexpr the compilation * @param indent indentation level * @param func name of the decoding function * @param value value to be decoded */ virtual void compileDecoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const; /** Emit the index of the compiled type * @param out output stream */ void appendIndex (class StringBuffer& out) const; /** Emit the name of the compiled type * @param out output stream */ void appendName (class StringBuffer& out) const; /** Emit the name of the compiled multi-set type * @param out output stream */ void appendMSetName (class StringBuffer& out) const; # endif // EXPR_COMPILE /** Display the type definition * @param printer the printer object */ virtual void display (const class Printer& printer) const; private: /** Number of possible values in the type */ mutable card_t myNumValues; /** Name of the type (may be NULL) */ char* myName; /** Flag: is the type ordered? */ const bool myIsOrdered; protected: /** Constraint associated with the type */ class Constraint* myConstraint; # ifdef EXPR_COMPILE /** Index number of the compiled type */ unsigned myIndex; /** Flag: have the comparison functions been generated? */ bool myGenerated; /** Original type */ const class Type* myFather; # endif // EXPR_COMPILE }; #endif // TYPE_H_ maria-1.3.5/Type/UnionType.C0000644000175000017500000004341007643253074015752 0ustar msmakelamsmakela// Union type class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "UnionType.h" #include "UnionValue.h" #include "ComponentList.h" #include "Constraint.h" #include "Printer.h" /** @file UnionType.C * Union data type */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class Value& UnionType::getFirstValue () const { if (myConstraint) return *myConstraint->getFirstValue ().copy (); return *new class UnionValue (*this, 0, (*this)[card_t (0)].getFirstValue ()); } class Value& UnionType::getLastValue () const { if (myConstraint) return *myConstraint->getLastValue ().copy (); return *new class UnionValue (*this, getSize () - 1, (*this)[card_t (getSize () - 1)].getLastValue ()); } bool UnionType::isAssignable (const class Type& type) const { if (&type == this) return true; if (type.getKind () != getKind ()) return myComponents.isAssignable (type); return myComponents.isAssignable (static_cast(type).myComponents); } bool UnionType::isAlwaysAssignable (const class Type& type) const { if (&type == this) return true; if (type.getKind () != getKind ()) return false; return myComponents.isAlwaysAssignable (static_cast(type).myComponents); } bool UnionType::isConstrained (const class Value& value) const { assert (value.getType ().isAssignable (*this)); const class UnionValue& v = static_cast(value); assert (v.getIndex () < getSize ()); return (*this)[v.getIndex ()].isConstrained (v.getValue ()); } card_t UnionType::do_getNumValues () const { card_t numValues = 0; assert (!myNumValues && myComponents.getSize ()); myNumValues = new card_t[myComponents.getSize ()]; for (card_t i = 0; i < myComponents.getSize (); i++) { card_t num = myComponents[i].getNumValues (); if (num != CARD_T_MAX && num < CARD_T_MAX - numValues) myNumValues[i] = numValues += num; else return CARD_T_MAX; } return numValues; } card_t UnionType::convert (const class Value& value) const { assert (value.getKind () == Value::vUnion); assert (isConstrained (value)); assert (getNumValues () < CARD_T_MAX); if (myConstraint) return Type::convert (value); const class UnionValue& v = static_cast(value); card_t i = v.getIndex (); card_t number = i ? myNumValues[i - 1] : 0; number += (*this)[i].convert (v.getValue ()); assert (number < getNumValues ()); return number; } class Value* UnionType::convert (card_t number) const { assert (number < getNumValues ()); assert (getNumValues () < CARD_T_MAX); if (myConstraint) return Type::convert (number); card_t i = 0; while (myNumValues[i] <= number) i++; class Value* v = (*this)[i].convert (number - (i ? myNumValues[i - 1] : 0)); return new class UnionValue (*this, i, *v); } class Value* UnionType::cast (class Value& value) const { for (card_t i = getSize (); i--; ) { if (value.getType ().isAssignable ((*this)[i])) { if ((*this)[i].isConstrained (value)) { value.setType ((*this)[i]); return new class UnionValue (*this, i, value); } else break; } } delete &value; return NULL; } #ifdef EXPR_COMPILE # include "CExpression.h" # include "util.h" # include void UnionType::compile (class StringBuffer& out) { for (card_t i = 0; i < myComponents.getSize (); i++) const_cast(myComponents[i]).compile (out); Type::compile (out); } void UnionType::compileDefinition (class StringBuffer& out, unsigned indent) const { char ixname[25]; out.indent (indent), out.append ("struct {\n"); out.indent (indent + 2), out.append ("unsigned t;\n"); out.indent (indent + 2), out.append ("union {\n"); for (card_t i = 0; i < myComponents.getSize (); i++) { out.indent (indent + 4), myComponents[i].appendName (out); snprintf (ixname, sizeof ixname, " u%u;\n", i); out.append (ixname); } out.indent (indent + 2), out.append ("} u;\n"); out.indent (indent), out.append ("}"); } bool UnionType::compileEqual (class StringBuffer& out, unsigned indent, const char* left, const char* right, bool equal, bool first, bool last, bool backslash) const { size_t llen = strlen (left), rlen = strlen (right); char* l = new char[llen + 25]; char* r = new char[rlen + 25]; memcpy (l, left, llen); memcpy (r, right, rlen); if (!first) out.indent (indent); out.append (left), out.append (".t"); out.append (equal ? "==" : "!="); out.append (right), out.append (".t"); out.append (backslash ? (equal ? "&&\\\n" : "||\\\n") : (equal ? "&&\n" : "||\n")); out.indent (indent++); out.append ("("); first = true; for (card_t i = myComponents.getSize (); i--; ) { if (first) first = false; else out.indent (indent); out.append ("("); out.append (left), out.append (".t"); out.append ("=="); out.append (i); out.append (backslash ? "&&\\\n" : "&&\n"); out.indent (indent + 1); out.append ("("); snprintf (l + llen, 23, ".u.u%u", i); snprintf (r + rlen, 23, ".u.u%u", i); if (!myComponents[i].compileEqual (out, indent + 2, l, r, equal, true, true, backslash)) out.append (equal ? "1" : "0"); out.append ("))"); if (i) out.append (backslash ? "||\\\n" : "||\n"); } delete[] l; delete[] r; out.append (")"), indent--; if (!last) out.append (backslash ? (equal ? "&&\\\n" : "||\\\n") : (equal ? "&&\n" : "||\n")); return true; } void UnionType::compileCompare3 (class StringBuffer& out, const char* condition, const char* component) const { const size_t len = strlen (component); char* const newcomp = new char[len + 25]; char* const offset = newcomp + len; memcpy (newcomp, component, len); const size_t condlen = condition ? strlen (condition) : 0; char* const newcond = new char[condlen ? len + condlen + 28 : len + 26]; char* const coffset = condlen ? newcond + condlen + len + 3 : newcond + len + 1; if (condlen) { memcpy (newcond, condition, condlen); memcpy (newcond + condlen, "&&l", 3); memcpy (newcond + condlen + 3, component, len); } else *newcond = 'l', memcpy (newcond + 1, component, len); memcpy (offset, ".t", 3); Type::compileLeafCompare3 (out, condition, newcomp); for (card_t i = 0; i < myComponents.getSize (); i++) { snprintf (coffset, 26, ".t==%u", i); snprintf (offset, 25, ".u.u%u", i); myComponents[i].compileCompare3 (out, newcond, newcomp); } delete[] newcond; delete[] newcomp; } void UnionType::do_compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { size_t llen = strlen (lvalue), rlen = strlen (rvalue); char* lval = new char[llen + 25]; char* rval = new char[rlen + 25]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); out.indent (indent); out.append ("do {\n"); if (!wrap) { wrap = "wrap"; out.indent (indent + 2); out.append ("bool_t "); out.append (wrap); out.append ("=0;\n"); } out.indent (indent += 2); out.append ("switch ("); if (lvalue != rvalue && strcmp (lvalue, rvalue)) out.append (lvalue), out.append (".t="); out.append (rvalue); out.append (".t) {\n"); for (card_t i = 0;; ) { snprintf (lval + llen, 25, ".u.u%u", i); snprintf (rval + rlen, 25, ".u.u%u", i); out.indent (indent); out.append ("case "); out.append (i); out.append (":\n"); { card_t j = i++; if (i == myComponents.getSize ()) i = 0; myComponents[j].compileSuccessor (out, indent + 2, lval, rval, wrap); } out.indent (indent + 2); out.append ("if (!"); out.append (wrap); out.append (") continue;\n"); out.indent (indent + 2); out.append (wrap); out.append ("=0;\n"); out.indent (indent + 2); out.append (lvalue); out.append (".t="); out.append (i); out.append (";\n"); snprintf (lval + llen, 25, ".u.u%u", i); myComponents[i].compileBottom (out, indent + 2, lval); if (i) { out.indent (indent + 2); out.append ("break;\n"); } else break; } out.indent (indent); out.append ("}\n"); out.indent (indent -= 2); out.append ("} while (0);\n"); delete[] lval; delete[] rval; } void UnionType::do_compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { size_t llen = strlen (lvalue), rlen = strlen (rvalue); char* lval = new char[llen + 25]; char* rval = new char[rlen + 25]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); out.indent (indent); out.append ("do {\n"); if (!wrap) { wrap = "wrap"; out.indent (indent + 2); out.append ("bool_t "); out.append (wrap); out.append ("=0;\n"); } out.indent (indent += 2); out.append ("switch ("); if (lvalue != rvalue && strcmp (lvalue, rvalue)) out.append (lvalue), out.append (".t="); out.append (rvalue); out.append (".t) {\n"); for (card_t i = 0;; ) { snprintf (lval + llen, 25, ".u.u%u", i); snprintf (rval + rlen, 25, ".u.u%u", i); out.indent (indent); out.append ("case "); out.append (i); out.append (":\n"); { card_t j = i++; if (i == myComponents.getSize ()) i = 0; myComponents[j].compilePredecessor (out, indent + 2, lval, rval, wrap); } out.indent (indent + 2); out.append ("if (!"); out.append (wrap); out.append (") continue;\n"); out.indent (indent + 2); out.append (wrap); out.append ("=0;\n"); out.indent (indent + 2); out.append (lvalue); out.append (".t="); out.append (i); out.append (";\n"); snprintf (lval + llen, 25, ".u.u%u", i); myComponents[i].compileTop (out, indent + 2, lval); if (i) { out.indent (indent + 2); out.append ("break;\n"); } else break; } out.indent (indent); out.append ("}\n"); out.indent (indent -= 2); out.append ("} while (0);\n"); delete[] lval; delete[] rval; } void UnionType::compileCast (class CExpression& cexpr, unsigned indent, const class Type& target, const char* lvalue, const char* rvalue) const { assert (isAssignable (target)); if (target.getKind () == Type::tUnion) static_cast(target).compileCastFrom (cexpr, indent, *this, lvalue, rvalue); else { class StringBuffer& out = cexpr.getOut (); class StringBuffer cond; card_t first = CARD_T_MAX; for (card_t i = getSize (); i--; ) { if (myComponents[i].isAssignable (target)) { if (first == CARD_T_MAX) first = i; else cond.append ("&&"); cond.append (rvalue); cond.append (".t!="); cond.append (i); } } assert (first != CARD_T_MAX); out.indent (indent); out.append ("if ("); out.append (cond); out.append (")\n"); cexpr.compileError (indent + 2, errUnion); size_t len = strlen (rvalue); char* rval = new char[len + 25]; memcpy (rval, rvalue, len); snprintf (rval + len, 25, ".u.u%u", first); myComponents[first].compileCast (cexpr, indent, target, lvalue, rval); delete[] rval; if (const class Constraint* c = target.getConstraint ()) c->compileCheck (cexpr, indent, lvalue); } } void UnionType::compileCastFrom (class CExpression& cexpr, unsigned indent, const class Type& source, const char* lvalue, const char* rvalue) const { class StringBuffer& out = cexpr.getOut (); if (this == &source) { out.indent (indent); out.append (lvalue); out.append ("="); out.append (rvalue); out.append (";\n"); return; } for (card_t i = getSize (); i--; ) { if (source.isAssignable ((*this)[i])) { out.indent (indent); out.append (lvalue); out.append (".t="); out.append (i); out.append (";\n"); size_t len = strlen (lvalue); char* lval = new char[len + 25]; memcpy (lval, lvalue, len); snprintf (lval + len, 25, ".u.u%u", i); source.compileCast (cexpr, indent, (*this)[i], lval, rvalue); delete[] lval; if (const class Constraint* c = getConstraint ()) c->compileCheck (cexpr, indent, lvalue); return; } } assert (false); } void UnionType::do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { assert (getNumValues () < CARD_T_MAX && getSize ()); out.indent (indent); out.append ("switch ("), out.append (value), out.append (".t) {\n"); size_t length = strlen (value); char* val = new char[length + 25]; char* offset = val + length; memcpy (val, value, length); for (card_t i = 0; i < getSize (); i++) { out.indent (indent); if (i) { out.append ("case "), out.append (i), out.append (":\n"); out.indent (indent + 2), out.append (number); out.append (add ? "+=" : "="), out.append (myNumValues[i - 1]); out.append (";\n"); } else out.append ("default:\n"); snprintf (offset, 25, ".u.u%u", i); (*this)[i].compileConversion (out, indent + 2, val, number, i || add); out.indent (indent + 2); out.append ("break;\n"); } delete[] val; out.indent (indent); out.append ("}\n"); } void UnionType::compileReverseConversion (class StringBuffer& out, unsigned indent, const char* number, const char* value) const { if (myConstraint) Type::compileReverseConversion (out, indent, number, value); else { size_t length = strlen (value); char* val = new char[length + 25]; char* offset = val + length; memcpy (val, value, length); bool next = false; for (card_t i = getSize (); i--; next = true) { out.indent (indent); if (next) out.append ("else "); card_t num = i ? myNumValues[i - 1] : 0; if (num) { out.append ("if ("), out.append (number); out.append (">="); out.append (num), out.append (") "); } out.append ("{\n"); out.indent (indent + 2); if (num) { out.append (number); out.append ("-="); out.append (num); out.append (", "); } out.append (value), out.append (".t="); snprintf (offset, 25, ".u.u%u", i); out.append (offset + 4), out.append (";\n"); (*this)[i].compileReverseConversion (out, indent + 2, number, val); out.indent (indent); out.append ("}\n"); } delete[] val; } } void UnionType::compileEncoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const { if (getNumValues () < CARD_T_MAX) Type::compileEncoder (cexpr, indent, func, value); else { size_t length = strlen (value); char* val = new char[length + 25]; char* offset = val + length; memcpy (val, value, length); class StringBuffer& out = cexpr.getOut (); if (getSize () > 1) { out.indent (indent); out.append (func); out.append (" ("); out.append (value), out.append (".t, "); out.append (log2 (getSize ())); out.append (");\n"); } out.indent (indent); out.append ("switch ("), out.append (value), out.append (".t) {\n"); for (card_t i = getSize (); i--; ) { out.indent (indent); out.append ("case "), out.append (i), out.append (":\n"); snprintf (offset, 25, ".u.u%u", i); (*this)[i].compileEncoder (cexpr, indent + 2, func, val); out.indent (indent + 2); out.append ("break;\n"); } out.indent (indent); out.append ("}\n"); delete[] val; } } void UnionType::compileDecoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const { if (getNumValues () < CARD_T_MAX) Type::compileDecoder (cexpr, indent, func, value); else { size_t length = strlen (value); char* val = new char[length + 25]; char* offset = val + length; memcpy (val, value, length); class StringBuffer& out = cexpr.getOut (); if (getSize () > 1) { out.indent (indent); out.append (value); out.append (".t = "); out.append (func); out.append (" ("); out.append (log2 (getSize ())); out.append (");\n"); } else { out.indent (indent); out.append (value); out.append (".t = 0;\n"); } out.indent (indent); out.append ("switch ("), out.append (value), out.append (".t) {\n"); for (card_t i = getSize (); i--; ) { out.indent (indent); out.append ("case "), out.append (i), out.append (":\n"); snprintf (offset, 25, ".u.u%u", i); (*this)[i].compileDecoder (cexpr, indent + 2, func, val); out.indent (indent + 2); out.append ("break;\n"); } out.indent (indent); out.append ("}\n"); } } #endif // EXPR_COMPILE void UnionType::display (const class Printer& printer) const { printer.printRaw ("union "); printer.delimiter ('{')++; myComponents.display (printer); --printer.delimiter ('}'); if (myConstraint) myConstraint->display (printer); } maria-1.3.5/Type/UnionType.h0000644000175000017500000002447007767301450016023 0ustar msmakelamsmakela// Union type class -*- c++ -*- #ifndef UNIONTYPE_H_ # define UNIONTYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "ComponentList.h" /** @file UnionType.h * Union data type */ /* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Union type */ class UnionType : public Type { public: /** Constructor * @param components Components of the union */ UnionType (class ComponentList& components) : Type (components.isOrdered ()), myComponents (components), myNumValues (0) { delete &components; } /** Copy constructor */ UnionType (const class UnionType& old) : Type (old), myComponents (old.myComponents), myNumValues (0) {} private: /** Assignment operator */ class UnionType& operator= (const class UnionType& old); public: /** Destructor */ ~UnionType () { delete[] myNumValues; } /** Copy the Type */ class Type* copy () const { return new class UnionType (*this); } /** Determine the kind of the type */ enum Kind getKind () const { return tUnion; } /** Get the first value of this type */ class Value& getFirstValue () const; /** Get the last value of this type */ class Value& getLastValue () const; /** Determine the number of components in the type */ card_t getSize () const { return myComponents.getSize (); } /** Get a component by name * @param name name of the component * @return pointer to the component, or NULL if not found */ const class Type* operator[] (const char* name) const { return myComponents[name]; } /** Get a component by index number * @param i index to the component * @return reference to the component */ const class Type& operator[] (card_t i) const { return myComponents[i]; } /** Get the index number of a component * @param name name of the component * @return index of the component */ card_t getIndex (const char* name) const { return myComponents.getIndex (name); } /** Get the name of a component * @param i index of the component * @return name of the component */ const char* getComponentName (card_t i) const { return myComponents.getName (i); } /** Determine the cumulated number of values for a component * @param i index of the component * @return number of values of all components up to index */ card_t getCumulatedValues (card_t i) const { assert (i < myComponents.getSize ()); if (!myNumValues) do_getNumValues (); return i ? myNumValues[i - 1] : 0; } /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ class Value* convert (card_t number) const; /** See if the type is assignable to another type * @param type the type this type should be assignable to * @return true if this type is assignable to the type */ bool isAssignable (const class Type& type) const; /** See if the type is always assignable to another type * @param type the type this type should always be assignable to * @return true if this type always is assignable to the type */ bool isAlwaysAssignable (const class Type& type) const; /** See if the component list is assignable from a type * @param type the type this list should be assignable from * @return true if this list is assignable from the type */ bool isAssignableFrom (const class Type& type) const { return myComponents.isAssignableFrom (type); } /** See if the component list is always assignable from a type * @param type the type the list should always be assignable from * @return true if this list always is assignable from the type */ bool isAlwaysAssignableFrom (const class Type& type) const { return myComponents.isAlwaysAssignableFrom (type); } /** Determine whether a value is compatible with the constraints of this type * @param value value to check * @return true if the value passes the constraint check */ bool isConstrained (const class Value& value) const; /** Get the number of possible values for this type */ card_t do_getNumValues () const; /** Convert a value to this type, if possible * @param value value to be converted * @return the converted value, or NULL */ class Value* cast (class Value& value) const; # ifdef EXPR_COMPILE /** Generate a C type declaration and auxiliary functions * @param out output stream for the declarations */ void compile (class StringBuffer& out); /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ void compileDefinition (class StringBuffer& out, unsigned indent) const; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param left left-hand-side C expression to be compared * @param right right-hand-side C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @param backslash flag: prepend all newlines with backslashes * @return true if any code was generated */ bool compileEqual (class StringBuffer& out, unsigned indent, const char* left, const char* right, bool equal, bool first, bool last, bool backslash) const; /** Generate three-way comparison statements * @param out output stream * @param condition additional condition for the comparison (NULL=none) * @param component component to be compared */ void compileCompare3 (class StringBuffer& out, const char* condition, const char* component) const; /** Generate statements for incrementing an unconstrained value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose successor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ void do_compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Generate statements for decrementing an unconstrained value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose predecessor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ void do_compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Emit code for converting a value of this type to another * @param cexpr the compilation * @param indent indentation level * @param target target type * @param lvalue left-hand-side value of the assignment * @param rvalue C expression for the value to be converted */ void compileCast (class CExpression& cexpr, unsigned indent, const class Type& target, const char* lvalue, const char* rvalue) const; /** Emit code for converting a value of another type to this * @param cexpr the compilation * @param indent indentation level * @param source source type * @param lvalue left-hand-side value of the assignment * @param rvalue C expression for the value to be converted */ void compileCastFrom (class CExpression& cexpr, unsigned indent, const class Type& source, const char* lvalue, const char* rvalue) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; /** Emit code for converting a number to a value * @param out output stream * @param indent indentation level * @param number number to be converted * @param value value to be computed */ void compileReverseConversion (class StringBuffer& out, unsigned indent, const char* number, const char* value) const; /** Emit code for encoding a value * @param cexpr the compilation * @param indent indentation level * @param func name of the encoding function * @param value value to be encoded */ void compileEncoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const; /** Emit code for decoding a value * @param cexpr the compilation * @param indent indentation level * @param func name of the decoding function * @param value value to be decoded */ void compileDecoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const; # endif // EXPR_COMPILE /** Display the type definition * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The union components */ class ComponentList myComponents; /** Cumulated numbers of possible values of the components */ mutable card_t* myNumValues; }; #endif // UNIONTYPE_H_ maria-1.3.5/Type/VectorType.C0000644000175000017500000003652007643253074016130 0ustar msmakelamsmakela// Vector type class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "VectorType.h" #include "VectorValue.h" #include "Constraint.h" #include "Printer.h" #include /** @file VectorType.C * Array data type */ /* Copyright © 1998-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ class Value& VectorType::getFirstValue () const { if (myConstraint) return *myConstraint->getFirstValue ().copy (); class Value* comp = &myItemType->getFirstValue (); class VectorValue* v = new class VectorValue (*this); for (card_t i = getSize (); --i; (*v)[i] = comp->copy ()); (*v)[0] = comp; return *v; } class Value& VectorType::getLastValue () const { if (myConstraint) return *myConstraint->getLastValue ().copy (); class Value* comp = &myItemType->getLastValue (); class VectorValue* v = new class VectorValue (*this); for (card_t i = getSize (); --i; (*v)[i] = comp->copy ()); (*v)[0] = comp; return *v; } bool VectorType::isAssignable (const class Type& type) const { if (&type == this) return true; if (type.getKind () != getKind ()) return Type::isAssignable (type); const class VectorType& v = static_cast(type); return myIndexType->isAlwaysAssignable (*v.myIndexType) && myItemType->isAssignable (*v.myItemType); } bool VectorType::isAlwaysAssignable (const class Type& type) const { if (&type == this) return true; if (type.getKind () != getKind ()) return false; const class VectorType& v = static_cast(type); return myIndexType->isAlwaysAssignable (*v.myIndexType) && myItemType->isAlwaysAssignable (*v.myItemType); } bool VectorType::isConstrained (const class Value& value) const { assert (value.getType ().isAssignable (*this)); const class VectorValue& v = static_cast(value); assert (v.getSize () == getSize ()); for (card_t i = getSize (); i--; ) if (!myItemType->isConstrained (v[i])) return false; return Type::isConstrained (value); } card_t VectorType::do_getNumValues () const { assert (!myConstraint); card_t numValues; card_t numItemValues = myItemType->getNumValues (); numValues = 1; if (numItemValues == CARD_T_MAX) return CARD_T_MAX; else if (numItemValues == 1) return 1; for (card_t i = 0, size = getSize (); i < size; i++) { if (numItemValues < CARD_T_MAX / numValues) numValues *= numItemValues; else return CARD_T_MAX; } return numValues; } card_t VectorType::convert (const class Value& value) const { assert (value.getKind () == Value::vVector); assert (isConstrained (value)); assert (getNumValues () < CARD_T_MAX); if (myConstraint) return Type::convert (value); card_t number = 0; const class VectorValue& v = static_cast(value); card_t i = getSize (), numItemValues = myItemType->getNumValues (); while (i--) (number *= numItemValues) += myItemType->convert (v[i]); assert (number < getNumValues ()); return number; } class Value* VectorType::convert (card_t number) const { assert (number < getNumValues ()); assert (getNumValues () < CARD_T_MAX); if (myConstraint) return Type::convert (number); class VectorValue* value = new class VectorValue (*this); const card_t numItemValues = myItemType->getNumValues (); const card_t size = getSize (); for (card_t i = 0; i < size; i++) { card_t num = number % numItemValues; number /= numItemValues; (*value)[i] = myItemType->convert (num); } assert (isConstrained (*value)); return value; } #ifdef EXPR_COMPILE # include "CExpression.h" # include void VectorType::compile (class StringBuffer& out) { const_cast(myIndexType)->compile (out); const_cast(myItemType)->compile (out); Type::compile (out); } void VectorType::compileDefinition (class StringBuffer& out, unsigned indent) const { char ixname[25]; out.indent (indent), out.append ("struct {\n"); out.indent (indent + 2), myItemType->appendName (out); snprintf (ixname, sizeof ixname, " a[%u]", getSize ()); out.append (ixname); out.append (";\n"); out.indent (indent), out.append ("}"); } bool VectorType::compileEqual (class StringBuffer& out, unsigned indent, const char* left, const char* right, bool equal, bool first, bool last, bool backslash) const { if (getNumValues () == 1) return false; size_t llen = strlen (left), rlen = strlen (right); char* l = new char[llen + 25]; char* r = new char[rlen + 25]; memcpy (l, left, llen); memcpy (r, right, rlen); bool gen = false; for (card_t i = getSize (); i--; ) { snprintf (l + llen, 25, ".a[%u]", i); snprintf (r + rlen, 25, ".a[%u]", i); gen = myItemType->compileEqual (out, indent, l, r, equal, first, !i, backslash); if (gen) first = false; } delete[] l; delete[] r; if (gen && !last) out.append (backslash ? (equal ? "&&\\\n" : "||\\\n") : (equal ? "&&\n" : "||\n")); return gen || !last; } void VectorType::compileCompare3 (class StringBuffer& out, const char* condition, const char* component) const { const size_t len = strlen (component); char* const newcomp = new char[len + 25]; char* const offset = newcomp + len; memcpy (newcomp, component, len); for (card_t i = myIndexType->getNumValues (); i--; ) { snprintf (offset, 25, ".a[%u]", i); myItemType->compileCompare3 (out, condition, newcomp); } delete[] newcomp; } void VectorType::do_compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { size_t llen = strlen (lvalue), rlen = strlen (rvalue); char* lval = new char[llen + 25]; char* rval = new char[rlen + 25]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); out.indent (indent); out.append ("do {\n"); if (!wrap) { wrap = "wrap"; out.indent (indent + 2); out.append ("bool_t "); out.append (wrap); out.append ("=0;\n"); } for (card_t i = 0;; ) { snprintf (lval + llen, 25, ".a[%u]", i); snprintf (rval + rlen, 25, ".a[%u]", i); myItemType->compileSuccessor (out, indent + 2, lval, rval, wrap); if (++i < getSize ()) { out.indent (indent + 2); out.append ("if (!"); out.append (wrap); out.append (") {\n"); if (lvalue != rvalue && strcmp (lvalue, rvalue)) { for (card_t j = i; j < getSize (); j++) { out.indent (indent + 4); out.append (lvalue); out.append (".a["); out.append (j); out.append ("]="); out.append (rvalue); out.append (".a["); out.append (j); out.append ("];\n"); } } out.indent (indent + 4); out.append ("continue;\n"); out.indent (indent + 2); out.append ("}\n"); out.indent (indent + 2); out.append (wrap); out.append ("=0;\n"); } else break; } out.indent (indent); out.append ("} while (0);\n"); delete[] lval; delete[] rval; } void VectorType::do_compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const { size_t llen = strlen (lvalue), rlen = strlen (rvalue); char* lval = new char[llen + 25]; char* rval = new char[rlen + 25]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); out.indent (indent); out.append ("do {\n"); if (!wrap) { wrap = "wrap"; out.indent (indent + 2); out.append ("bool_t "); out.append (wrap); out.append ("=0;\n"); } for (card_t i = 0;; ) { snprintf (lval + llen, 25, ".a[%u]", i); snprintf (rval + rlen, 25, ".a[%u]", i); myItemType->compilePredecessor (out, indent + 2, lval, rval, wrap); if (++i < getSize ()) { out.indent (indent + 2); out.append ("if (!"); out.append (wrap); out.append (") {\n"); if (lvalue != rvalue && strcmp (lvalue, rvalue)) { for (card_t j = i; j < getSize (); j++) { out.indent (indent + 4); out.append (lvalue); out.append (".a["); out.append (j); out.append ("]="); out.append (rvalue); out.append (".a["); out.append (j); out.append ("];\n"); } } out.indent (indent + 4); out.append ("continue;\n"); out.indent (indent + 2); out.append ("}\n"); out.indent (indent + 2); out.append (wrap); out.append ("=0;\n"); } else break; } out.indent (indent); out.append ("} while (0);\n"); delete[] lval; delete[] rval; } void VectorType::compileCast (class CExpression& cexpr, unsigned indent, const class Type& target, const char* lvalue, const char* rvalue) const { assert (isAssignable (target)); if (target.getKind () != Type::tVector) Type::compileCast (cexpr, indent, target, lvalue, rvalue); else { const class VectorType& vt = static_cast(target); assert (getSize () == vt.getSize ()); size_t llen = strlen (lvalue); size_t rlen = strlen (rvalue); char* lval = new char[llen + 25]; char* rval = new char[llen + 25]; memcpy (lval, lvalue, llen); memcpy (rval, rvalue, rlen); for (card_t i = getSize (); i--; ) { snprintf (lval + llen, 25, ".a[%u]", i); snprintf (rval + rlen, 25, ".a[%u]", i); myItemType->compileCast (cexpr, indent, *vt.myItemType, lval, rval); } delete[] lval; delete[] rval; if (const class Constraint* c = target.getConstraint ()) c->compileCheck (cexpr, indent, lvalue); } } void VectorType::do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const { card_t i = getSize (); assert (getNumValues () < CARD_T_MAX && i); size_t length = strlen (value); char* val = new char[length + 25]; char* offset = val + length; memcpy (val, value, length); if (--i) { const char* num = number; if (add) { out.indent (indent), out.append ("{\n"); out.indent (indent += 2), out.append ("card_t "); length = strlen (number); char* nbr = new char[length + 2]; memcpy (nbr, number, length); memcpy (nbr + length, "_", 2); num = nbr; out.append (num), out.append (";\n"); } const card_t numValues = myItemType->getNumValues (); for (bool next = false; i; next = true) { snprintf (offset, 25, ".a[%u]", i--); myItemType->compileConversion (out, indent, val, num, next); out.indent (indent), out.append (num), out.append ("*="); out.append (numValues), out.append (";\n"); } memcpy (offset, ".a[0]", 6); myItemType->compileConversion (out, indent, val, num, true); if (add) { out.indent (indent), out.append (number), out.append ("+="); out.append (num), out.append (";\n"); out.indent (indent -= 2), out.append ("}\n"); delete[] num; } } else { memcpy (offset, ".a[0]", 6); myItemType->compileConversion (out, indent, val, number, add); } delete[] val; } void VectorType::compileReverseConversion (class StringBuffer& out, unsigned indent, const char* number, const char* value) const { if (myConstraint) Type::compileReverseConversion (out, indent, number, value); else if (getNumValues () == 1) compileBottom (out, indent, value); else { size_t length = strlen (value); char* val = new char[length + 25]; char* offset = val + length; memcpy (val, value, length); if (getSize () > 1) { length = strlen (number); char* num = new char[length + 2]; memcpy (num, number, length); memcpy (num + length, "_", 2); out.indent (indent), out.append ("{\n"); out.indent (indent + 2); out.append ("card_t "), out.append (num), out.append (";\n"); card_t numValues = myItemType->getNumValues (); for (card_t i = 0; i < getSize (); i++) { snprintf (offset, 25, ".a[%u]", i); out.indent (indent + 2); out.append (num), out.append ("="), out.append (number); out.append ("%"), out.append (numValues); out.append (", "); out.append (number), out.append ("/="); out.append (numValues); out.append (";\n"); myItemType->compileReverseConversion (out, indent + 2, num, val); } out.indent (indent), out.append ("}\n"); delete[] num; } else { memcpy (offset, ".a[0]", 6); myItemType->compileReverseConversion (out, indent, number, val); } delete[] val; } } void VectorType::compileEncoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const { if (getNumValues () < CARD_T_MAX) Type::compileEncoder (cexpr, indent, func, value); else { size_t length = strlen (value); char* val = new char[length + 6]; memcpy (val, value, length); memcpy (val + length, ".a[i]", 6); class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append ("{\n"); out.indent (indent + 2); out.append ("card_t i;\n"); out.indent (indent + 2); out.append ("for (i=0; i<"); out.append (getSize ()); out.append ("; i++) {\n"); myItemType->compileEncoder (cexpr, indent + 4, func, val); out.indent (indent + 2); out.append ("}\n"); out.indent (indent); out.append ("}\n"); delete[] val; } } void VectorType::compileDecoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const { if (getNumValues () < CARD_T_MAX) Type::compileDecoder (cexpr, indent, func, value); else { size_t length = strlen (value); char* val = new char[length + 6]; memcpy (val, value, length); memcpy (val + length, ".a[i]", 6); class StringBuffer& out = cexpr.getOut (); out.indent (indent); out.append ("{\n"); out.indent (indent + 2); out.append ("card_t i;\n"); out.indent (indent + 2); out.append ("for (i=0; i<"); out.append (getSize ()); out.append ("; i++) {\n"); myItemType->compileDecoder (cexpr, indent + 4, func, val); out.indent (indent + 2); out.append ("}\n"); out.indent (indent); out.append ("}\n"); delete[] val; } } #endif // EXPR_COMPILE void VectorType::display (const class Printer& printer) const { if (const char* item = myItemType->getName ()) printer.print (item); else myItemType->display (printer); printer.delimiter ('[')++; if (const char* i = myIndexType->getName ()) printer.print (i); else myIndexType->display (printer); --printer.delimiter (']'); if (myConstraint) myConstraint->display (printer); } maria-1.3.5/Type/VectorType.h0000644000175000017500000002075607767301450016200 0ustar msmakelamsmakela// Vector type class -*- c++ -*- #ifndef VECTORTYPE_H_ # define VECTORTYPE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Type.h" /** @file VectorType.h * Array data type */ /* Copyright © 1998-2001,2003 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Vector (array) type */ class VectorType : public Type { public: /** Constructor * @param itemType The vector item type * @param indexType The vector index type */ VectorType (const class Type& itemType, const class Type& indexType) : Type (itemType.isOrdered ()), myItemType (&itemType), myIndexType (&indexType) { assert (myItemType && myIndexType); assert (myIndexType->isOrdered ()); #ifndef NDEBUG card_t size = myIndexType->getNumValues (); assert (size > 0 && size < CARD_T_MAX); #endif // NDEBUG } /** Copy constructor */ VectorType (const class VectorType& old) : Type (old), myItemType (old.myItemType), myIndexType (old.myIndexType) { assert (myItemType && myIndexType); assert (myIndexType->isOrdered ()); #ifndef NDEBUG card_t size = myIndexType->getNumValues (); assert (size > 0 && size < CARD_T_MAX); #endif // NDEBUG } private: /** Assignment operator */ class VectorType& operator= (const class VectorType& old); public: /** Destructor */ ~VectorType () {} /** Copy the Type */ class Type* copy () const { return new class VectorType (*this); } /** Determine the kind of the type */ enum Kind getKind () const { return tVector; } /** Get the item type */ const class Type& getItemType () const { return *myItemType; } /** Get the index type */ const class Type& getIndexType () const { return *myIndexType; } /** Determine the vector size */ card_t getSize () const { return myIndexType->getNumValues (); } /** Get the first value of this type */ class Value& getFirstValue () const; /** Get the last value of this type */ class Value& getLastValue () const; /** Convert a value of this type to a number * @param value value to be converted * @return number between 0 and getNumValues () - 1 */ card_t convert (const class Value& value) const; /** Convert a number to a value of this type * @param number number between 0 and getNumValues () - 1 * @return the corresponding value */ class Value* convert (card_t number) const; /** See if the type is assignable to another type * @param type the type this type should be assignable to * @return true if this type is assignable to the type */ bool isAssignable (const class Type& type) const; /** See if the type is always assignable to another type * @param type the type this type should always be assignable to * @return true if this type always is assignable to the type */ bool isAlwaysAssignable (const class Type& type) const; /** Determine whether a value is compatible with the constraints of this type * @param value value to check * @return true if the value passes the constraint check */ bool isConstrained (const class Value& value) const; /** Get the number of possible values for this type */ card_t do_getNumValues () const; # ifdef EXPR_COMPILE /** Generate a C type declaration and auxiliary functions * @param out output stream for the declarations */ void compile (class StringBuffer& out); /** Generate a C type declaration * @param out output stream for the declarations * @param indent indentation level */ void compileDefinition (class StringBuffer& out, unsigned indent) const; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param left left-hand-side C expression to be compared * @param right right-hand-side C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @param backslash flag: prepend all newlines with backslashes * @return true if any code was generated */ bool compileEqual (class StringBuffer& out, unsigned indent, const char* left, const char* right, bool equal, bool first, bool last, bool backslash) const; /** Generate three-way comparison statements * @param out output stream * @param condition additional condition for the comparison (NULL=none) * @param component component to be compared */ void compileCompare3 (class StringBuffer& out, const char* condition, const char* component) const; /** Generate statements for incrementing an unconstrained value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose successor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ void do_compileSuccessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Generate statements for decrementing an unconstrained value * @param out output stream * @param indent indentation level * @param lvalue variable to receive the result * @param rvalue variable whose predecessor is to be computed * @param wrap overflow flag variable (NULL=omit overwrap code) */ void do_compilePredecessor (class StringBuffer& out, unsigned indent, const char* lvalue, const char* rvalue, const char* wrap) const; /** Emit code for converting a value of this type to another * @param cexpr the compilation * @param indent indentation level * @param target target type * @param lvalue left-hand-side value of the assignment * @param rvalue C expression for the value to be converted */ void compileCast (class CExpression& cexpr, unsigned indent, const class Type& target, const char* lvalue, const char* rvalue) const; /** Emit code for converting an unconstrained value to a number * @param out output stream * @param indent indentation level * @param value value to be converted * @param number number to be computed * @param add flag: add to number instead of assigning */ void do_compileConversion (class StringBuffer& out, unsigned indent, const char* value, const char* number, bool add) const; /** Emit code for converting a number to a value * @param out output stream * @param indent indentation level * @param number number to be converted * @param value value to be computed */ void compileReverseConversion (class StringBuffer& out, unsigned indent, const char* number, const char* value) const; /** Emit code for encoding a value * @param cexpr the compilation * @param indent indentation level * @param func name of the encoding function * @param value value to be encoded */ void compileEncoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const; /** Emit code for decoding a value * @param cexpr the compilation * @param indent indentation level * @param func name of the decoding function * @param value value to be decoded */ void compileDecoder (class CExpression& cexpr, unsigned indent, const char* func, const char* value) const; # endif // EXPR_COMPILE /** Display the type definition * @param printer the printer object */ void display (const class Printer& printer) const; private: /** The item type */ const class Type* myItemType; /** The index type */ const class Type* myIndexType; }; #endif // VECTORTYPE_H_ maria-1.3.5/Type/allTypes.h0000644000175000017500000000230407643253074015657 0ustar msmakelamsmakela/** @file allTypes.h * Header file that includes all classes derived from Type */ /* Copyright © 1998-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include "IntType.h" #include "CardType.h" #include "BoolType.h" #include "CharType.h" #include "EnumType.h" #include "IdType.h" #include "StructType.h" #include "UnionType.h" #include "VectorType.h" #include "BufferType.h" maria-1.3.5/Type/typedefs.h0000644000175000017500000000354307643253074015713 0ustar msmakelamsmakela/* Type definitions used in the Maria expression evaluator -*- c++ -*- */ #ifndef TYPEDEFS_H_ # define TYPEDEFS_H_ # include # include /** @file typedefs.h * Type definitions used in the expression evaluator */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Signed integer type */ typedef signed int int_t; /** Minimum value of int_t */ # define INT_T_MIN INT_MIN /** Maximum value of int_t */ # define INT_T_MAX INT_MAX /** Number of bits needed for representing int_t */ # define INT_T_BIT (CHAR_BIT * sizeof (int_t)) /** Unsigned integer (cardinality) type */ typedef unsigned int card_t; /** Maximum value of card_t */ # define CARD_T_MAX UINT_MAX /** Number of bits needed for representing card_t */ # define CARD_T_BIT (CHAR_BIT * sizeof (card_t)) /** Character type */ typedef unsigned char char_t; /** Maximum value of char_t */ # define CHAR_T_MAX UCHAR_MAX /** Number of bits needed for representing char_t */ # define CHAR_T_BIT (CHAR_BIT * sizeof (char_t)) #endif // TYPEDEFS_H_ maria-1.3.5/Value/0000755000175000017500000000000010272511405014030 5ustar msmakelamsmakelamaria-1.3.5/Value/BufferValue.C0000644000175000017500000002567007643253065016371 0ustar msmakelamsmakela// Buffer value class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BufferValue.h" #include "BufferType.h" #include "Constraint.h" /** @file BufferValue.C * The contents of a queue or stack */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ BufferValue::BufferValue (const class Type& type) : Value (type), myComponents (static_cast(type).getSize ()) { assert (getType ().getKind () == Type::tBuffer); } BufferValue::BufferValue (const class BufferValue& old) : Value (old.getType ()), myComponents (old.myComponents) { assert (getType ().getKind () == Type::tBuffer); } BufferValue::~BufferValue () { } bool BufferValue::operator< (const class BufferValue& other) const { assert (other.myComponents.getSize () == myComponents.getSize ()); card_t size = getCapacity (), osize = other.getCapacity (); if (size < osize) return true; else if (osize < size) return false; while (size--) if (*myComponents[size] < *other.myComponents[size]) return true; else if (*other.myComponents[size] < *myComponents[size]) return false; return false; } bool BufferValue::operator== (const class BufferValue& other) const { assert (other.myComponents.getSize () == myComponents.getSize ()); for (card_t i = 0; i < myComponents.getSize (); i++) { if (!myComponents[i]) return !other.myComponents[i]; if (!other.myComponents[i] || !(*myComponents[i] == *other.myComponents[i])) return false; } return true; } card_t BufferValue::operator- (const class BufferValue& other) const { if (!getSize ()) return 0; const class Type& itemType = static_cast(getType ()).getItemType (); card_t numItemValues = itemType.getNumValues (); card_t offset = 0, i = 0; for (card_t mult = 1; i < getSize () && myComponents[i]; mult *= numItemValues, i++) if (!other.myComponents[i]) offset += mult; assert (i == getSize () || !other.myComponents[i]); card_t diff = 0; while (i--) { diff *= numItemValues; if (!other.myComponents[i]) diff += itemType.convert (*myComponents[i]); else if (*other.myComponents[i] < *myComponents[i]) diff += *myComponents[i] - *other.myComponents[i]; else diff -= *other.myComponents[i] - *myComponents[i]; } return diff + offset; } void BufferValue::bottom () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value& v = c->getFirstValue (); assert (&v.getType () == &getType () && v.getKind () == getKind ()); const class BufferValue& bv = static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = bv[i] ? bv[i]->copy () : NULL; } return; } for (card_t i = 0; i < getSize (); i++) delete myComponents[i], myComponents[i] = NULL; } void BufferValue::top () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value& v = c->getLastValue (); assert (&v.getType () == &getType () && v.getKind () == getKind ()); const class BufferValue& bv = static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = bv[i] ? bv[i]->copy () : NULL; } return; } for (card_t i = 0; i < getSize (); i++) delete myComponents[i], myComponents[i] = &static_cast(getType ()).getItemType () .getLastValue (); } bool BufferValue::increment () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value* v = &c->getNextHigh (*this); assert (&v->getType () == &getType () && v->getKind () == getKind ()); if (*this == *static_cast(v)) { if (!(v = c->getNextLow (*this))) { bottom (); return false; } assert (&v->getType () == &getType () && v->getKind () == getKind ()); const class BufferValue& bv = *static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = bv[i] ? bv[i]->copy () : NULL; } return true; } } for (card_t i = 0; i < getSize (); i++) { if (!myComponents[i]) { myComponents[i] = &static_cast(getType ()).getItemType () .getFirstValue (); return true; } if (myComponents[i]->increment ()) return true; } bottom (); return false; } bool BufferValue::decrement () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value* v = &c->getPrevLow (*this); assert (&v->getType () == &getType () && v->getKind () == getKind ()); if (*this == *static_cast(v)) { if (!(v = c->getPrevHigh (*this))) { top (); return false; } assert (&v->getType () == &getType () && v->getKind () == getKind ()); const class BufferValue& bv = *static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = bv[i] ? bv[i]->copy () : NULL; } return true; } } card_t i; for (i = 0; i < getSize (); i++) if (!myComponents[i]) break; else if (myComponents[i]->decrement ()) return true; if (i--) { delete myComponents[i]; myComponents[i] = NULL; return true; } else { top (); return false; } } class Value* BufferValue::cast (const class Type& type) { assert (getType ().isAssignable (type)); if (&type == &getType () || type.getKind () != Type::tBuffer) return Value::cast (type); const class BufferType& bt = static_cast(type); const class Type& itemType = bt.getItemType (); card_t i; for (i = 0; i < getSize () && (*this)[i]; i++); if (i > bt.getSize ()) { delete this; return NULL; } class BufferValue* value = new class BufferValue (type); for (i = 0; i < getSize () && (*this)[i]; i++) (*value)[i] = (*this)[i], (*this)[i] = NULL; delete this; while (i--) { if (!((*value)[i] = (*value)[i]->cast (itemType))) { delete value; return NULL; } } return value->cast (type); } #include "Printer.h" void BufferValue::display (const class Printer& printer) const { printer.delimiter ('{')++; for (card_t i = 0; myComponents[i]; ) { myComponents[i]->display (printer); if (++i == getSize () || !myComponents[i]) break; else printer.delimiter (','); } printer--.delimiter ('}'); } #ifdef EXPR_COMPILE # include "StringBuffer.h" # include /** maximum length of a 64-bit index value, plus delimiters */ static const size_t ixlength = 25; void BufferValue::compile (class StringBuffer&) const { assert (false); } void BufferValue::compileInit (const char* name, unsigned indent, class StringBuffer& out) const { /** length of the supplied name string */ size_t length = strlen (name); /** an extended name */ char* ixname = new char[length + ixlength]; memcpy (ixname, name, length); out.indent (indent); out.append (name); out.append (".s="); out.append (getCapacity ()); out.append (indent ? ";\n" : ", "); // initialized buffer items for (card_t i = 0; i < getSize () && myComponents[i]; ) { snprintf (ixname + length, ixlength, ".a[%u]", i); myComponents[i++]->compileInit (ixname, indent, out); if (i < getSize () && myComponents[i] && !indent) out.append (", "); } delete[] ixname; } bool BufferValue::compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const { /** length of the supplied name string */ size_t length = strlen (var); /** an extended name */ char* ixname = new char[length + ixlength]; memcpy (ixname, var, length); /** length of the buffer value */ card_t capacity = getCapacity (); if (!first) out.indent (indent); out.append (var); out.append (".s"); out.append (equal ? "==" : "!="); out.append (capacity); if (capacity) out.append (equal ? "&&\n" : "||\n"); // initialized buffer items for (card_t i = capacity; i--; ) { snprintf (ixname + length, ixlength, ".a[%u]", i); myComponents[i]->compileEqual (out, indent, ixname, equal, false, !i); } if (!last) out.append (equal ? "&&\n" : "||\n"); delete[] ixname; return true; } unsigned BufferValue::compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const { assert (!equal || last); /** length of the supplied name string */ size_t length = strlen (var); /** an extended name */ char* ixname = new char[length + ixlength]; memcpy (ixname, var, length); /** length of the buffer value */ card_t capacity = getCapacity (); if (!first) out.indent (indent); out.openParen (1); out.append (var); out.append (less ? ".s<" : ".s>"); out.append (capacity); out.append ("||\n"); out.indent (indent + 1); out.openParen (1); out.append (var); out.append (".s=="); out.append (capacity); if (capacity) out.append ("&&\n"); /** number of opened parentheses */ unsigned opened = 2; // initialized buffer items for (card_t i = capacity; i--; ) { snprintf (ixname + length, ixlength, ".a[%u]", i); if (i) { opened += myComponents[i]->compileOrder (out, indent + opened, ixname, less, false, false, false); myComponents[i]->compileEqual (out, indent + opened, ixname, true, false, false); } else opened += myComponents[i]->compileOrder (out, indent + opened, ixname, less, equal, false, true); } out.closeParen (opened); if (!last) out.append ("||\n"); delete[] ixname; return 0; } #endif // EXPR_COMPILE maria-1.3.5/Value/BufferValue.h0000644000175000017500000001175407643253065016434 0ustar msmakelamsmakela// Buffer value class -*- c++ -*- #ifndef BUFFERVALUE_H_ # define BUFFERVALUE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Value.h" # include "ValueList.h" /** @file BufferValue.h * The contents of a queue or stack */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Buffer value */ class BufferValue : public Value { public: /** Constructor * @param type type of the value */ BufferValue (const class Type& type); private: /** Copy constructor */ BufferValue (const class BufferValue& old); /** Assignment operator */ class BufferValue& operator= (const class BufferValue& old); public: /** Destructor */ ~BufferValue (); /** Virtual copy constructor */ class Value* copy () const { return new class BufferValue (*this); } /** Determine the kind of the value */ enum Kind getKind () const { return vBuffer; } /** Determine the maximum number of components in the buffer */ card_t getSize () const { return myComponents.getSize (); } /** Determine the current capacity of the buffer */ card_t getCapacity () const { for (card_t i = getSize (); i; ) if (myComponents[--i]) return i + 1; return 0; } /** Address a component by index */ const class Value* operator[] (card_t i) const { return myComponents[i]; } /** Address a component by index */ class Value*& operator[] (card_t i) { return myComponents[i]; } /** Less-than comparison */ bool operator< (const class BufferValue& other) const; /** Equality comparison */ bool operator== (const class BufferValue& other) const; /** Difference operator * @param other value to be substracted from this (may not be less) * @return the difference */ card_t operator- (const class BufferValue& other) const; /** Reset the value to the first value */ void bottom (); /** Reset the value to the last value */ void top (); /** Get the next value * @return false if the value wrapped around; otherwise true */ bool increment (); /** Get the previous value * @return false if the value wrapped around; otherwise true */ bool decrement (); /** Convert the value to another type if possible * @param type type to be casted to * @return the converted value, or NULL */ class Value* cast (const class Type& type); /** Display this object * @param printer The printer object */ void display (const class Printer& printer) const; # ifdef EXPR_COMPILE /** Dump this value in C notation * @param out the output stream */ void compile (class StringBuffer& out) const; /** Generate C assignment statements for initializing this value * @param name name of the lvalue * @param indent indentation level (0=generate a compound statement) * @param out output stream for the generated code */ void compileInit (const char* name, unsigned indent, class StringBuffer& out) const; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indenting) * @param last flag: last component (no expression chaining) * @return true if any code was generated */ bool compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const; /** Generate ordering comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param less comparison type: true=less, false=greater * @param equal comparison type: true=equal, false=unequal * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @return number of parentheses left open */ unsigned compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const; # endif // EXPR_COMPILE private: /** The components */ class ValueList myComponents; }; #endif // BUFFERVALUE_H_ maria-1.3.5/Value/Error.h0000644000175000017500000000322707643253065015313 0ustar msmakelamsmakela/* Error codes -*- c -*- */ #ifndef ERROR_H_ # define ERROR_H_ /** @file Error.h * Evaluation error codes from the compiled code */ /* Copyright © 2000-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Error codes */ enum Error { errNone = 0, /* no error */ errConst, /* constraint violation */ errVar, /* undefined variable */ errUndef, /* undefined expression evaluated */ errFatal, /* fatal expression evaluated */ errDiv0, /* division by zero */ errOver, /* overflow */ errMod, /* modulus error */ errShift, /* shift error */ errUnion, /* attempt to reference a non-active union component */ errBuf, /* buffer boundary violation */ /* codes not used by the low-level expression evaluator */ errCard, /* cardinality overflow */ errComp /* incompatible values (no actual error) */ }; #endif /* ERROR_H_ */ maria-1.3.5/Value/LeafValue.C0000644000175000017500000001535410254524067016020 0ustar msmakelamsmakela// Integer value class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "LeafValue.h" #include "EnumType.h" #include "IdType.h" #include "Constraint.h" /** @file LeafValue.C * Non-compound value (representable in a machine word) */ /* Copyright © 1999-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Determine the smallest value of an unconstrained type * @param type the data type * @return the smallest value */ inline static card_t bottomValue (const class Type& type) { switch (type.getKind ()) { case Type::tInt: return card_t (INT_T_MIN); case Type::tEnum: return static_cast(type).getFirstEnum (); default: return 0; } } /** Determine the largest value of an unconstrained type * @param type the data type * @return the largest value */ inline static card_t topValue (const class Type& type) { switch (type.getKind ()) { case Type::tInt: return INT_T_MAX; case Type::tCard: return CARD_T_MAX; case Type::tBool: return true; case Type::tChar: return CHAR_T_MAX; case Type::tEnum: return static_cast(type).getLastEnum (); case Type::tId: return static_cast(type).getSize () - 1; case Type::tStruct: case Type::tVector: case Type::tUnion: case Type::tBuffer: break; } assert (false); return 0; } bool LeafValue::operator< (const class LeafValue& other) const { assert (getType ().getKind () == other.getType ().getKind ()); if (getType ().getKind () == Type::tInt) return int_t (myValue) < int_t (other.myValue); return myValue < other.myValue; } card_t LeafValue::operator- (const class LeafValue& other) const { assert (!(*this < other)); if (getType ().getKind () == Type::tInt) return int_t (myValue) - int_t (other.myValue); return myValue - other.myValue; } void LeafValue::bottom () { if (const class Constraint* c = getType ().getConstraint ()) { const class Value& v = c->getFirstValue (); assert (&v.getType () == &getType () && v.getKind () == getKind ()); myValue = static_cast(v).myValue; } else myValue = ::bottomValue (getType ()); } void LeafValue::top () { if (const class Constraint* c = getType ().getConstraint ()) { const class Value& v = c->getLastValue (); assert (&v.getType () == &getType () && v.getKind () == getKind ()); myValue = static_cast(v).myValue; } else myValue = ::topValue (getType ()); } bool LeafValue::increment () { if (myValue == ::topValue (getType ())) { bottom (); return false; } if (const class Constraint* c = getType ().getConstraint ()) { const class Value* v = &c->getNextHigh (*this); assert (&v->getType () == &getType () && v->getKind () == getKind ()); if (myValue == static_cast(v)->myValue) { if (!(v = c->getNextLow (*this))) { bottom (); return false; } assert (&v->getType () == &getType () && v->getKind () == getKind ()); myValue = static_cast(v)->myValue; return true; } } myValue++; return true; } bool LeafValue::decrement () { if (myValue == ::bottomValue (getType ())) { top (); return false; } if (const class Constraint* c = getType ().getConstraint ()) { const class Value* v = &c->getPrevLow (*this); assert (&v->getType () == &getType () && v->getKind () == getKind ()); if (myValue == static_cast(v)->myValue) { if (!(v = c->getPrevHigh (*this))) { top (); return false; } assert (&v->getType () == &getType () && v->getKind () == getKind ()); myValue = static_cast(v)->myValue; return true; } } myValue--; return true; } #include "Printer.h" void LeafValue::display (const class Printer& printer) const { switch (getType ().getKind ()) { case Type::tInt: printer.print (int_t (myValue)); break; case Type::tBool: printer.print (bool (myValue)); break; case Type::tChar: printer.print (char_t (myValue)); break; case Type::tEnum: if (const char* const comp = static_cast(getType ()).getEnumName (myValue)) { printer.print (comp); break; } case Type::tId: case Type::tCard: printer.print (myValue); break; case Type::tStruct: case Type::tVector: case Type::tUnion: case Type::tBuffer: assert (false); } } #ifdef EXPR_COMPILE # include "StringBuffer.h" void LeafValue::compile (class StringBuffer& out) const { if (getType ().getKind () == Type::tInt) { if (int_t (myValue) == INT_T_MIN) out.append ("INT_MIN"); else if (int_t (myValue) == INT_T_MAX) out.append ("INT_MAX"); else out.append (int_t (myValue)); } else if (myValue == CARD_T_MAX) out.append ("UINT_MAX"); else out.append (myValue); } void LeafValue::compileInit (const char* name, unsigned indent, class StringBuffer& out) const { if (indent) out.indent (indent); out.append (name); out.append ("="); compile (out); if (indent) out.append (";\n"); } bool LeafValue::compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const { if (!first) out.indent (indent); out.append (var); out.append (equal ? "==" : "!="); compile (out); if (!last) out.append (equal ? "&&\n" : "||\n"); return true; } unsigned LeafValue::compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const { assert (!equal || last); if (!first) out.indent (indent); if (!last) out.openParen (1); out.append (var); out.append (less ? (equal ? "<=" : "<") : (equal ? ">=" : ">")); compile (out); if (!last) { out.append ("||\n"); return 1; } else return 0; } #endif // EXPR_COMPILE maria-1.3.5/Value/LeafValue.h0000644000175000017500000001305207643253065016063 0ustar msmakelamsmakela// Leaf value class -*- c++ -*- #ifndef LEAFVALUE_H_ # define LEAFVALUE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Value.h" /** @file LeafValue.h * Non-compound value (representable in a machine word) */ /* Copyright © 1999-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Leaf value */ class LeafValue : public Value { public: /** Constructor * @param type type of the value * @param value the value (signed) */ LeafValue (const class Type& type, int_t value) : Value (type), myValue (value) {} /** Constructor * @param type type of the value * @param value the value (signed) */ LeafValue (const class Type& type, card_t value) : Value (type), myValue (value) {} /** Constructor * @param type type of the value * @param value the value (signed) */ LeafValue (const class Type& type, char_t value) : Value (type), myValue (value) {} /** Constructor * @param type type of the value * @param value the value (signed) */ LeafValue (const class Type& type, bool value) : Value (type), myValue (value) {} /** Constructor, initialize to the smallest possible value * @param type type of the value */ LeafValue (const class Type& type); /** Copy constructor */ LeafValue (const class LeafValue& old) : Value (old), myValue (old.myValue) {} private: /** Assignment operator */ class LeafValue& operator= (const class LeafValue& old); public: /** Destructor */ ~LeafValue () {} /** Virtual copy constructor */ class Value* copy () const { return new class LeafValue (*this); } /** Determine the kind of the value */ enum Kind getKind () const { return vLeaf; } /** @name Determine the value */ /*@{*/ operator int_t () const { return myValue; } operator card_t () const { return myValue; } operator char_t () const { return myValue; } operator bool () const { return myValue; } /*@}*/ /** @name Set the value */ /*@{*/ void setValue (int_t value) { myValue = value; } void setValue (card_t value) { myValue = value; } void setValue (char_t value) { myValue = value; } void setValue (bool value) { myValue = value; } /*@}*/ /** Less-than comparison */ bool operator< (const class LeafValue& other) const; /** Equality comparison */ bool operator== (const class LeafValue& other) const { return myValue == other.myValue; } /** Difference operator * @param other value to be substracted from this (may not be less) * @return the difference */ card_t operator- (const class LeafValue& other) const; /** Reset the value to the first value */ void bottom (); /** Reset the value to the last value */ void top (); /** Get the next value * @return false if the value wrapped around; otherwise true */ bool increment (); /** Get the previous value * @return false if the value wrapped around; otherwise true */ bool decrement (); /** Display this object * @param printer The printer object */ void display (const class Printer& printer) const; # ifdef EXPR_COMPILE /** Dump this value in C notation * @param out the output stream */ void compile (class StringBuffer& out) const; /** Generate C assignment statements for initializing this value * @param name name of the lvalue * @param indent indentation level (0=generate a compound statement) * @param out output stream for the generated code */ void compileInit (const char* name, unsigned indent, class StringBuffer& out) const; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @return true if any code was generated */ bool compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const; /** Generate ordering comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param less comparison type: true=less, false=greater * @param equal comparison type: true=equal, false=unequal * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @return number of parentheses left open */ unsigned compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const; # endif // EXPR_COMPILE private: /** The value */ card_t myValue; }; #endif // LEAFVALUE_H_ maria-1.3.5/Value/StructValue.C0000644000175000017500000002222707643253065016437 0ustar msmakelamsmakela// Structure value class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "StructValue.h" #include "StructType.h" #include "Constraint.h" /** @file StructValue.C * Structure value */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ StructValue::StructValue (const class Type& type) : Value (type), myComponents (static_cast(type).getSize ()) { assert (getType ().getKind () == Type::tStruct); } StructValue::StructValue (const class StructValue& old) : Value (old.getType ()), myComponents (old.myComponents) { assert (getType ().getKind () == Type::tStruct); } StructValue::~StructValue () { } bool StructValue::operator< (const class StructValue& other) const { assert (other.myComponents.getSize () == myComponents.getSize ()); for (card_t i = myComponents.getSize (); i--; ) if (*myComponents[i] < *other.myComponents[i]) return true; else if (*other.myComponents[i] < *myComponents[i]) return false; return false; } bool StructValue::operator== (const class StructValue& other) const { assert (other.myComponents.getSize () == myComponents.getSize ()); for (card_t i = myComponents.getSize (); i--; ) if (!(*myComponents[i] == *other.myComponents[i])) return false; return true; } void StructValue::bottom () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value& v = c->getFirstValue (); assert (&v.getType () == &getType () && v.getKind () == getKind ()); const class StructValue& sv = static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = sv[i].copy (); } } else for (card_t i = 0; i < getSize (); i++) myComponents[i]->bottom (); } void StructValue::top () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value& v = c->getLastValue (); assert (&v.getType () == &getType () && v.getKind () == getKind ()); const class StructValue& sv = static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = sv[i].copy (); } } else for (card_t i = 0; i < getSize (); i++) myComponents[i]->top (); } card_t StructValue::operator- (const class StructValue& other) const { if (!getSize ()) return 0; card_t i, numValues; for (i = numValues = 1; i < getSize (); i++) numValues *= myComponents[i - 1]->getType ().getNumValues (); card_t diff = 0; for (i = getSize (); --i; numValues /= myComponents[i - 1]->getType ().getNumValues ()) if (*myComponents[i] < *other.myComponents[i]) diff -= (*other.myComponents[i] - *myComponents[i]) * numValues; else diff += (*myComponents[i] - *other.myComponents[i]) * numValues; assert (numValues == 1); if (*myComponents[0] < *other.myComponents[0]) diff -= *other.myComponents[0] - *myComponents[0]; else diff += *myComponents[0] - *other.myComponents[0]; return diff; } bool StructValue::increment () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value* v = &c->getNextHigh (*this); assert (&v->getType () == &getType () && v->getKind () == getKind ()); if (*this == *static_cast(v)) { if (!(v = c->getNextLow (*this))) { bottom (); return false; } assert (&v->getType () == &getType () && v->getKind () == getKind ()); const class StructValue& sv = *static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = sv[i].copy (); } return true; } } for (card_t i = 0; i < getSize (); i++) if (myComponents[i]->increment ()) return true; if (getType ().getConstraint ()) bottom (); return false; } bool StructValue::decrement () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value* v = &c->getPrevLow (*this); assert (&v->getType () == &getType () && v->getKind () == getKind ()); if (*this == *static_cast(v)) { if (!(v = c->getPrevHigh (*this))) { top (); return false; } assert (&v->getType () == &getType () && v->getKind () == getKind ()); const class StructValue& sv = *static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = sv[i].copy (); } return true; } } for (card_t i = 0; i < getSize (); i++) if (myComponents[i]->decrement ()) return true; if (getType ().getConstraint ()) top (); return false; } class Value* StructValue::cast (const class Type& type) { assert (getType ().isAssignable (type)); if (type.getKind () != Type::tStruct) return Value::cast (type); const class StructType& st = static_cast(type); assert (getSize () == st.getSize ()); for (card_t i = getSize (); i--; ) { if (!((*this)[i] = (*this)[i]->cast (st[i]))) { delete this; return NULL; } } return Value::cast (type); } #include "Printer.h" void StructValue::display (const class Printer& printer) const { if (getSize ()) { printer.delimiter ('{')++; for (card_t i = 0;;) { myComponents[i]->display (printer); if (++i == getSize ()) break; else printer.delimiter (','); } printer--.delimiter ('}'); } else printer.delimiter ('{').delimiter ('}'); } #ifdef EXPR_COMPILE # include "StringBuffer.h" # include /** maximum length of a 64-bit index value, plus delimiters */ static const size_t ixlength = 23; void StructValue::compile (class StringBuffer&) const { assert (false); } void StructValue::compileInit (const char* name, unsigned indent, class StringBuffer& out) const { /** length of the supplied name string */ size_t length = strlen (name); /** an extended name */ char* ixname = new char[length + ixlength]; memcpy (ixname, name, length); for (card_t i = 0; i < getSize (); ) { snprintf (ixname + length, ixlength, ".s%u", i); myComponents[i]->compileInit (ixname, indent, out); if (++i < getSize () && !indent) out.append (", "); } delete[] ixname; } bool StructValue::compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const { if (!getSize ()) return false; /** length of the supplied name string */ size_t length = strlen (var); /** an extended name */ char* ixname = new char[length + ixlength]; memcpy (ixname, var, length); for (card_t i = getSize (); i--; ) { snprintf (ixname + length, ixlength, ".s%u", i); if (myComponents[i]->compileEqual (out, indent, ixname, equal, first, !i)) first = false; } delete[] ixname; if (!last) out.append (equal ? "&&\n" : "||\n"); return true; } unsigned StructValue::compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const { assert (!equal || last); /** length of the supplied name string */ size_t length = strlen (var); /** an extended name */ char* ixname = new char[length + ixlength]; memcpy (ixname, var, length); /** number of opened parentheses */ unsigned opened = 0; for (card_t i = getSize (); i--; first = false) { snprintf (ixname + length, ixlength, ".s%u", i); if (i) { opened += myComponents[i]->compileOrder (out, indent + opened, ixname, less, false, first, false); myComponents[i]->compileEqual (out, indent, ixname, true, first, false); } else opened += myComponents[i]->compileOrder (out, indent + opened, ixname, less, equal, first, true); } out.closeParen (opened); if (getSize ()) { if (!last) out.append ("||\n"); } else if (last) out.append (equal ? "1" : "0"); delete[] ixname; return 0; } #endif // EXPR_COMPILE maria-1.3.5/Value/StructValue.h0000644000175000017500000001144007643253065016477 0ustar msmakelamsmakela// Structure value class -*- c++ -*- #ifndef STRUCTVALUE_H_ # define STRUCTVALUE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Value.h" # include "ValueList.h" /** @file StructValue.h * Structure value */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Structure value */ class StructValue : public Value { public: /** Constructor * @param type type of the value */ StructValue (const class Type& type); private: /** Copy constructor */ StructValue (const class StructValue& old); /** Assignment operator */ class StructValue& operator= (const class StructValue& old); public: /** Destructor */ ~StructValue (); /** Virtual copy constructor */ class Value* copy () const { return new class StructValue (*this); } /** Determine the kind of the value */ enum Kind getKind () const { return vStruct; } /** Determine the number of components in the struct */ card_t getSize () const { return myComponents.getSize (); } /** Address a component by index */ const class Value& operator[] (card_t i) const { return *myComponents[i]; } /** Address a component by index */ class Value*& operator[] (card_t i) { return myComponents[i]; } /** Less-than comparison */ bool operator< (const class StructValue& other) const; /** Equality comparison */ bool operator== (const class StructValue& other) const; /** Difference operator * @param other value to be substracted from this (may not be less) * @return the difference */ card_t operator- (const class StructValue& other) const; /** Reset the value to the first value */ void bottom (); /** Reset the value to the last value */ void top (); /** Get the next value * @return false if the value wrapped around; otherwise true */ bool increment (); /** Get the previous value * @return false if the value wrapped around; otherwise true */ bool decrement (); /** Convert the value to another type if possible * @param type type to be casted to * @return the converted value, or NULL */ class Value* cast (const class Type& type); /** Display this object * @param printer The printer object */ void display (const class Printer& printer) const; # ifdef EXPR_COMPILE /** Dump this value in C notation * @param out the output stream */ void compile (class StringBuffer& out) const; /** Generate C assignment statements for initializing this value * @param name name of the lvalue * @param indent indentation level (0=generate a compound statement) * @param out output stream for the generated code */ void compileInit (const char* name, unsigned indent, class StringBuffer& out) const; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indenting) * @param last flag: last component (no expression chaining) * @return true if any code was generated */ bool compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const; /** Generate ordering comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param less comparison type: true=less, false=greater * @param equal comparison type: true=equal, false=unequal * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @return number of parentheses left open */ unsigned compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const; # endif // EXPR_COMPILE private: /** The components */ class ValueList myComponents; }; #endif // STRUCTVALUE_H_ maria-1.3.5/Value/UnionValue.C0000644000175000017500000002014507643253065016240 0ustar msmakelamsmakela// Union value class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "UnionValue.h" #include "UnionType.h" #include "Constraint.h" /** @file UnionValue.C * Union value */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ UnionValue::UnionValue (const class Type& type, card_t i, class Value& value) : Value (type), myIndex (i), myValue (&value) { assert (getType ().getKind () == Type::tUnion); assert (&myValue->getType () == &static_cast(getType ())[myIndex]); } UnionValue::UnionValue (const class UnionValue& old) : Value (old.getType ()), myIndex (old.myIndex), myValue (old.myValue->copy ()) { assert (getType ().getKind () == Type::tUnion); assert (myValue && &myValue->getType () == &static_cast(getType ())[myIndex]); } UnionValue::~UnionValue () { delete myValue; } bool UnionValue::operator< (const class UnionValue& other) const { assert (&getType () == &other.getType ()); if (myIndex < other.myIndex) return true; else if (other.myIndex < myIndex) return false; else return getValue () < other.getValue (); } bool UnionValue::operator== (const class UnionValue& other) const { assert (&getType () == &other.getType ()); return myIndex == other.myIndex && getValue () == other.getValue (); } card_t UnionValue::operator- (const class UnionValue& other) const { const class UnionType& type = static_cast(getType ()); card_t diff = type.getCumulatedValues (myIndex) - type.getCumulatedValues (other.myIndex); if (myIndex == other.myIndex) diff += getValue () - other.getValue (); else diff += type[myIndex].convert (getValue ()) - type[other.myIndex].convert (other.getValue ()); return diff; } void UnionValue::bottom () { delete myValue; if (const class Constraint* c = getType ().getConstraint ()) { const class Value& v = c->getFirstValue (); assert (&v.getType () == &getType () && v.getKind () == getKind ()); const class UnionValue& uv = static_cast(v); myIndex = uv.myIndex; myValue = uv.myValue->copy (); return; } myValue = &static_cast(getType ()) [myIndex = 0].getFirstValue (); } void UnionValue::top () { delete myValue; if (const class Constraint* c = getType ().getConstraint ()) { const class Value& v = c->getLastValue (); assert (&v.getType () == &getType () && v.getKind () == getKind ()); const class UnionValue& uv = static_cast(v); myIndex = uv.myIndex; myValue = uv.myValue->copy (); return; } const class UnionType& type = static_cast(getType ()); myValue = &type[myIndex = type.getSize () - 1].getLastValue (); } bool UnionValue::increment () { if (const class Constraint* c = getType ().getConstraint ()) { const class Value* v = &c->getNextHigh (*this); assert (&v->getType () == &getType () && v->getKind () == getKind ()); if (*this == *static_cast(v)) { if (!(v = c->getNextLow (*this))) { bottom (); return false; } assert (&v->getType () == &getType () && v->getKind () == getKind ()); const class UnionValue& uv = *static_cast(v); delete myValue; myIndex = uv.myIndex; myValue = uv.myValue->copy (); return true; } } if (myValue->increment ()) return true; if (++myIndex == static_cast(getType ()).getSize ()) myIndex = 0; delete myValue; myValue = &static_cast(getType ()) [myIndex].getFirstValue (); return myIndex != 0; } bool UnionValue::decrement () { if (const class Constraint* c = getType ().getConstraint ()) { const class Value* v = &c->getPrevLow (*this); assert (&v->getType () == &getType () && v->getKind () == getKind ()); if (*this == *static_cast(v)) { if (!(v = c->getPrevHigh (*this))) { top (); return false; } assert (&v->getType () == &getType () && v->getKind () == getKind ()); const class UnionValue& uv = *static_cast(v); delete myValue; myIndex = uv.myIndex; myValue = uv.myValue->copy (); return true; } } if (myValue->decrement ()) return true; if (!myIndex) { top (); return false; } delete myValue; myValue = &static_cast(getType ()) [--myIndex].getLastValue (); return true; } class Value* UnionValue::cast (const class Type& type) { if (type.getKind () == Type::tUnion) return Value::cast (type); const class UnionType& ut = static_cast(getType ()); if (!ut[myIndex].isAssignable (type)) { delete this; return NULL; } class Value* v = myValue; myValue = NULL; delete this; return v; } #include "Printer.h" void UnionValue::display (const class Printer& printer) const { printer.print (static_cast(getType ()) .getComponentName (myIndex)); printer.delimiter ('=')++; myValue->display (printer); printer--; } #ifdef EXPR_COMPILE # include "StringBuffer.h" # include /** Get a C name of this union lvalue * @param prefix prefix C name of the base lvalue * @param i index number of the active union component */ static char* getLvalueName (const char* prefix, unsigned i) { const size_t length = strlen (prefix), ilength = 25; char* name = new char[length + ilength]; memcpy (name, prefix, length); snprintf (name + length, ilength, ".u.u%u", i); return name; } void UnionValue::compile (class StringBuffer&) const { assert (false); } void UnionValue::compileInit (const char* name, unsigned indent, class StringBuffer& out) const { char* ixname = getLvalueName (name, myIndex); out.indent (indent); out.append (name); out.append (".t="); out.append (myIndex); out.append (indent ? ";\n" : ", "); myValue->compileInit (ixname, indent, out); delete[] ixname; } bool UnionValue::compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const { char* ixname = getLvalueName (var, myIndex); if (!first) out.indent (indent); out.append (var); out.append (".t"); out.append (equal ? "==" : "!="); out.append (myIndex); out.append (equal ? "&&\n" : "||\n"); if (!myValue->compileEqual (out, indent, ixname, equal, false, last) && last) out.chop (3); delete[] ixname; return true; } unsigned UnionValue::compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const { assert (!equal || last); char* ixname = getLvalueName (var, myIndex); if (!first) out.indent (indent); out.openParen (1); out.append (var); out.append (less ? ".t<" : ".t>"); out.append (myIndex); out.append ("||\n"); out.indent (indent + 1); out.openParen (1); out.append (var); out.append (".t=="); out.append (myIndex); out.append ("&&\n"); myValue->compileOrder (out, indent, ixname, less, equal, false, true); out.closeParen (2); if (!last) out.append ("||\n"); delete[] ixname; return 0; } #endif // EXPR_COMPILE maria-1.3.5/Value/UnionValue.h0000644000175000017500000001146007643253065016305 0ustar msmakelamsmakela// Union value class -*- c++ -*- #ifndef UNIONVALUE_H_ # define UNIONVALUE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Value.h" /** @file UnionValue.h * Union value */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Union value */ class UnionValue : public Value { public: /** Constructor * @param type the union type * @param i index of the selected component * @param value value of the selected component */ UnionValue (const class Type& type, card_t i, class Value& value); private: /** Copy constructor */ UnionValue (const class UnionValue& old); /** Assignment operator */ class UnionValue& operator= (const class UnionValue& old); public: /** Destructor */ ~UnionValue (); /** Virtual copy constructor */ class Value* copy () const { return new class UnionValue (*this); } /** Determine the kind of the value */ enum Kind getKind () const { return vUnion; } /** Determine the index of the present component */ card_t getIndex () const { return myIndex; } /** Determine the value of the present component */ const class Value& getValue () const { return *myValue; } /** Less-than comparison */ bool operator< (const class UnionValue& other) const; /** Equality comparison */ bool operator== (const class UnionValue& other) const; /** Difference operator * @param other value to be substracted from this (may not be less) * @return the difference */ card_t operator- (const class UnionValue& other) const; /** Reset the value to the first value */ void bottom (); /** Reset the value to the last value */ void top (); /** Get the next value * @return false if the value wrapped around; otherwise true */ bool increment (); /** Get the previous value * @return false if the value wrapped around; otherwise true */ bool decrement (); /** Convert the value to another type if possible * @param type type to be casted to * @return the converted value, or NULL */ class Value* cast (const class Type& type); /** Display this object * @param printer The printer object */ void display (const class Printer& printer) const; # ifdef EXPR_COMPILE /** Dump this value in C notation * @param out the output stream */ void compile (class StringBuffer& out) const; /** Generate C assignment statements for initializing this value * @param name name of the lvalue * @param indent indentation level (0=generate a compound statement) * @param out output stream for the generated code */ void compileInit (const char* name, unsigned indent, class StringBuffer& out) const; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indenting) * @param last flag: last component (no expression chaining) * @return true if any code was generated */ bool compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const; /** Generate ordering comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param less comparison type: true=less, false=greater * @param equal comparison type: true=equal, false=unequal * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @return number of parentheses left open */ unsigned compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const; # endif // EXPR_COMPILE private: /** Index of the referenced union component */ card_t myIndex; /** Value of the component */ class Value* myValue; }; #endif // UNIONVALUE_H_ maria-1.3.5/Value/Valuation.C0000644000175000017500000001134307643253065016115 0ustar msmakelamsmakela// Valuation (value distribution for variables) -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Valuation.h" #include "Value.h" #include "VariableDefinition.h" #ifndef NDEBUG # include "Type.h" #endif // NDEBUG /** @file Valuation.C * Assignment of variables to values */ /* Copyright © 1999-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ Valuation::Valuation () : myValues (), myError (errNone), myExpr (0), myGlobalMarking (0) { } Valuation::Valuation (const class Valuation& old) : myValues (), myError (old.myError), myExpr (old.myExpr), myGlobalMarking (old.myGlobalMarking) { for (const_iterator i = old.myValues.begin (); i != old.myValues.end (); i++) { assert (i->second != NULL); myValues[i->first] = i->second->copy (); } } Valuation::~Valuation () { for (iterator i = myValues.begin (); i != myValues.end (); i++) delete i->second; } const class Value* Valuation::getValue (const class VariableDefinition& var) const { const_iterator i = myValues.find (&var); if (i == myValues.end ()) return NULL; return i->second; } void Valuation::setValue (const class VariableDefinition& var, class Value& value) { assert (var.getType ().isConstrained (value)); Map::value_type p (&var, &value); std::pair status = myValues.insert (p); if (!status.second) { delete status.first->second; myValues.erase (status.first); status = myValues.insert (p); assert (status.second); } } bool Valuation::increment (const class VariableDefinition& var) { const_iterator i = myValues.find (&var); assert (i != myValues.end ()); return i->second->increment (); } bool Valuation::decrement (const class VariableDefinition& var) { const_iterator i = myValues.find (&var); assert (i != myValues.end ()); return i->second->decrement (); } bool Valuation::undefine (const class VariableDefinition& var) { iterator i = myValues.find (&var); if (i == myValues.end ()) return false; delete i->second; myValues.erase (i); return true; } const char* Valuation::msg (enum Error err) { switch (err) { case errNone: return "noError"; case errConst: return "constraintViolation"; case errVar: return "undefinedVariable"; case errUndef: return "undefinedExpression"; case errFatal: return "fatalExpression"; case errDiv0: return "divisionByZero"; case errOver: return "overflow"; case errMod: return "modulusError"; case errShift: return "shiftError"; case errUnion: return "unionViolation"; case errBuf: return "bufferViolation"; case errCard: return "cardinalityOverflow"; case errComp: return "unificationError"; } assert (false); return 0; } #include "Printer.h" #include "Expression.h" void Valuation::display (const class Printer& printer, bool hide) const { printer.delimiter ('<')++; if (myError) { printer.printRaw (msg (myError)); if (myExpr) { printer.delimiter (':'); printer++.linebreak (); myExpr->display (printer); printer--; } } else assert (!myExpr); for (const_iterator i = myValues.begin (); i != myValues.end (); i++) { if (hide && i->first->isHidden ()) continue; printer.linebreak (); printer.print (i->first->getName ()); printer.delimiter (':')++; i->second->display (printer); printer--; } printer--.linebreak (); printer.delimiter ('>'); } void Valuation::displayEscaped (class StringBuffer& out, bool hide) const { assert (!myError); class Printer printer; printer.setOutput (&out); for (const_iterator v = myValues.begin (); v != myValues.end (); v++) { if (hide && v->first->isHidden ()) continue; out.append ('_', 2); unsigned i = out.getLength (); out.append (v->first->getName ()); out.escape (i); out.append ('_', 2); i = out.getLength (); v->second->display (printer); out.escape (i); } } maria-1.3.5/Value/Valuation.h0000644000175000017500000001347707643253065016174 0ustar msmakelamsmakela// Valuation (value distribution for variables) -*- c++ -*- #ifndef VALUATION_H_ # define VALUATION_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include # include "Error.h" /** @file Valuation.h * Assignment of variables to values */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Valuation (value distribution for variables) */ class Valuation { /** Pointer comparator */ struct vptr { bool operator () (const class VariableDefinition* v1, const class VariableDefinition* v2) const { return v1 < v2; } }; public: /** Map from variables to their values */ typedef std::map Map; /** Iterator to the valuation map */ typedef Map::iterator iterator; /** Constant iterator to the valuation map */ typedef Map::const_iterator const_iterator; /** Constructor */ Valuation (); /** Copy constructor */ Valuation (const class Valuation& old); private: /** Assignment operator */ class Valuation& operator= (const class Valuation& old); public: /** Destructor */ ~Valuation (); /** Get the value of a variable * @param var identifies the variable * @return the value, or NULL if there is none */ const class Value* getValue (const class VariableDefinition& var) const; /** Assign a value to a variable. If the variable already has a value, * delete the old value. * @param var identifies the variable * @param value value to be assigned */ void setValue (const class VariableDefinition& var, class Value& value); /** Get the global marking */ const class GlobalMarking* getGlobalMarking () const { return myGlobalMarking; } /** Set the global marking * @param m the new global marking */ void setGlobalMarking (const class GlobalMarking* m) { myGlobalMarking = m; } /** Increase the value of a variable in the valuation * @param var identifies the variable * @return false if the value wrapped around; otherwise true */ bool increment (const class VariableDefinition& var); /** Decrease the value of a variable in the valuation * @param var identifies the variable * @return false if the value wrapped around; otherwise true */ bool decrement (const class VariableDefinition& var); /** Remove the value of a variable from the valuation * @param var identifies the variable * @return true if the value was previously defined */ bool undefine (const class VariableDefinition& var); /** Iterator to the beginning of the assignment collection */ const_iterator begin () const { return myValues.begin (); } /** Iterator to the end of the assignment collection */ const_iterator end () const { return myValues.end (); } /** Determine whether the valuation is clear of errors */ bool isOK () const { return !myError; } /** Determine whether the valuation is clear of errors * or a variable is undefined */ bool isOKorVar () const { return !myError || myError == errVar; } /** Clear the errors associated with the valuation */ void clearErrors () const { myError = errNone, myExpr = 0; } /** Copy the errors from one valuation to another */ void copyErrors (const class Valuation& v) const { myError = v.myError, myExpr = v.myExpr; } /** Read the error code */ enum Error getError () const { return myError; } /** Determine which expression caused the error */ const class Expression& getExpr () const { assert (!!myExpr); return *myExpr; } /** Flag an error * @param error error code * @param expr expression that caused the error */ void flag (enum Error error, const class Expression& expr) const { assert (error && !myError && !myExpr); myError = error, myExpr = &expr; } /** Flag a unification error */ void flagUnificationError () const { myError = errComp; } /** Flag an undefined situation * @param fatal flag: is this a fatal situation? */ void flagUndefined (bool fatal) const { assert (!myError && !myExpr); myError = fatal ? errFatal : errUndef; } /** Translate an error code to an error message * @param err error code * @return the translated message */ static const char* msg (enum Error err); /** Display this object * @param printer The printer object * @param hide Flag: omit hidden variables and values */ void display (const class Printer& printer, bool hide = false) const; /** Convert the valuation to an alphanumeric identifier * @param out The output stream * @param hide Flag: omit hidden variables and values */ void displayEscaped (class StringBuffer& out, bool hide = false) const; private: /** The values sorted by variable names */ Map myValues; /** Errors occurred while processing the valuation */ mutable enum Error myError; /** Expression that caused the error */ mutable const class Expression* myExpr; /** The global marking (if available) */ const class GlobalMarking* myGlobalMarking; }; #endif // VALUATION_H_ maria-1.3.5/Value/Value.C0000644000175000017500000000762307643253065015235 0ustar msmakelamsmakela// Value base class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "allValues.h" #include "UnionType.h" /** @file Value.C * Abstract base class for values */ /* Copyright © 1999-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ bool Value::operator< (const class Value& other) const { assert (other.getKind () == getKind ()); switch (getKind ()) { case vLeaf: return static_cast(*this) < static_cast(other); case vStruct: return static_cast(*this) < static_cast(other); case vUnion: return static_cast(*this) < static_cast(other); case vVector: return static_cast(*this) < static_cast(other); case vBuffer: return static_cast(*this) < static_cast(other); } assert (false); return false; } bool Value::operator== (const class Value& other) const { assert (other.getKind () == getKind ()); switch (getKind ()) { case vLeaf: return static_cast(*this) == static_cast(other); case vStruct: return static_cast(*this) == static_cast(other); case vUnion: return static_cast(*this) == static_cast(other); case vVector: return static_cast(*this) == static_cast(other); case vBuffer: return static_cast(*this) == static_cast(other); } assert (false); return false; } card_t Value::operator- (const class Value& other) const { assert (other.getKind () == getKind ()); assert (!(*this < other)); switch (getKind ()) { case vLeaf: return static_cast(*this) - static_cast(other); case vStruct: return static_cast(*this) - static_cast(other); case vUnion: return static_cast(*this) - static_cast(other); case vVector: return static_cast(*this) - static_cast(other); case vBuffer: return static_cast(*this) - static_cast(other); } assert (false); return 0; } class Value* Value::cast (const class Type& type) { if (type.getKind () == Type::tUnion) return static_cast(type).cast (*this); if (getKind () != vLeaf || (type.getKind () == myType->getKind () || int_t (static_cast(*this)) >= 0 || myType->getKind () != Type::tInt || type.getKind () == Type::tInt)) { setType (type); if (type.isConstrained (*this)) return this; } delete this; return 0; } maria-1.3.5/Value/Value.h0000644000175000017500000001167707643253065015306 0ustar msmakelamsmakela// Value base class -*- c++ -*- #ifndef VALUE_H_ # define VALUE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include "typedefs.h" /** @file Value.h * Abstract base class for values */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Value base class */ class Value { public: /** Value kinds (@see getKind) */ enum Kind { vLeaf, vStruct, vUnion, vVector, vBuffer }; /** Constructor * @param type Type of the Value */ Value (const class Type& type) : myType (&type) {} /** Copy constructor */ Value (const class Value& old) : myType (old.myType) {} private: /** Assignment operator */ class Value& operator= (const class Value& old); public: /** Destructor */ virtual ~Value () {} /** Virtual copy constructor */ virtual class Value* copy () const = 0; /** Determine the kind of the value */ virtual enum Kind getKind () const = 0; /** Determine the type of the value */ const class Type& getType () const { return *myType; } /** Set the type of the value */ void setType (const class Type& type) { myType = &type; } /** Less-than comparison */ bool operator< (const class Value& other) const; /** Equality comparison */ bool operator== (const class Value& other) const; /** Difference operator * @param other value to be substracted from this (may not be less) * @return the difference */ card_t operator- (const class Value& other) const; /** Reset the value to the first value */ virtual void bottom () = 0; /** Reset the value to the last value */ virtual void top () = 0; /** Get the next value * @return false if the value wrapped around; otherwise true */ virtual bool increment () = 0; /** Get the previous value * @return false if the value wrapped around; otherwise true */ virtual bool decrement () = 0; /** Convert the value to another type if possible * @param type type to be casted to * @return the converted value, or NULL */ virtual class Value* cast (const class Type& type); /** Display this object * @param printer The printer object */ virtual void display (const class Printer& printer) const = 0; # ifdef EXPR_COMPILE /** Dump this value in C notation * @param out the output stream */ virtual void compile (class StringBuffer& out) const = 0; /** Generate C assignment statements for initializing this value * @param name name of the lvalue * @param indent indentation level (0=generate a compound statement) * @param out output stream for the generated code */ virtual void compileInit (const char* name, unsigned indent, class StringBuffer& out) const = 0; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @return true if any code was generated */ virtual bool compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const = 0; /** Generate ordering comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param less comparison type: true=less, false=greater * @param equal comparison type: true=equal, false=unequal * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @return number of parentheses left open */ virtual unsigned compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const = 0; # endif // EXPR_COMPILE private: /** Type of the Value */ const class Type* myType; }; /** Less-or-equal comparison of values */ inline static bool operator<= (const class Value& left, const class Value& right) { return !(right < left); } #endif // VALUE_H_ maria-1.3.5/Value/ValueList.C0000644000175000017500000000336707643253065016072 0ustar msmakelamsmakela// Value list class -*- c++ -*- #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "ValueList.h" #include "Value.h" #include /** @file ValueList.C * List of values (components of StructValue, BufferValue or VectorValue) */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ ValueList::ValueList (card_t size) : mySize (size), myComponents (NULL) { if (mySize) { myComponents = new class Value*[mySize]; memset (myComponents, 0, mySize * sizeof *myComponents); } } ValueList::ValueList (const class ValueList& old) : mySize (old.mySize), myComponents (NULL) { if (mySize) { myComponents = new class Value*[mySize]; for (card_t i = 0; i < mySize; i++) myComponents[i] = old.myComponents[i] ? old.myComponents[i]->copy () : NULL; } } ValueList::~ValueList () { for (card_t i = 0; i < mySize; i++) delete myComponents[i]; delete[] myComponents; } maria-1.3.5/Value/ValueList.h0000644000175000017500000000400407643253065016124 0ustar msmakelamsmakela// Value list class -*- c++ -*- #ifndef VALUELIST_H_ # define VALUELIST_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include "typedefs.h" /** @file ValueList.h * List of values (components of StructValue, BufferValue or VectorValue) */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Value list */ class ValueList { public: /** Constructor * @param size Size of the value list (number of elements) */ ValueList (card_t size); /** Copy constructor */ ValueList (const class ValueList& old); private: /** Assignment operator */ class ValueList& operator= (const class ValueList& old); public: /** Destructor */ ~ValueList (); /** Determine the size of the list */ card_t getSize () const { return mySize; } /** Address an element by index */ class Value*& operator[] (card_t i) { assert (i < mySize); return myComponents[i]; } /** Address an element by index */ const class Value* operator[] (card_t i) const { assert (i < mySize); return myComponents[i]; } private: /** Size of the list */ card_t mySize; /** The values */ class Value** myComponents; }; #endif // VALUELIST_H_ maria-1.3.5/Value/VectorValue.C0000644000175000017500000002224407643253065016414 0ustar msmakelamsmakela// Vector value class -*- c++ -*- #include "snprintf.h" #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "VectorValue.h" #include "VectorType.h" #include "Constraint.h" /** @file VectorValue.C * Array value */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ VectorValue::VectorValue (const class Type& type) : Value (type), myComponents (static_cast(type).getSize ()) { assert (getType ().getKind () == Type::tVector); } VectorValue::VectorValue (const class VectorValue& old) : Value (old.getType ()), myComponents (old.myComponents) { assert (getType ().getKind () == Type::tVector); } VectorValue::~VectorValue () { } bool VectorValue::operator< (const class VectorValue& other) const { assert (other.myComponents.getSize () == myComponents.getSize ()); for (card_t i = myComponents.getSize (); i--; ) { assert (myComponents[i] && other.myComponents[i]); if (*myComponents[i] < *other.myComponents[i]) return true; else if (*other.myComponents[i] < *myComponents[i]) return false; } return false; } bool VectorValue::operator== (const class VectorValue& other) const { assert (other.myComponents.getSize () == myComponents.getSize ()); for (card_t i = myComponents.getSize (); i--; ) { assert (myComponents[i] && other.myComponents[i]); if (!(*myComponents[i] == *other.myComponents[i])) return false; } return true; } card_t VectorValue::operator- (const class VectorValue& other) const { if (!getSize ()) return 0; const class Type& itemType = static_cast(getType ()).getItemType (); card_t numItemValues = itemType.getNumValues (); card_t diff = 0, i = getSize (); while (i--) { card_t d; if (myComponents[i] && other.myComponents[i]) d = *myComponents[i] < *other.myComponents[i] ? -(*other.myComponents[i] - *myComponents[i]) : *myComponents[i] - *other.myComponents[i]; else assert (false), d = 0; (diff *= numItemValues) += d; } return diff; } void VectorValue::bottom () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value& v = c->getFirstValue (); assert (&v.getType () == &getType () && v.getKind () == getKind ()); const class VectorValue& vv = static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = vv[i].copy (); } return; } for (card_t i = 0; i < getSize (); i++) myComponents[i]->bottom (); } void VectorValue::top () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value& v = c->getLastValue (); assert (&v.getType () == &getType () && v.getKind () == getKind ()); const class VectorValue& vv = static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = vv[i].copy (); } return; } for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = &static_cast(getType ()).getItemType () .getLastValue (); } } bool VectorValue::increment () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value* v = &c->getNextHigh (*this); assert (&v->getType () == &getType () && v->getKind () == getKind ()); if (*this == *static_cast(v)) { if (!(v = c->getNextLow (*this))) { bottom (); return false; } assert (&v->getType () == &getType () && v->getKind () == getKind ()); const class VectorValue& vv = *static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = vv[i].copy (); } return true; } } for (card_t i = 0; i < getSize (); i++) if (myComponents[i]->increment ()) return true; if (getType ().getConstraint ()) bottom (); return false; } bool VectorValue::decrement () { assert (getSize () == static_cast(getType ()).getSize ()); if (const class Constraint* c = getType ().getConstraint ()) { const class Value* v = &c->getPrevLow (*this); assert (&v->getType () == &getType () && v->getKind () == getKind ()); if (*this == *static_cast(v)) { if (!(v = c->getPrevHigh (*this))) { top (); return false; } assert (&v->getType () == &getType () && v->getKind () == getKind ()); const class VectorValue& vv = *static_cast(v); for (card_t i = getSize (); i--; ) { delete myComponents[i]; myComponents[i] = vv[i].copy (); } return true; } } for (card_t i = 0; i < getSize (); i++) if (myComponents[i]->decrement ()) return true; if (getType ().getConstraint ()) top (); return false; } class Value* VectorValue::cast (const class Type& type) { assert (getType ().isAssignable (type)); if (type.getKind () != Type::tVector) return Value::cast (type); const class VectorType& vt = static_cast(type); const class Type& itemType = vt.getItemType (); assert (getSize () == vt.getSize ()); for (card_t i = getSize (); i--; ) { if ((*this)[i] && !((*this)[i] = (*this)[i]->cast (itemType))) { delete this; return NULL; } } return Value::cast (type); } #include "Printer.h" void VectorValue::display (const class Printer& printer) const { printer.delimiter ('{')++; for (card_t i = 0;;) { if (myComponents[i]) myComponents[i]->display (printer); if (++i == getSize ()) break; else printer.delimiter (','); } printer--.delimiter ('}'); } #ifdef EXPR_COMPILE # include "StringBuffer.h" # include /** maximum length of a 64-bit index value, plus delimiters */ static const size_t ixlength = 25; void VectorValue::compile (class StringBuffer&) const { assert (false); } void VectorValue::compileInit (const char* name, unsigned indent, class StringBuffer& out) const { /** length of the supplied name string */ size_t length = strlen (name); /** an extended name */ char* ixname = new char[length + ixlength]; memcpy (ixname, name, length); for (card_t i = 0; i < getSize (); ) { snprintf (ixname + length, ixlength, ".a[%u]", i); myComponents[i]->compileInit (ixname, indent, out); if (++i < getSize () && !indent) out.append (", "); } delete[] ixname; } bool VectorValue::compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const { if (!getSize ()) return false; /** length of the supplied name string */ size_t length = strlen (var); /** an extended name */ char* ixname = new char[length + ixlength]; memcpy (ixname, var, length); for (card_t i = getSize (); i--; ) { snprintf (ixname + length, ixlength, ".a[%u]", i); if (myComponents[i]->compileEqual (out, indent, ixname, equal, first, !i)) first = false; } if (!last) out.append (equal ? "&&\n" : "||\n"); delete[] ixname; return true; } unsigned VectorValue::compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const { assert (!equal || last); /** length of the supplied name string */ size_t length = strlen (var); /** an extended name */ char* ixname = new char[length + ixlength]; memcpy (ixname, var, length); /** number of opened parentheses */ unsigned opened = 0; for (card_t i = getSize (); i--; first = false) { snprintf (ixname + length, ixlength, ".a[%u]", i); if (i) { opened += myComponents[i]->compileOrder (out, indent + opened, ixname, less, false, first, false); myComponents[i]->compileEqual (out, indent, ixname, true, first, false); } else opened += myComponents[i]->compileOrder (out, indent + opened, ixname, less, equal, first, true); } out.closeParen (opened); if (!last) out.append ("||\n"); delete[] ixname; return 0; } #endif // EXPR_COMPILE maria-1.3.5/Value/VectorValue.h0000644000175000017500000001142607643253065016461 0ustar msmakelamsmakela// Vector value class -*- c++ -*- #ifndef VECTORVALUE_H_ # define VECTORVALUE_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Value.h" # include "ValueList.h" /** @file VectorValue.h * Array value */ /* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /** Vector value */ class VectorValue : public Value { public: /** Constructor * @param type type of the value */ VectorValue (const class Type& type); private: /** Copy constructor */ VectorValue (const class VectorValue& old); /** Assignment operator */ class VectorValue& operator= (const class VectorValue& old); public: /** Destructor */ ~VectorValue (); /** Virtual copy constructor */ class Value* copy () const { return new class VectorValue (*this); } /** Determine the kind of the value */ enum Kind getKind () const { return vVector; } /** Determine the number of components in the vector */ card_t getSize () const { return myComponents.getSize (); } /** Address a component by index */ const class Value& operator[] (card_t i) const { return *myComponents[i]; } /** Address a component by index */ class Value*& operator[] (card_t i) { return myComponents[i]; } /** Less-than comparison */ bool operator< (const class VectorValue& other) const; /** Equality comparison */ bool operator== (const class VectorValue& other) const; /** Difference operator * @param other value to be substracted from this (may not be less) * @return the difference */ card_t operator- (const class VectorValue& other) const; /** Reset the value to the first value */ void bottom (); /** Reset the value to the last value */ void top (); /** Get the next value * @return false if the value wrapped around; otherwise true */ bool increment (); /** Get the previous value * @return false if the value wrapped around; otherwise true */ bool decrement (); /** Convert the value to another type if possible * @param type type to be casted to * @return the converted value, or NULL */ class Value* cast (const class Type& type); /** Display this object * @param printer The printer object */ void display (const class Printer& printer) const; # ifdef EXPR_COMPILE /** Dump this value in C notation * @param out the output stream */ void compile (class StringBuffer& out) const; /** Generate C assignment statements for initializing this value * @param name name of the lvalue * @param indent indentation level (0=generate a compound statement) * @param out output stream for the generated code */ void compileInit (const char* name, unsigned indent, class StringBuffer& out) const; /** Generate equality or inequality comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param equal type of comparison: true=equality, false=inequality * @param first flag: first component (no indenting) * @param last flag: last component (no expression chaining) * @return true if any code was generated */ bool compileEqual (class StringBuffer& out, unsigned indent, const char* var, bool equal, bool first, bool last) const; /** Generate ordering comparison expression * @param out output stream * @param indent indentation level * @param var C expression to be compared * @param less comparison type: true=less, false=greater * @param equal comparison type: true=equal, false=unequal * @param first flag: first component (no indentation) * @param last flag: last component (no expression chaining) * @return number of parentheses left open */ unsigned compileOrder (class StringBuffer& out, unsigned indent, const char* var, bool less, bool equal, bool first, bool last) const; # endif // EXPR_COMPILE private: /** The components */ class ValueList myComponents; }; #endif // VECTORVALUE_H_ maria-1.3.5/Value/allValues.h0000644000175000017500000000214007643253065016143 0ustar msmakelamsmakela/** @file allValues.h * Header file that includes all classes derived from Value */ /* Copyright © 1999-2001 Marko Mäkelä (msmakela@tcs.hut.fi). This file is part of MARIA, a reachability analyzer and model checker for high-level Petri nets. MARIA 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, or (at your option) any later version. MARIA 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. The GNU General Public License is often shipped with GNU software, and is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include "LeafValue.h" #include "StructValue.h" #include "UnionValue.h" #include "VectorValue.h" #include "BufferValue.h" maria-1.3.5/doc/0000755000175000017500000000000010272511406013522 5ustar msmakelamsmakelamaria-1.3.5/doc/maria.texinfo0000644000175000017500000057707510232532461016236 0ustar msmakelamsmakela\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename maria.info @settitle Maria @set UPDATED 23 April 2005 @set VERSION 1.3.5 @iftex @syncodeindex fn cp @syncodeindex vr cp @syncodeindex tp cp @finalout @end iftex @ifinfo @synindex fn cp @synindex vr cp @synindex tp cp @end ifinfo @dircategory Formal Methods @direntry * Maria: (maria). Reachability Analyzer for Algebraic System Nets @end direntry @c %**end of header @ifinfo This file documents Maria, a reachability analyzer for Algebraic System Nets. This manual documents Maria version @value{VERSION}. Copyright @copyright{} 1998-2000, 2002-2003, 2005 Marko M@"akel@"a. Copyright @copyright{} 2001 Marko M@"akel@"a and Helsinki University of Technology, Laboratory for Theoretical Computer Science. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. @ignore Permission is granted to process this file through TeX and print the results, provided the printed document carries a copying permission notice identical to this one except for the removal of this paragraph (this paragraph not being relevant to the printed manual). @end ignore Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the sections entitled ``Copying'' and ``GNU General Public License'' are included exactly as in the original, and provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that the section entitled ``GNU General Public License'' and this permission notice may be stated in a translation approved by the copyright holder. @end ifinfo @titlepage @title Maria @subtitle Modular Reachability Analyzer for Algebraic System Nets @subtitle @value{UPDATED}, Maria Version @value{VERSION} @author by Marko M@"akel@"a @page @vskip 0pt plus 1filll Copyright @copyright{} 1998-2000, 2002-2003, 2005 Marko M@"akel@"a. Copyright @copyright{} 2001 Marko M@"akel@"a and Helsinki University of Technology, Laboratory for Theoretical Computer Science. @sp 2 Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. @ignore Permission is granted to process this file through TeX and print the results, provided the printed document carries copying permission notice identical to this one except for the removal of this paragraph (this paragraph not being relevant to the printed manual). @end ignore Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the section entitled ``GNU General Public License'' is included exactly as in the original, and provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that the section entitled ``GNU General Public License'' and this permission notice may be included in translations approved by the copyright holder instead of in the original English. @end titlepage @page @node Top, Introduction, (dir), (dir) @ifinfo This manual documents version @value{VERSION} of Maria. @end ifinfo @menu * Introduction:: * Modeling:: The net description language of Maria * Analysis:: Performing reachability analysis with Maria * Algorithms:: Algorithms used in Maria * Grammar:: Grammar of the Maria languages * Graph Files:: Format of the reachability graph files * Compiling:: Compiling Maria * Bugs:: Reporting Bugs * Examples:: Sample Petri Nets for Maria * Copying:: The GNU General Public License says how you can copy and share Maria * Index:: Cross-references to the text. @end menu @node Introduction, Modeling, Top, Top @unnumbered Introduction @dfn{Maria}, or @dfn{Modular Reachability Analyzer}, is a reachability analyzer for Algebraic System Nets. It will generate reachability graphs for Algebraic System Nets, detect deadlocks and check properties expressed using temporal logic formulae. Maria is remotely based on Prod, a reachability analyzer for Proposition/Transition Nets developed earlier at the Laboratory for Theoretical Computer Science. Its data type system and expression syntax are heavily inspired by the C programming language. In order to understand this manual, you should be familiar with the basic concepts of Petri Nets and also have some knowledge in C. Maria was written by Marko M@"akel@"a in a research project at the Helsinki University of Technology in the Laboratory for Theoretical Computer Science. The project is financed by the National Technology Agency of Finland (TEKES), Nokia Research Center, Nokia Networks, the Helsinki Telephone Corporation and the Finnish Rail Administration. Many of the ideas implemented in Maria were brought up in discussions among the laboratory staff. Ideas expressed by Dr.@: Kimmo Varpaaniemi, Dr.@: Nisse Husberg, Keijo Heljanko and Tommi Junttila have influenced the design. @w{Dr.@: Varpaaniemi} sketched the first version of the unification algorithm (@pxref{Unification}), and he helped in debugging by stressing the analyzer with quite obscure examples. Also Simo Blom, who was the first one to use the analyzer for something real, reported some bugs, which have now been fixed. The model-checking functionality (@pxref{Model Checking}) is based on the ideas of Keijo Heljanko and others, and the algorithms were initially implemented by Timo Latvala. This edition corresponds to version @value{VERSION} of Maria. @node Modeling, Analysis, Introduction, Top @chapter The Net Description Language @cindex modeling @cindex nets, composing Petri Nets are often represented as directed bipartite graphs using a graphical notation. An entirely graphical notation only works for relatively simple nets that can be represented on one sheet of paper. We decided to use a purely textual notation, since it avoids many problems, such as creating an optimal graphical layout for an automatically generated Petri Net model and creating a graphical user interface that works flawlessly on various hardware and software platforms. @menu * Design Criteria:: Why the language became what it is now * Lexical Conventions:: The format of numbers, comments etc. * Net Constructs:: * Types:: Defining data types * Functions:: Defining functions or constants * Places:: Declaring Petri Net places * Transitions:: Declaring Petri Net transitions * Subnets:: Declaring Petri Net modules * Verification:: Commands for on-the-fly verification * Data Types:: The data type system * Expressions:: Expressions and formulae in the language * Output Variables:: Non-determinism in transitions * Scoping:: Look-up rules for names @end menu @node Design Criteria, Lexical Conventions, Modeling, Modeling @section Design Criteria As an admirer of the programming languages C and C++, I decided to make the net description language resemble C as closely as possible. Users familiar with C should feel comfortable with the way data types are defined and expressions are written in the net description language. In the following, we will present the grammar of the net description language using regular expressions (@pxref{Patterns, , Patterns, flex, The Flex Manual}) and the Extended Backus@minus{}Naur Form (@pxref{Language and Grammar, , Languages and Context-Free Grammars, bison, The GNU Bison Manual}). @node Lexical Conventions, Net Constructs, Design Criteria, Modeling @section Lexical Conventions @cindex lexical conventions The lexical conventions of the Maria Petri Net description language determine how to format net descriptions in text files, including the mechanisms for embedding explanatory comments. @menu * Formatting:: How net descriptions should be formatted * Comments:: Writing notes for the human reader * Lexical Tokens:: * Reserved Words:: Reserved words in the language * Numeric Constants:: Different ways of presenting numbers * Character Constants:: Single-character constants * Identifiers:: Names for variables, places, transitions etc. * Preprocessor:: Control directives for the preprocessor @end menu @node Formatting, Comments, Lexical Conventions, Lexical Conventions @subsection Formatting The net description language is not sensitive to the presence or absence of white space between language elements provided that all keywords and identifiers are distinguished. Thus the user has the same degree of freedom that C and C++ allow in formatting code. White space includes these characters: space (@samp{' '}), newline (@samp{'\n'}), carriage return (@samp{'\r'}), form feed (@samp{'\f'}), horizontal tabulator (@samp{'\t'}) and vertical tabulator (@samp{'\v'}). @node Comments, Lexical Tokens, Formatting, Lexical Conventions @subsection Comments Comments are indicated as they are in the C++ programming language. Two contiguous slashes (@samp{//}) indicate the start of a comment that continues to the end of the current line. A slash immediately followed by an asterisk (@samp{/*}) indicates a comment that continues until the reverse sequence (@samp{*/}) is encountered. Comments may not be nested, and comments are interpreted only between language elements (e.g., not inside names enclosed in double quotes). @node Lexical Tokens, Preprocessor, Comments, Lexical Conventions @subsection Lexical Tokens Lexical tokens are the atomic constituents of the language, consisting of characters or character sequences. @menu * Reserved Words:: Reserved words in the language * Numeric Constants:: Different ways of presenting numbers * Character Constants:: Single-character constants * Identifiers:: Names for variables, places, transitions etc. @end menu @node Reserved Words, Numeric Constants, Lexical Tokens, Lexical Tokens @subsubsection Reserved Words @cindex reserved words There are quite a few reserved words in the net description language: @multitable @columnfractions .25 .25 .25 .25 @item @code{atom} @tab @code{cardinality} @tab @code{const} @tab @code{deadlock} @item @code{empty} @tab @code{enabled} @tab @code{enum} @tab @code{equals} @item @code{false} @tab @code{fatal} @tab @code{gate} @tab @code{hide} @item @code{id} @tab @code{in} @tab @code{infinite} @tab @code{intersect} @item @code{is} @tab @code{map} @tab @code{max} @tab @code{min} @item @code{minus} @tab @code{out} @tab @code{place} @tab @code{prop} @item @code{queue} @tab @code{reject} @tab @code{release} @tab @code{stack} @item @code{strongly_fair} @tab @code{struct} @tab @code{subnet} @tab @code{subset} @item @code{trans} @tab @code{true} @tab @code{typedef} @tab @code{undefined} @item @code{union} @tab @code{until} @tab @code{weakly_fair} @end multitable @noindent In order to use any of these words as an identifier (@pxref{Identifiers}), you will have to enclose it in double quotation marks (@samp{"}). @node Numeric Constants, Character Constants, Reserved Words, Lexical Tokens @subsubsection Numeric Constants @cindex constants, numeric @cindex numeric constants Maria has three interchangeable ways of entering integer numeric constants. The constants can be entered using one of three different notations: with decimal numbers (@samp{[1-9][0-9]*}), octal numbers (@samp{0[0-7]*}) or hexadecimal numbers (@samp{0x[0-9a-fA-F]+}). When a numeric constant is too long to fit in the internal representation, the lexical analyzer will detect it and issue a diagnostic message. Decimal numbers are always unsigned, but the hexadecimal and octal representations are translated directly to the system-dependent internal representation, which usually is a 32-bit word interpreted as a signed integer using two's complement arithmetic. @node Character Constants, Identifiers, Numeric Constants, Lexical Tokens @subsubsection Character Constants @cindex constants, character @cindex character constants Character constants are just like in the C programming language: a single character enclosed in apostrophes (@samp{'}). The backslash (@samp{\}) is used for entering special characters: @table @samp @item \a alert, bell (@kbd{BEL}) @item \b backspace (@kbd{BS}) @item \t horizontal tabulator (@kbd{HT}) @item \n newline, line feed (@kbd{LF}) @item \v vertical tabulator (@kbd{VT}) @item \f form feed (@kbd{FF}) @item \r carriage return (@kbd{CR}) @item \[0-7]@{1,3@} octal notation @item \x[0-9a-fA-F]@{1,2@} hexadecimal notation @item \@var{c} character @var{c} (@code{@var{c} != '\n'}) @end table @noindent Any other characters than the apostrophe or the backslash can be entered verbatim between the apostrophes. Any non-special character quoted with the backslash will be entered as such, i.e.@: the backslash will be ignored. Thus, @samp{'\c'} is equivalent to @samp{'c'}. The line break character is a special case. In order to maintain consistence with the quoted identifiers discussed below, a backslash followed by a line break and any amount of white space containing no line breaks will be ignored. @node Identifiers, , Character Constants, Lexical Tokens @subsubsection Identifiers @cindex identifiers, syntax of Maria uses textual names for identifying places, transitions, data types, variables, enumeration constants and many other things. None of the identifiers become reserved words. For instance, @samp{bool} may be a type name, a place name or the name of a structure component. Anything of the form @samp{[A-Za-z_][A-Za-z0-9_]*} that is not a reserved word is an identifier. Identifiers can also be enclosed in double quotation marks. As with single-character constants, only the backslash and the quotation mark must be escaped with a backslash, and the backslash notation (@pxref{Character Constants}) can be used for entering non-printable characters. Non-printable characters need not be escaped, though. The only character that is not allowed in identifiers is the @kbd{NUL} character. The backslash character (@samp{\}) can be used to break up long identifiers. A backslash followed by a line break and any amount of white space containing no line breaks will be ignored in the input. Also, backslashes can be used to quote the following character. For instance, @samp{in\ k} is equivalent to @samp{"in k"}. In double quotes, the newline character is just as significant as any other character. Sometimes one wants to split a long quoted identifier to several lines without the line breaks being significant. This can be achieved by putting a backslash immediately before the line break. The lexical analyzer will ignore the backslash, the line break and the immediately following white space (not line break). @node Preprocessor, , Lexical Tokens, Lexical Conventions @subsection Preprocessor Directives @cindex preprocessor The language contains a subset of the directives implemented in the C language preprocessor. Conditional compilation and macro definitions are not supported in the current version. Preprocessor directives are indicated with a number sign (@samp{#}) located in the first (leftmost) column. The number sign may be followed by any amount of lexical comments and other white space than newline. The line, which must be terminated with a newline, must contain exactly one preprocessor directive. @menu * Include:: Embedding other files * Conditions:: Conditional processing * Line:: Setting the line number counter * Comment:: Preprocessor comment @end menu @node Include, Conditions, Preprocessor, Preprocessor @subsubsection Embedding Other Files: @samp{#include} @cindex include files @findex #include The @samp{#include} directive works just like in the C preprocessor, except that the file name must be enclosed in double quotes and never in angle brackets (@samp{<} and @samp{>}). The string in double quotes is interpreted as a quoted identifier (@pxref{Identifier}). @node Conditions, Line, Include, Preprocessor @subsubsection Conditional Processing @cindex conditional processing @cindex preprocessor symbols @findex #ifdef @findex #ifndef @findex #else @findex #endif @findex #undef @findex #define The @samp{#ifdef}, @samp{#ifndef}, @samp{#else} and @samp{#endif} directives work just like in the C preprocessor, expecting an argument of the form @samp{[A-Za-z_][A-Za-z0-9_]*}. Note that there is no @samp{#if} directive and that the @samp{#define} directive only takes one argument, the name of the symbol. The preprocessor symbols are not macros; no macro expansion will take place. Conditional processing can be used to avoid problems with multiple inclusions of a file or to add some parameterization to the net model. Preprocessor symbols can also be defined on the command line. @node Line, Comment, Conditions, Preprocessor @subsubsection Setting the Line Number: @samp{#line} @cindex line counter, setting @findex #line Code generation tools usually generate @samp{#line} directives for excerpts that are to be embedded verbatim in the generated code. This allows the compiler to refer to the relevant input file of the code generator in its diagnostic messages. The Maria languages implement the @samp{#line} directive in order to better support the diagnostics of automatically generated net descriptions. The @samp{line} keyword is followed by a numeric constant and a character string constant indicating the line number and the file name of the following line. @node Comment, , Line, Preprocessor @subsubsection Preprocessor Comment: @samp{#!} @findex #! The special preprocessor directive @samp{#!}, which causes the rest of the line to be ignored, was added in order to make it possible for Maria input files to also be executable scripts in systems having an appropriate @code{exec} system call. @node Net Constructs, Data Types, Lexical Conventions, Modeling @section Constructs for Defining Nets @cindex nets, constructs @menu * Types:: Defining data types * Functions:: Defining functions or constants * Places:: Declaring Petri Net places * Transitions:: Declaring Petri Net transitions * Subnets:: Declaring Petri Net modules * Verification:: Commands for on-the-fly verification @end menu @node Types, Functions, Net Constructs, Net Constructs @subsection Type Definitions: @samp{typedef} @cindex data types, defining @findex typedef In the Maria languages, only the predefined data types @samp{bool}, @samp{int}, @samp{unsigned} and @samp{char} can be used without naming them using the grammatical construct @example type: TYPEDEF typedefinition name @end example @noindent inspired by C. The built-in type names are not reserved words. For instance, any reference to the type @samp{int} following the definition @code{typedef int (-64..63) int;} will refer to an integer representable with 7 bits. For a comprehensive description of the data type system, see @ref{Data Types}. Here we will only present the syntax, not the semantics. Some of the syntax for defining data types resembles the C programming language very closely: @example @group typedefinition: ENUM '@{' enum_item ( delim enum_item )* '@}' | STRUCT '@{' comp_list '@}' | UNION '@{' comp_list '@}' | typereference @end group @group typereference: name enum_item: name [ [ '=' ] number ] comp_list: comp (delim comp)* [ delim ] comp: typedefinition name number: expr delim: ',' | ';' @end group @end example The extra leaf data types include an empty @samp{struct}, often used for denoting black tokens, and an @dfn{identifier} type used for identifying e.g.@: processes or objects. Note that if you intend to compile the model (@pxref{Maria Options}), the empty @samp{struct} does not work on all C compilers. @example @group typedefinition: STRUCT '@{' '@}' | ID '[' number ']' @end group @end example @noindent It is a good idea to define an alias (@pxref{Functions}) for the black token, so that its definition can be changed easily: @example @group typedef struct @{@} token; // typedef unsigned (0) token; token token =