www.pudn.com > cppcc.rar > ebnf_la_node.hh


/*
 *  File:       ebnf_la_node.hh
 *              $Id: ebnf_la_node.hh,v 1.11 2002/06/26 20:46:29 alec Exp $
 *
 *  Author:     Alec Panovici (alecu@email.com)
 * 
 *  Comments:
 *
 *  Revision history:
 *
 *  $Log: ebnf_la_node.hh,v $
 *  Revision 1.11  2002/06/26 20:46:29  alec
 *  g++ 3.x happy
 *
 *  Revision 1.10  2002/06/23 23:31:59  alec
 *  la-time usercode (force)
 *
 *  Revision 1.9  2002/06/13 11:36:52  alec
 *  added #line stuff
 *
 *  Revision 1.8  2002/06/05 21:32:43  alec
 *  g++ happy
 *
 *  Revision 1.7  2002/05/31 12:11:08  alec
 *  *** empty log message ***
 *
 *  Revision 1.6  2002/05/27 03:00:00  alec
 *  doc update
 *
 *  Revision 1.5  2002/05/22 01:36:19  alec
 *  LOOKAHEAD fixes
 *
 *  Revision 1.4  2002/05/16 21:34:35  alec
 *  parser generation done
 *
 *  Revision 1.3  2002/05/10 18:07:58  alec
 *  *** empty log message ***
 *
 *  Revision 1.2  2002/05/10 07:15:10  alec
 *  parser parse tree ok
 *
 *  Revision 1.1  2002/05/08 18:17:22  alec
 *  *** empty log message ***
 *
 */


/*
  Copyright (C) 2002 Alexandru Panoviciu (alecu@email.com)

  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 __EBNF_LA_NODE_HH__
#define __EBNF_LA_NODE_HH__

#include 
#include 
using namespace std;

#include "ebnf_node.hh"
#include "vbitset.hh"
#include "numbered_la_spec.hh"
#include "catch_clause.hh"

class TokenDesc;
class ITokenSpec;

/**
 * This class adds to the EbnfNode the stuff needed for generating a LA
 * parser.
 */
class EbnfLaNode : public EbnfNode
{

public:

  /**
   * Creates a new EbnfLaNode associated with the given position in the input
   * file and having the associated (possibly NULL) lookahead specification.
   */
  EbnfLaNode (const Position &pos_, NumberedLaSpec *laSpec_ = NULL) :
    EbnfNode(pos_), laSpec(laSpec_)
  {}

  /**
   * Copy constructor. It has an in-depth semantics (the lookahead spec, if
   * any is cloned).
   */
  EbnfLaNode (const EbnfLaNode &o) :
    EbnfNode(o.getPos()),
    laSpec(o.laSpec != NULL ? dynamic_cast(o.laSpec->clone())
           : NULL),
    first(o.first), follow(o.follow), nullable(o.nullable),
    startCode(o.startCode), endCode(o.endCode),
    forceStartCode(o.forceStartCode), forceEndCode(o.forceEndCode),
    catchList(o.catchList), colour(o.colour)
  {}

  ~EbnfLaNode ()
  {
    if (laSpec != NULL) delete laSpec;
  }

#ifdef DEBUG
protected:

  static int indent_level;

  static void indent()
  {
    indent_level++;
  }

  static void unindent ()
  {
    indent_level--;
  }

  static ostream& format (ostream &os)
  {
    for (int i = 0; i < indent_level; i++)
      os << " ";
    return os;
  }
  void dumpAttributes (ostream &os) const;

public:
  
  static ITokenSpec *tokens;
#endif

public:

  /**
   * The lookahead associated with this node, if any (can be NULL).
   */
  NumberedLaSpec *laSpec;

  /**
   * Contains the user code found before the expansion represented by this
   * node in the input file.
   */
  CodeChunk startCode;

  /**
   * Contains the user code found after the expansion represented by this node
  in the input file.
  */
  CodeChunk endCode;

  bool forceStartCode, forceEndCode;

  /**
   * Contains any CatchClause objects resulted from the catch constructions
   * found in the input file after the production represented by this node.
   */
  vector catchList;

