/**
   * Annotate the specified node. If any annotations have been recorded and {@link #mark() marked},
   * the specified node is wrapped by those annotations and the outer-most annotation is returned.
   * Otherwise, the specified node is returned.
   *
   * @param node The node.
   * @return The annotated node.
   */
  public Node annotate(Node node) {
    if (DEBUG) System.out.println("annotate(" + node + ")");

    if (null != top.mark) {
      // Find the mark in the next closest context, if it exists.
      Annotation base = null;
      Context c = top.next;
      while (null != c) {
        if (null != c.mark) {
          base = c.mark;
          break;
        }
        c = c.next;
      }

      // Apply the annotations between the base and current mark to
      // the specified node, while also preserving any new
      // annotations.
      Annotation a = (Annotation) top.mark.getNode();
      top.mark.setNode(node);
      if (null == base) {
        node = annotation;
        annotation = a;
      } else {
        node = base.getNode();
        base.setNode(a);
      }
      top.mark = null;
    }

    // Done.
    return node;
  }
  /**
   * Mark the current annotation. This method must be called before recognizing the nonterminals to
   * be annotated. Furthermore, it must be called within the context of a stateful production.
   */
  public void mark() {
    if (DEBUG) System.out.println("mark()");

    if (null == annotation) {
      top.mark = null;
    } else {
      top.mark = annotation.innerMost();
    }
  }
  /**
   * Record a pragma.
   *
   * @see Pragma
   * @param directive The actual directive.
   * @param location The pragma's source location.
   */
  public void pragma(String directive, Location location) {
    if (DEBUG) System.out.println("pragma(" + directive + ")");

    Pragma pragma = new Pragma(directive, null);
    pragma.setLocation(location);
    if (null == annotation) {
      annotation = pragma;
    } else {
      annotation.innerMost().setNode(pragma);
    }
  }
  /**
   * Record an ident directive.
   *
   * @see SourceIdentity
   * @param ident The actual identity marker.
   * @param location The ident directive's source location.
   */
  public void ident(String ident, Location location) {
    if (DEBUG) System.out.println("ident(" + ident + ")");

    SourceIdentity identity = new SourceIdentity(ident, null);
    identity.setLocation(location);
    if (null == annotation) {
      annotation = identity;
    } else {
      annotation.innerMost().setNode(identity);
    }
  }
  /**
   * Record a line marker. Note that string values for the four flags are interpreted as follows:
   * Any non-null string counts for <code>true</code>, while null counts for <code>false</code>.
   *
   * @see LineMarker
   * @param file The file name (without quotes).
   * @param line The line number.
   * @param isStartFile The start file flag.
   * @param isReturnToFile The return to file flag.
   * @param isSystemHeader The system header flag.
   * @param isExternC The extern C flag.
   * @param location The line marker's source location.
   */
  public void lineMarker(
      String file,
      int line,
      String isStartFile,
      String isReturnToFile,
      String isSystemHeader,
      String isExternC,
      Location location) {
    if (DEBUG) System.out.println("lineMarker(" + file + ": " + line + ")");

    int flags = 0;
    if (null != isStartFile) flags |= LineMarker.FLAG_START_FILE;
    if (null != isReturnToFile) flags |= LineMarker.FLAG_RETURN_TO_FILE;
    if (null != isSystemHeader) flags |= LineMarker.FLAG_SYSTEM_HEADER;
    if (null != isExternC) flags |= LineMarker.FLAG_EXTERN_C;

    LineMarker marker = new LineMarker(line, file, flags, null);
    marker.setLocation(location);
    if (null == annotation) {
      annotation = marker;
    } else {
      annotation.innerMost().setNode(marker);
    }
  }