context: /*
   * ProductionPattern.cs
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public License
   * as published by the Free Software Foundation; either version 3
   * of the License, or (at your option) any later version.
   *
   * This library 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
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free
   * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   * MA 02111-1307, USA.
   *
   * Copyright (c) 2003-2005 Per Cederberg. All rights reserved.
   */
  
  using System.Collections;
  using System.Text;
  
  namespace PerCederberg.Grammatica.Runtime {
  
      /**
       * A production pattern. This class represents a set of production
       * alternatives that together forms a single production. A
       * production pattern is identified by an integer id and a name,
       * both provided upon creation. The pattern id is used for
       * referencing the production pattern from production pattern
       * elements.
       *
       * @author   Per Cederberg, <per at percederberg dot net>
       * @version  1.5
       */
      public class ProductionPattern {
  
          /**
           * The production pattern identity.
           */
          private int id;
  
          /**
           * The production pattern name.
           */
          private string name;
  
          /**
           * The synthectic production flag. If this flag is set, the
           * production identified by this pattern has been artificially
           * inserted into the grammar.
           */
          private bool synthetic;
  
          /**
           * The list of production pattern alternatives.
           */
          private ArrayList alternatives;
  
          /**
           * The default production pattern alternative. This alternative
           * is used when no other alternatives match. It may be set to
           * -1, meaning that there is no default (or fallback) alternative.
           */
          private int defaultAlt;
  
          /**
           * The look-ahead set associated with this pattern.
           */
          private LookAheadSet lookAhead;
  
          /**
           * Creates a new production pattern.
           *
           * @param id             the production pattern id
           * @param name           the production pattern name
           */
          public ProductionPattern(int id, string name) {
              id = id;
              name = name;
              synthetic = false;
              alternatives = new ArrayList();
              defaultAlt = -1;
              lookAhead = null;
          }
  
          /**
           * The production pattern identity property (read-only). This
           * property contains the unique identity value.
           *
           * @since 1.5
           */
          public int Id {
              get {
                  return id;
              }
          }
  
          /**
           * Returns the unique production pattern identity value.
           *
           * @return the production pattern id
           *
           * @see #Id
           *
           * @deprecated Use the Id property instead.
           */
          public int GetId() {
              return Id;
          }
  
          /**
           * The production pattern name property (read-only).
           *
           * @since 1.5
           */
          public string Name {
              get {
                  return name;
              }
          }
  
          /**
           * Returns the production pattern name.
           *
           * @return the production pattern name
           *
           * @see #Name
           *
           * @deprecated Use the Name property instead.
           */
          public string GetName() {
              return Name;
          }
  
          /**
           * The synthetic production pattern property. If this property
           * is set, the production identified by this pattern has been
           * artificially inserted into the grammar. No parse tree nodes
           * will be created for such nodes, instead the child nodes
           * will be added directly to the parent node. By default this
           * property is set to false.
           *
           * @since 1.5
           */
          public bool Synthetic {
              get {
                  return synthetic;
              }
              set {
                  synthetic = value;
              }
          }
  
          /**
           * Checks if the synthetic production flag is set. If this
           * flag is set, the production identified by this pattern has
           * been artificially inserted into the grammar. No parse tree
           * nodes will be created for such nodes, instead the child
           * nodes will be added directly to the parent node.
           *
           * @return true if this production pattern is synthetic, or
           *         false otherwise
           *
           * @see #Synthetic
           *
           * @deprecated Use the Synthetic property instead.
           */
          public bool IsSyntetic() {
              return Synthetic;
          }
  
          /**
           * Sets the synthetic production pattern flag. If this flag is set,
           * the production identified by this pattern has been artificially
           * inserted into the grammar. By default this flag is set to
           * false.
           *
           * @param syntetic       the new value of the synthetic flag
           *
           * @see #Synthetic
           *
           * @deprecated Use the Synthetic property instead.
           */
          public void SetSyntetic(bool synthetic) {
              Synthetic = synthetic;
          }
  
          /**
           * The look-ahead set property. This property contains the
           * look-ahead set associated with this alternative.
           */
          internal LookAheadSet LookAhead {
              get {
                  return lookAhead;
              }
              set {
                  lookAhead = value;
              }
          }
  
          /**
           * The default pattern alternative property. The default
           * alternative is used when no other alternative matches. The
           * default alternative must previously have been added to the
           * list of alternatives. This property is set to null if no
           * default pattern alternative has been set.
           */
          internal ProductionPatternAlternative DefaultAlternative {
              get {
                  if (defaultAlt >= 0) {
                      object obj = alternatives[defaultAlt];
                      return (ProductionPatternAlternative) obj;
                  } else {
                      return null;
                  }
              }
              set {
                  defaultAlt = 0;
                  for (int i = 0; i < alternatives.Count; i++) {
                      if (alternatives[i] == value) {
                          defaultAlt = i;
                      }
                  }
              }
          }
  
          /**
           * The production pattern alternative count property
           * (read-only).
           *
           * @since 1.5
           */
          public int Count {
              get {
                  return alternatives.Count;
              }
          }
  
          /**
           * Returns the number of alternatives in this pattern.
           *
           * @return the number of alternatives in this pattern
           *
           * @see #Count
           *
           * @deprecated Use the Count property instead.
           */
          public int GetAlternativeCount() {
              return Count;
          }
  
          /**
           * The production pattern alternative index (read-only).
           *
           * @param index          the alternative index, 0 <= pos < Count
           *
           * @return the alternative found
           *
           * @since 1.5
           */
          public ProductionPatternAlternative this[int index] {
              get {
                  return (ProductionPatternAlternative) alternatives[index];
              }
          }
  
          /**
           * Returns an alternative in this pattern.
           *
           * @param pos            the alternative position, 0 <= pos < count
           *
           * @return the alternative found
           *
           * @deprecated Use the class indexer instead.
           */
          public ProductionPatternAlternative GetAlternative(int pos) {
              return this[pos];
          }
  
          /**
           * Checks if this pattern is recursive on the left-hand side.
           * This method checks if any of the production pattern
           * alternatives is left-recursive.
           *
           * @return true if at least one alternative is left recursive, or
           *         false otherwise
           */
          public bool IsLeftRecursive() {
              ProductionPatternAlternative  alt;
  
              for (int i = 0; i < alternatives.Count; i++) {
                  alt = (ProductionPatternAlternative) alternatives[i];
                  if (alt.IsLeftRecursive()) {
                      return true;
                  }
              }
              return false;
          }
  
          /**
           * Checks if this pattern is recursive on the right-hand side.
           * This method checks if any of the production pattern
           * alternatives is right-recursive.
           *
           * @return true if at least one alternative is right recursive, or
           *         false otherwise
           */
          public bool IsRightRecursive() {
              ProductionPatternAlternative  alt;
  
              for (int i = 0; i < alternatives.Count; i++) {
                  alt = (ProductionPatternAlternative) alternatives[i];
                  if (alt.IsRightRecursive()) {
                      return true;
                  }
              }
              return false;
          }
  
          /**
           * Checks if this pattern would match an empty stream of
           * tokens. This method checks if any one of the production
           * pattern alternatives would match the empty token stream.
           *
           * @return true if at least one alternative match no tokens, or
           *         false otherwise
           */
          public bool IsMatchingEmpty() {
              ProductionPatternAlternative  alt;
  
              for (int i = 0; i < alternatives.Count; i++) {
                  alt = (ProductionPatternAlternative) alternatives[i];
                  if (alt.IsMatchingEmpty()) {
                      return true;
                  }
              }
              return false;
          }
  
          /**
           * Adds a production pattern alternative.
           *
           * @param alt            the production pattern alternative to add
           *
           * @throws ParserCreationException if an identical alternative has
           *             already been added
           */
          public void AddAlternative(ProductionPatternAlternative alt) {
              if (alternatives.Contains(alt)) {
                  throw new ParserCreationException(
                      ParserCreationException.ErrorType.INVALID_PRODUCTION,
                      name,
                      "two identical alternatives exist");
              }
              alt.SetPattern(this);
              alternatives.Add(alt);
          }
  
          /**
           * Returns a string representation of this object.
           *
           * @return a token string representation
           */
          public override string ToString() {
              StringBuilder  buffer = new StringBuilder();
              StringBuilder  indent = new StringBuilder();
              int            i;
  
              buffer.Append(name);
              buffer.Append("(");
              buffer.Append(id);
              buffer.Append(") ");
              for (i = 0; i < buffer.Length; i++) {
                  indent.Append(" ");
              }
              for (i = 0; i < alternatives.Count; i++) {
  
gt:                 if (i == 0) {