gt:     throw new UnsupportedOperationException();
context: /*
   * xtc - The eXTensible Compiler
   * Copyright (C) 2009-2012 New York University
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * version 2 as published by the Free Software Foundation.
   *
   * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   * USA.
   */
  package xtc.lang.cpp;
  
  import java.lang.StringBuilder;
  
  import java.util.List;
  import java.util.ArrayList;
  import java.util.Map;
  import java.util.HashMap;
  import java.util.Iterator;
  
  import xtc.lang.cpp.Syntax.Kind;
  import xtc.lang.cpp.Syntax.LanguageTag;
  import xtc.lang.cpp.Syntax.PreprocessorTag;
  import xtc.lang.cpp.Syntax.ConditionalTag;
  import xtc.lang.cpp.Syntax.DirectiveTag;
  import xtc.lang.cpp.Syntax.Layout;
  import xtc.lang.cpp.Syntax.Language;
  import xtc.lang.cpp.Syntax.Text;
  import xtc.lang.cpp.Syntax.Directive;
  import xtc.lang.cpp.Syntax.Conditional;
  
  import xtc.tree.Location;
  
  /**
   * Parses directives into compound tokens.
   *
   * @author Paul Gazzillo
   * @version $Revision: 1.17 $
   */
  public class DirectiveParser implements Iterator<Syntax> {
    /** The input stream of tokens. */
    Iterator<Syntax> stream;
      
    /** We are at the beginning of a newline. */
    protected boolean newline;
     
    /** Create a new directive parser stream. */
    public DirectiveParser(Iterator<Syntax> stream, String filename) {
      this.stream = stream;
      this.newline = true;
    }
      
    /**
     * This function parses preprocessor directives.  The directive must
     * occur at the beginning of the new line, which is why we must keep
     * a flag indicating whether this is so.
     *
     * The function returns either the next Yytoken
     * from the lexer or a Directive which the function has parsed.
     *
     * The directive's location is taken from the location of the hash
     * symbol.
     *
     * @return the next token or compound token.
     */
    public Syntax next() {
      Syntax syntax = stream.next();
        
      // Parse the directive.
      if (newline && syntax.kind() == Kind.LANGUAGE
          && syntax.toLanguage().tag().ppTag() == PreprocessorTag.HASH) {
        List<Language<?>> list;
        String directiveName;
        DirectiveTag tag;
        boolean prevWhite = false;  // Flag for preserving whitespace.
        Location location = syntax.getLocation();
          
        list = new ArrayList<Language<?>>();
          
        do { // Skip the whitespace after the #.
          syntax = stream.next();
  
          if (syntax.kind() == Kind.LAYOUT
              && ((Layout) syntax).hasNewline()) {
            break;
  
          } else if (syntax.kind() == Kind.LANGUAGE) {
            break;
          }
        } while (true);
  
        if (syntax.kind() == Kind.LAYOUT && ((Layout) syntax).hasNewline()
            || syntax.kind() == Kind.EOF) {
          // It's an empty line marker.
          Directive empty = new Directive(DirectiveTag.LINEMARKER, list);
          empty.setLocation(location);
  
          return empty;
        }
  
        directiveName = syntax.toLanguage().getTokenText();
  
        if (tagMap.containsKey(directiveName)) {
          tag = tagMap.get(directiveName);
  
        } else if (syntax.toLanguage().tag().ppTag() == PreprocessorTag.NUMBER) {
          tag = DirectiveTag.LINEMARKER;
          list.add(syntax.toLanguage());
        } else {
          tag = DirectiveTag.INVALID;
          list.add(syntax.toLanguage());
        }
  
        do { // Skip the whitespace after the directive name.
          syntax = stream.next();
  
          if (syntax.kind() == Kind.LAYOUT
              && ((Layout) syntax).hasNewline()) {
            break;
  
          } else if (syntax.kind() == Kind.LANGUAGE) {
            break;
          }
        } while (true);
  
        if (syntax.kind() == Kind.LAYOUT && ((Layout) syntax).hasNewline()
            || syntax.kind() == Kind.EOF) {
          // It's an empty directive.
          Directive empty = new Directive(tag, list);
          empty.setLocation(location);
  
          return empty;
        }
  
        list.add(syntax.toLanguage());
  
        do { // Collect the tokens in the directive.
          syntax = stream.next();
  
          if (syntax.kind() == Kind.EOF) {
            // Don't swallow the EOF.
            break;
  
          } else if (syntax.kind() == Kind.LANGUAGE) {
            if (prevWhite) {
              syntax.setFlag(Preprocessor.PREV_WHITE);
              prevWhite = false;
            }
            list.add(syntax.toLanguage());
  
          } else if (syntax.kind() == Kind.LAYOUT
              && ((Layout) syntax).hasNewline()) {
            break;
  
          } else if (syntax.kind() == Kind.LAYOUT) {
            // Set the PREV_WHITE flag when a token is preceded by
            // whitespace.  This is used to preserve spacing in expanded
            // macros.
            if (syntax.getTokenText().length() > 0) {
              prevWhite = true;
            }
          }
        } while (true);
  
        newline = true;
  
        Directive directive = new Directive(tag, list);
        directive.setLocation(location);
  
        return directive;
  
      } else {
        // Check whether there is a newline.
        newline = (syntax.kind() == Kind.LAYOUT)
          && ((Layout) syntax).hasNewline();
  
        return syntax;
      }
    }
      
    public boolean hasNext() {
      return stream.hasNext();
    }
  
    private static final HashMap<String, DirectiveTag> tagMap
      = new HashMap<String, DirectiveTag>();
  
    static {
      tagMap.put("if", DirectiveTag.IF);
      tagMap.put("ifdef", DirectiveTag.IFDEF);
      tagMap.put("ifndef", DirectiveTag.IFNDEF);
      tagMap.put("elif", DirectiveTag.ELIF);
      tagMap.put("else", DirectiveTag.ELSE);
      tagMap.put("endif", DirectiveTag.ENDIF);
      tagMap.put("include", DirectiveTag.INCLUDE);
      tagMap.put("include_next", DirectiveTag.INCLUDE_NEXT);
      tagMap.put("define", DirectiveTag.DEFINE);
      tagMap.put("undef", DirectiveTag.UNDEF);
      tagMap.put("line", DirectiveTag.LINE);
      tagMap.put("error", DirectiveTag.ERROR);
      tagMap.put("warning", DirectiveTag.WARNING);
      tagMap.put("pragma", DirectiveTag.PRAGMA);
    }
  
    public void remove() {
  