// 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_