  /**
   * Contains the FIRST set of terminals for this node.
   *
   * \sa EbnfFirstCompAlgo
   */
  vBitset first;

  /**
   * Contains the FOLLOW set of terminals for this node.
   *
   * \sa EbnfFollowCompAlgo
   */
  vBitset follow;

  /**
   * Indicates whether the expansion represented by this node can match an
   * empty string of tokens.
   *
   * \sa EbnfNullableCompAlgo
   */
  bool nullable;

  /**
   * During the recursive traversal we use colours to mark visited nodes.
   */
  typedef enum { white, grey, black } Colours;

  /**
   * This field is used during recursive traversal of EBNF nodes, which may
   * reffer to each other. Their meanings are the classical: white : not
   * visited yet, grey : being visited now, black: already visited. This field
   * can be (and is) used by the EbnfNodeAlgo implementations in order to
   * avoid infinite recursion if some productions mutually refer each other.
   */
  Colours colour;
};


/**
 * Represents an expansion obtained by applying the "|" operator to two
 * other expansions.
 */
class EbnfOrNode : public EbnfLaNode
{
public:
  
  EbnfOrNode (EbnfLaNode *pre_, EbnfLaNode *post_,
              const Position &pos_) :
    EbnfLaNode(pos_),
    pre(pre_), post(post_)
  {}

  EbnfOrNode (const EbnfOrNode &o) :
    EbnfLaNode(o),
    pre(dynamic_cast(o.pre->clone())),
    post(dynamic_cast(o.post->clone()))
  {}
    
  virtual EbnfNode& operator [] (int index)
  {
    ASSERT((0 <= index) && (index <= 1),
           "Bad index in EbnfOrNode::operator []");
    return index ? *post : *pre;
  }
  
  virtual EbnfNode* clone ()
  {
    return new EbnfOrNode(*this);
  }

  virtual int getChildCount ()
  {
    return 2;
  }
  
  virtual ~EbnfOrNode ()
  {
    delete pre;
    delete post;
  }
  
#ifdef DEBUG

  virtual void dump (ostream &os) const;
  
#endif

public:

  /**
   * The left operand of the "|" operator in textual order.
   */
  EbnfLaNode *pre;

  /**
   * The right operand of the "|" operator in textual order.
   */
  EbnfLaNode *post;
};


/**
 * Represents an expansion obtained from the concatenation of two other
 * expansions.
 */
class EbnfCatNode : public EbnfLaNode
{
public:
  
  EbnfCatNode (EbnfLaNode *pre_, EbnfLaNode *post_,
              const Position &pos_) :
    EbnfLaNode(pos_),
    pre(pre_), post(post_)
  {}

  EbnfCatNode (const EbnfCatNode &o) :
    EbnfLaNode(o),
    pre(dynamic_cast(o.pre->clone())),
    post(dynamic_cast(o.post->clone()))
  {}

  virtual EbnfNode& operator [] (int index)
  {
    ASSERT((0 <= index) && (index <= 1),
           "Bad index in EbnfCatNode::operator []");
    return index ? *post : *pre;
  }

  virtual int getChildCount ()
  {
    return 2;
  }
  
  virtual EbnfNode* clone ()
  {
    return new EbnfCatNode(*this);
  }

  virtual ~EbnfCatNode ()
  {
    delete pre;
    delete post;
  }

#ifdef DEBUG

  virtual void dump (ostream &os) const;
  
#endif

public:

  /**
   * The first part of the concatenation, in textual order.
   */
  EbnfLaNode *pre;

  /**
   * the second part of the concatenation, in textual order.
   */
  EbnfLaNode *post;
};


/**
 * Represents an expansion obtained by applying the "*"operator to a nother
 * expansion.
 */
class EbnfStarNode : public EbnfLaNode
{
public:
  
  EbnfStarNode (EbnfLaNode *in_,
                const Position &pos_) :
    EbnfLaNode(pos_),
    in(in_)
  {}

  EbnfStarNode (const EbnfStarNode &o) :
    EbnfLaNode(o),
    in(dynamic_cast(o.in->clone()))
  {}

  virtual EbnfNode& operator [] (int index)
  {
    ASSERT((0 == index),
           "Bad index in EbnfStarNode::operator []");
    return *in;
  }

  virtual int getChildCount ()
  {
    return 1;
  }
  
  virtual EbnfNode* clone ()
  {
    return new EbnfStarNode(*this);
  }

  virtual ~EbnfStarNode ()
  {
    delete in;
  }

  
#ifdef DEBUG

  virtual void dump (ostream &os) const;
  
#endif

public:

  /**
   * The operand expansion to which we apply the "*" operator.
   */
  EbnfLaNode *in;
};


/**
 * Represents an expansion that matches whatever another production does.
 */
class EbnfNonterminalNode : public EbnfLaNode
{
public:
  
  EbnfNonterminalNode (const string &targetVar_, const Position &targetVarPos_,
                       const string &nontermName_,
                       const string &actualArgs_, const Position &argsPos_,
                       const Position &pos_) :
    EbnfLaNode(pos_),
    targetVar(targetVarPos_, targetVar_),
    nontermName(nontermName_), actualArgs(argsPos_, actualArgs_)
  {}

  EbnfNonterminalNode (const EbnfNonterminalNode &o) :
    EbnfLaNode(o),
    targetVar(o.targetVar), nontermName(o.nontermName),
    actualArgs(o.actualArgs)
  {}

  virtual EbnfNode& operator [] (int index)
  {
    ASSERT(0, "EbnfNonterminalNode::operator [] called !");
    return * (EbnfNode*) NULL;
  }

  virtual int getChildCount ()
  {
    return 0;
  }
  
  virtual EbnfNode* clone ()
  {
    return new EbnfNonterminalNode(*this);
  }

#ifdef DEBUG

  virtual void dump (ostream &os) const;
  
#endif

public:

  /**
   * If the result of calling the production's method should be stored in a
   * variable, this field contains the name of that variable, otherwise it
   * contains an empty string.
  */
  CodeChunk targetVar;

  /**
   * The name of the production to call.
   */
  string nontermName;

  /**
   * A string containing the C++ list of actual arguments to be passed to the
   * called production.
   */
  CodeChunk actualArgs;

  /**
   * Whis will point to the reffered production's expansion after fixup. BE
   * careful with this as it is possible to be NULL, if the production that is
   * refferred has no expansion (eg. pure code productions).
   */
  EbnfLaNode *nonterm;
};


/**
 * Represents an expansion that matches exactly one terminal.
 */
class EbnfTerminalNode : public EbnfLaNode
{
public:
  
  EbnfTerminalNode (TokenDesc &terminal_,
                    const Position &pos_) :
    EbnfLaNode(pos_),
    terminal(terminal_)
  {}

  EbnfTerminalNode (const EbnfTerminalNode &o) :
    EbnfLaNode(o),
    terminal(o.terminal)
  {}

  
  virtual EbnfNode& operator [] (int index)
  {
    ASSERT(0, "EbnfTerminalNode::operator [] called !");
    return * (EbnfNode*) NULL;
  }

  virtual int getChildCount ()
  {
    return 0;
  }
  
  virtual EbnfNode* clone ()
  {
    return new EbnfTerminalNode(*this);
  }

#ifdef DEBUG

  virtual void dump (ostream &os) const;
  
#endif

public:

  /**
   * Points to the TokenDesc object that describes the token matched by this
   * expansion.
   */
  TokenDesc &terminal;
};


/**
 * Represents an expansion that matches nothing.
 */
class EbnfLambdaNode : public EbnfLaNode
{
public:
  
  EbnfLambdaNode (const Position &pos_) :
    EbnfLaNode(pos_)
  {}

  EbnfLambdaNode (const EbnfLambdaNode &o) :
    EbnfLaNode(o)
  {}

  virtual EbnfNode& operator [] (int index)
  {
    ASSERT(0, "EbnfLambdaNode::operator [] called !");
    return *(EbnfNode*) NULL;
  }

  virtual int getChildCount ()
  {
    return 0;
  }
  
  virtual EbnfNode* clone ()
  {
    return new EbnfLambdaNode(*this);
  }

#ifdef DEBUG

  virtual void dump (ostream &os) const;
  
#endif

};


#endif /* #ifndef __EBNF_LA_NODE_HH__ */