alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Preprocessor.java)

This example Java source code file (Preprocessor.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

binaryexpr, boolean, expression, file, includeentry, interfaceentry, ioexception, math, parseexception, pragmahandler, since, string, symtabentry, token, util, vector

The Preprocessor.java Java example source code

/*
 * Copyright (c) 1999, 2000, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
/*
 * COMPONENT_NAME: idl.parser
 *
 * ORIGINS: 27
 *
 * Licensed Materials - Property of IBM
 * 5639-D57 (C) COPYRIGHT International Business Machines Corp. 1997, 1999
 * RMI-IIOP v1.0
 *
 */

package com.sun.tools.corba.se.idl;

// NOTES:
// -D57110<daz> Allow ID pragma directive to be applied to modules and update
//  feature in accordance to CORBA 2.3.
// -D59165<daz> Enable escaped identifiers when processing pragmas.
// -f60858.1<daz> Support -corba option, level = 2.2: Accept identifiers that
//  collide with keywords, in letter but not case, and issue a warning.
// -d62023 <daz> support -noWarn option; suppress inappropriate warnings when
//  parsing IBM-specific pragmas (#meta <interface_name> abstract).

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Stack;
import java.util.Vector;

import com.sun.tools.corba.se.idl.RepositoryID;

import com.sun.tools.corba.se.idl.constExpr.*;

/**
 * This class should be extended if new pragmas are desired.  If the
 * preprocessor encounters a pragma name which it doesn't recognize
 * (anything other than ID, prefix, or version), it calls the method
 * otherPragmas.  This is the only method which need be overridden.
 * The Preprocessor base class has a number of utility-like methods
 * which can be used by the overridden otherPragmas method.
 **/
public class Preprocessor
{
  /**
   * Public zero-argument constructor.
   **/
  Preprocessor ()
  {
  } // ctor

  /**
   *
   **/
  void init (Parser p)
  {
    parser  = p;
    symbols = p.symbols;
    macros  = p.macros;
  } // init

  /**
   *
   **/
  protected Object clone ()
  {
    return new Preprocessor ();
  } // clone

  /**
   *
   **/
  Token process (Token t) throws IOException, ParseException
  {
    token   = t;
    scanner = parser.scanner;
    // <f46082.40> Deactivate escaped identifier processing in Scanner while
    // preprocessing.
    //scanner.underscoreOK = true;
    scanner.escapedOK = false;
    try
    {
      switch (token.type)
      {
        case Token.Include:
          include ();
          break;
        case Token.If:
          ifClause ();
          break;
        case Token.Ifdef:
          ifdef (false);
          break;
        case Token.Ifndef:
          ifdef (true);
          break;
        case Token.Else:
          if (alreadyProcessedABranch.empty ())
            throw ParseException.elseNoIf (scanner);
          else if (((Boolean)alreadyProcessedABranch.peek ()).booleanValue ())
            skipToEndif ();
          else
          {
            alreadyProcessedABranch.pop ();
            alreadyProcessedABranch.push (new Boolean (true));
            token = scanner.getToken ();
          }
          break;
        case Token.Elif:
          elif ();
          break;
        case Token.Endif:
          if (alreadyProcessedABranch.empty ())
            throw ParseException.endNoIf (scanner);
          else
          {
            alreadyProcessedABranch.pop ();
            token = scanner.getToken ();
            break;
          }
        case Token.Define:
          define ();
          break;
        case Token.Undef:
          undefine ();
          break;
        case Token.Pragma:
          pragma ();
          break;
        case Token.Unknown:
          if (!parser.noWarn)
            ParseException.warning (scanner, Util.getMessage ("Preprocessor.unknown", token.name));
        case Token.Error:
        case Token.Line:
        case Token.Null:
          // ignore
        default:
          scanner.skipLineComment ();
          token = scanner.getToken ();
      }
    }
    catch (IOException e)
    {
      // <f46082.40> Underscore may now precede any identifier, so underscoreOK
      // is vestigal.  The Preprocessor must reset escapedOK so that Scanner
      // will process escaped identifiers according to specification.
      //scanner.underscoreOK = false;
      scanner.escapedOK = true;
      throw e;
    }
    catch (ParseException e)
    {
      // <f46082.40> See above.
      //scanner.underscoreOK = false;
      scanner.escapedOK = true;
      throw e;
    }
    // <f46082.40> See above.
    //scanner.underscoreOK = false;
    scanner.escapedOK = true;
    return token;
  } // process

  /**
   *
   **/
  private void include () throws IOException, ParseException
  {
    match (Token.Include);
    IncludeEntry include = parser.stFactory.includeEntry (parser.currentModule);
    include.sourceFile (scanner.fileEntry ());
    scanner.fileEntry ().addInclude (include);
    if (token.type == Token.StringLiteral)
      include2 (include);
    else if (token.type == Token.LessThan)
      include3 (include);
    else
    {
      int[] expected = {Token.StringLiteral, Token.LessThan};
      throw ParseException.syntaxError (scanner, expected, token.type);
    }
    if (parser.currentModule instanceof ModuleEntry)
      ((ModuleEntry)parser.currentModule).addContained (include);
    else if (parser.currentModule instanceof InterfaceEntry)
      ((InterfaceEntry)parser.currentModule).addContained (include);
  } // include

  /**
   *
   **/
  private void include2 (IncludeEntry include) throws IOException, ParseException
  {
    include.name ('"' + token.name + '"');
    include4 (include, token.name);
    match (Token.StringLiteral);
  } // include2

  /**
   *
   **/
  private void include3 (IncludeEntry include) throws IOException, ParseException
  {
    if (token.type != Token.LessThan)
      // match will throw an exception
      match (Token.LessThan);
    else
    {
      try
      {
        String includeFile = getUntil ('>');
        token = scanner.getToken ();
        include.name ('<' + includeFile + '>');
        include4 (include, includeFile);
        match (Token.GreaterThan);
      }
      catch (IOException e)
      {
        throw ParseException.syntaxError (scanner, ">", "EOF");
      }
    }
  } // include3

  /**
   *
   **/
  private void include4 (IncludeEntry include, String filename) throws IOException, ParseException
  {
    try
    {
      // If the #include is at the global scope, it is treated as
      // an import statement.  If it is within some other scope, it
      // is treated as a normal #include.
      boolean includeIsImport = parser.currentModule == parser.topLevelModule;
      //daz
      include.absFilename (Util.getAbsolutePath (filename, parser.paths));
      scanner.scanIncludedFile (include, getFilename (filename), includeIsImport);
    }
    catch (IOException e)
    {
      ParseException.generic (scanner, e.toString ());
    }
  } // include4

  /**
   *
   **/
  private void define () throws IOException, ParseException
  {
    match (Token.Define);
    if (token.equals (Token.Identifier))
    {
      String symbol = scanner.getStringToEOL ();
      symbols.put (token.name, symbol.trim ());
      match (Token.Identifier);
    }
    else if (token.equals (Token.MacroIdentifier))
    {
      symbols.put (token.name, '(' + scanner.getStringToEOL () . trim ());
      macros.addElement (token.name);
      match (Token.MacroIdentifier);
    }
    else
      throw ParseException.syntaxError (scanner, Token.Identifier, token.type);
  } // define

  /**
   *
   **/
  private void undefine () throws IOException, ParseException
  {
    match (Token.Undef);
    if (token.equals (Token.Identifier))
    {
      symbols.remove (token.name);
      macros.removeElement (token.name);
      match (Token.Identifier);
    }
    else
      throw ParseException.syntaxError (scanner, Token.Identifier, token.type);
  } // undefine

  /**
   *
   **/
  private void ifClause () throws IOException, ParseException
  {
    match (Token.If);
    constExpr ();
  } // ifClause

  /**
   *
   **/
  private void constExpr () throws IOException, ParseException
  {
    SymtabEntry dummyEntry = new SymtabEntry (parser.currentModule);
    dummyEntry.container (parser.currentModule);
    parser.parsingConditionalExpr = true;
    Expression boolExpr = booleanConstExpr (dummyEntry);
    parser.parsingConditionalExpr = false;
    boolean expr;
    if (boolExpr.value () instanceof Boolean)
      expr = ((Boolean)boolExpr.value ()).booleanValue ();
    else
      expr = ((Number)boolExpr.value ()).longValue () != 0;
    alreadyProcessedABranch.push (new Boolean (expr));
    if (!expr)
      skipToEndiforElse ();
  } // constExpr

  /**
   *
   **/
  Expression booleanConstExpr (SymtabEntry entry) throws IOException, ParseException
  {
    Expression expr = orExpr (null, entry);
    try
    {
      expr.evaluate ();
    }
    catch (EvaluationException e)
    {
      ParseException.evaluationError (scanner, e.toString ());
    }
    return expr;
  } // booleanConstExpr

  /**
   *
   **/
  private Expression orExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
  {
    if (e == null)
      e = andExpr (null, entry);
    else
    {
      BinaryExpr b = (BinaryExpr)e;
      b.right (andExpr (null, entry));
      e.rep (e.rep () + b.right ().rep ());
    }
    if (token.equals (Token.DoubleBar))
    {
      match (token.type);
      BooleanOr or = parser.exprFactory.booleanOr (e, null);
      or.rep (e.rep () + " || ");
      return orExpr (or, entry);
    }
    else
      return e;
  } // orExpr

  /**
   *
   **/
  private Expression andExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
  {
    if (e == null)
      e = notExpr (entry);
    else
    {
      BinaryExpr b = (BinaryExpr)e;
      b.right (notExpr (entry));
      e.rep (e.rep () + b.right ().rep ());
    }
    if (token.equals (Token.DoubleAmpersand))
    {
      match (token.type);
      BooleanAnd and = parser.exprFactory.booleanAnd (e, null);
      and.rep (e.rep () + " && ");
      return andExpr (and, entry);
    }
    else
      return e;
  } // andExpr

  /**
   *
   **/
  private Expression notExpr (/*boolean alreadySawExclamation, */SymtabEntry entry) throws IOException, ParseException
  {
    Expression e;
    if (token.equals (Token.Exclamation))
    {
      match (Token.Exclamation);
      e = parser.exprFactory.booleanNot (definedExpr (entry));
      e.rep ("!" + ((BooleanNot)e).operand ().rep ());
    }
    else
      e = definedExpr (entry);
    return e;
  } // notExpr

  /**
   *
   **/
  private Expression definedExpr (SymtabEntry entry) throws IOException, ParseException
  {
    if (token.equals (Token.Identifier) && token.name.equals ("defined"))
      match (Token.Identifier);
    return equalityExpr (null, entry);
  } // definedExpr

  /**
   *
   **/
  private Expression equalityExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
  {
    if (e == null)
    {
      parser.token = token; // Since parser to parse, give it this token
      e = parser.constExp (entry);
      token = parser.token; // Since parser last parsed, get its token
    }
    else
    {
      BinaryExpr b = (BinaryExpr)e;
      parser.token = token; // Since parser to parse, give it this token
      Expression constExpr = parser.constExp (entry);
      token = parser.token; // Since parser last parsed, get its token
      b.right (constExpr);
      e.rep (e.rep () + b.right ().rep ());
    }
    if (token.equals (Token.DoubleEqual))
    {
      match (token.type);
      Equal eq = parser.exprFactory.equal (e, null);
      eq.rep (e.rep () + " == ");
      return equalityExpr (eq, entry);
    }
    else if (token.equals (Token.NotEqual))
    {
      match (token.type);
      NotEqual n = parser.exprFactory.notEqual (e, null);
      n.rep (e.rep () + " != ");
      return equalityExpr (n, entry);
    }
    else if (token.equals (Token.GreaterThan))
    {
      match (token.type);
      GreaterThan g = parser.exprFactory.greaterThan (e, null);
      g.rep (e.rep () + " > ");
      return equalityExpr (g, entry);
    }
    else if (token.equals (Token.GreaterEqual))
    {
      match (token.type);
      GreaterEqual g = parser.exprFactory.greaterEqual (e, null);
      g.rep (e.rep () + " >= ");
      return equalityExpr (g, entry);
    }
    else if (token.equals (Token.LessThan))
    {
      match (token.type);
      LessThan l = parser.exprFactory.lessThan (e, null);
      l.rep (e.rep () + " < ");
      return equalityExpr (l, entry);
    }
    else if (token.equals (Token.LessEqual))
    {
      match (token.type);
      LessEqual l = parser.exprFactory.lessEqual (e, null);
      l.rep (e.rep () + " <= ");
      return equalityExpr (l, entry);
    }
    else
      return e;
  } // equalityExpr

  /**
   *
   **/
  Expression primaryExpr (SymtabEntry entry) throws IOException, ParseException
  {
    Expression primary = null;
    switch (token.type)
    {
      case Token.Identifier:
        // If an identifier gets this far, it means that no
        // preprocessor variable was defined with that name.
        // Generate a FALSE boolean expr.
        //daz        primary = parser.exprFactory.terminal ("0", new Long (0));
        primary = parser.exprFactory.terminal ("0", BigInteger.valueOf (0));
        token = scanner.getToken ();
        break;
      case Token.BooleanLiteral:
      case Token.CharacterLiteral:
      case Token.IntegerLiteral:
      case Token.FloatingPointLiteral:
      case Token.StringLiteral:
        //daz        primary = parser.literal ();
        primary = parser.literal (entry);
        token = parser.token;
        break;
      case Token.LeftParen:
        match (Token.LeftParen);
        primary = booleanConstExpr (entry);
        match (Token.RightParen);
        primary.rep ('(' + primary.rep () + ')');
        break;
      default:
        int[] expected = {Token.Literal, Token.LeftParen};
        throw ParseException.syntaxError (scanner, expected, token.type);
    }
    return primary;
  } // primaryExpr

  /**
   *
   **/
  private void ifDefine (boolean inParens, boolean not) throws IOException, ParseException
  {
    if (token.equals (Token.Identifier))
      if ((not && symbols.containsKey (token.name)) || (!not && !symbols.containsKey (token.name)))
      {
        alreadyProcessedABranch.push (new Boolean (false));
        skipToEndiforElse ();
      }
      else
      {
        alreadyProcessedABranch.push (new Boolean (true));
        match (Token.Identifier);
        if (inParens)
          match (Token.RightParen);
      }
    else
      throw ParseException.syntaxError (scanner, Token.Identifier, token.type);
  } // ifDefine

  /**
   *
   **/
  private void ifdef (boolean not) throws IOException, ParseException
  {
    if (not)
      match (Token.Ifndef);
    else
      match (Token.Ifdef);
    if (token.equals (Token.Identifier))
      if ((not && symbols.containsKey (token.name)) || (!not && !symbols.containsKey (token.name)))
      {
        alreadyProcessedABranch.push (new Boolean (false));
        skipToEndiforElse ();
      }
      else
      {
        alreadyProcessedABranch.push (new Boolean (true));
        match (Token.Identifier);
      }
    else
      throw ParseException.syntaxError (scanner, Token.Identifier, token.type);
  } // ifdef

  /**
   *
   **/
  private void elif () throws IOException, ParseException
  {
    if (alreadyProcessedABranch.empty ())
      throw ParseException.elseNoIf (scanner);
    else if (((Boolean)alreadyProcessedABranch.peek ()).booleanValue ())
      skipToEndif ();
    else
    {
      match (Token.Elif);
      constExpr ();
    }
  } // elif

  /**
   *
   **/
  private void skipToEndiforElse () throws IOException, ParseException
  {
    while (!token.equals (Token.Endif) && !token.equals (Token.Else) && !token.equals (Token.Elif))
    {
      if (token.equals (Token.Ifdef) || token.equals (Token.Ifndef))
      {
        alreadyProcessedABranch.push (new Boolean (true));
        skipToEndif ();
      }
      else
        token = scanner.skipUntil ('#');
    }
    process (token);
  } // skipToEndiforElse

  /**
   *
   **/
  private void skipToEndif () throws IOException, ParseException
  {
    while (!token.equals (Token.Endif))
    {
      token = scanner.skipUntil ('#');
      if (token.equals (Token.Ifdef) || token.equals (Token.Ifndef))
      {
        alreadyProcessedABranch.push (new Boolean (true));
        skipToEndif ();
      }
    }
    alreadyProcessedABranch.pop ();
    match (Token.Endif);
  } // skipToEndif

  ///////////////
  // For Pragma

  /**
   *
   **/
  private void pragma () throws IOException, ParseException
  {
    match (Token.Pragma);
    String pragmaType = token.name;

    // <d59165> Enable escaped identifiers while processing pragma internals.
    // Don't enable until scanning pragma name!
    scanner.escapedOK = true;
    match (Token.Identifier);

    // Add pragma entry to container
    PragmaEntry pragmaEntry = parser.stFactory.pragmaEntry (parser.currentModule);
    pragmaEntry.name (pragmaType);
    pragmaEntry.sourceFile (scanner.fileEntry ());
    pragmaEntry.data (scanner.currentLine ());
    if (parser.currentModule instanceof ModuleEntry)
      ((ModuleEntry)parser.currentModule).addContained (pragmaEntry);
    else if (parser.currentModule instanceof InterfaceEntry)
      ((InterfaceEntry)parser.currentModule).addContained (pragmaEntry);

    // If the token was an identifier, then pragmaType WILL be non-null.
    if (pragmaType.equals ("ID"))
      idPragma ();
    else if (pragmaType.equals ("prefix"))
      prefixPragma ();
    else if (pragmaType.equals ("version"))
      versionPragma ();

    // we are adding extensions to the Sun's idlj compiler to
    // handle correct code generation for local Objects, where
    // the OMG is taking a long time to formalize stuff.  Good
    // example of this is poa.idl.  Two proprietory pragmas
    // sun_local and sun_localservant are defined.  sun_local
    // generates only Holder and Helper classes, where read
    // and write methods throw marshal exceptions.  sun_localservant
    // is to generate Helper, Holder, and only Skel with _invoke
    // throwing an exception, since it does not make sense for
    // local objects.

    else if (pragmaType.equals ("sun_local"))
      localPragma();
    else if (pragmaType.equals ("sun_localservant"))
      localServantPragma();
    else
    {
      otherPragmas (pragmaType, tokenToString ());
      token = scanner.getToken ();
    }

    scanner.escapedOK = false; // <d59165> Disable escaped identifiers.
  } // pragma

  // <d57110> Pragma ID can be appiled to modules and it is an error to
  // name a type in more than one ID pragma directive.

  private Vector PragmaIDs = new Vector ();

  private void localPragma () throws IOException, ParseException
  {
    // Before I can use a parser method, I must make sure it has the current token.
    parser.token = token;
    // this makes sense only for interfaces, if specified for modules,
    // parser should throw an error
    SymtabEntry anErrorOccurred = new SymtabEntry ();
    SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred);
    // Was the indicated type found in the symbol table?
    if (entry == anErrorOccurred)
    {
        System.out.println("Error occured ");
      // Don't have to generate an error, scopedName already has.
      scanner.skipLineComment ();
      token = scanner.getToken ();
    }
    else
    {
      // by this time we have already parsed the ModuleName and the
      // pragma type, therefore setInterfaceType
      if (entry instanceof InterfaceEntry) {
          InterfaceEntry ent = (InterfaceEntry) entry;
          ent.setInterfaceType (InterfaceEntry.LOCAL_SIGNATURE_ONLY);
      }
      token = parser.token;
      String string = token.name;
      match (Token.StringLiteral);
      // for non-interfaces it doesn't make sense, so just ignore it
    }
  } // localPragma

  private void localServantPragma () throws IOException, ParseException
  {
    // Before I can use a parser method, I must make sure it has the current token.
    parser.token = token;
    // this makes sense only for interfaces, if specified for modules,
    // parser should throw an error
    SymtabEntry anErrorOccurred = new SymtabEntry ();
    SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred);

    // Was the indicated type found in the symbol table?
    if (entry == anErrorOccurred)
    {
      // Don't have to generate an error, scopedName already has.
      scanner.skipLineComment ();
      token = scanner.getToken ();
        System.out.println("Error occured ");
    }
    else
    {
      // by this time we have already parsed the ModuleName and the
      // pragma type, therefore setInterfaceType
      if (entry instanceof InterfaceEntry) {
          InterfaceEntry ent = (InterfaceEntry) entry;
          ent.setInterfaceType (InterfaceEntry.LOCALSERVANT);
      }
      token = parser.token;
      String string = token.name;
      match (Token.StringLiteral);
      // for non-interfaces it doesn't make sense, so just ignore it
    }
  } // localServantPragma


  /**
   *
   **/
  private void idPragma () throws IOException, ParseException
  {
    // Before I can use a parser method, I must make sure it has the current token.
    parser.token = token;

    // <d57110> This flag will relax the restriction that the scopedNamed
    // in this ID pragma directive cannot resolve to a module.
    parser.isModuleLegalType (true);
    SymtabEntry anErrorOccurred = new SymtabEntry ();
    SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred);
    parser.isModuleLegalType (false);  // <57110>

    // Was the indicated type found in the symbol table?
    if (entry == anErrorOccurred)
    {
      // Don't have to generate an error, scopedName already has.
      scanner.skipLineComment ();
      token = scanner.getToken ();
    }
    // <d57110>
    //else if (PragmaIDs.contains (entry))
    //{
    //  ParseException.badRepIDAlreadyAssigned (scanner, entry.name ());
    //  scanner.skipLineComment ();
    //  token = scanner.getToken ();
    //}
    else
    {
      token = parser.token;
      String string = token.name;
      // Do not match token until after raise exceptions, otherwise
      // incorrect messages will be emitted!
      if (PragmaIDs.contains (entry)) // <d57110>
      {
        ParseException.badRepIDAlreadyAssigned (scanner, entry.name ());
      }
      else if (!RepositoryID.hasValidForm (string)) // <d57110>
      {
        ParseException.badRepIDForm (scanner, string);
      }
      else
      {
        entry.repositoryID (new RepositoryID (string));
        PragmaIDs.addElement (entry); // <d57110>
      }
      match (Token.StringLiteral);
    }
  } // idPragma

  /**
   *
   **/
  private void prefixPragma () throws IOException, ParseException
  {
    String string = token.name;
    match (Token.StringLiteral);
    ((IDLID)parser.repIDStack.peek ()).prefix (string);
    ((IDLID)parser.repIDStack.peek ()).name ("");
  } // prefixPragma

  /**
   *
   **/
  private void versionPragma () throws IOException, ParseException
  {
    // Before I can use a parser method, I must make sure it has the current token.
    parser.token = token;
    // This flag will relax the restriction that the scopedNamed
    // in this Version pragma directive cannot resolve to a module.
    parser.isModuleLegalType (true);
    SymtabEntry anErrorOccurred = new SymtabEntry ();
    SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred);
    // reset the flag to original value
    parser.isModuleLegalType (false);
    if (entry == anErrorOccurred)
    {
      // Don't have to generate an error, scopedName already has.
      scanner.skipLineComment ();
      token = scanner.getToken ();
    }
    else
    {
      token = parser.token;
      String string = token.name;
      match (Token.FloatingPointLiteral);
      if (entry.repositoryID () instanceof IDLID)
        ((IDLID)entry.repositoryID ()).version (string);
    }
  } // versionPragma

  private Vector pragmaHandlers = new Vector ();

  /**
   *
   **/
  void registerPragma (PragmaHandler handler)
  {
    pragmaHandlers.addElement (handler);
  } // registerPragma

  /**
   *
   **/
  private void otherPragmas (String pragmaType, String currentToken) throws IOException
  {
    for (int i = pragmaHandlers.size () - 1; i >= 0; --i)
    {
      PragmaHandler handler = (PragmaHandler)pragmaHandlers.elementAt (i);
      if (handler.process (pragmaType, currentToken))
                break;
    }
  } // otherPragmas

  /*
   * These protected methods are used by extenders, by the code
   * which implements otherPragma.
   */

  /**
   * Get the current token.
   **/
  String currentToken ()
  {
    return tokenToString ();
  } // currentToken

  /**
   * This method, given an entry name, returns the entry with that name.
   * It can take fully or partially qualified names and returns the
   * appropriate entry defined within the current scope.  If no entry
   * exists, null is returned.
   **/
  SymtabEntry getEntryForName (String string)
  {
    boolean partialScope = false;
    boolean globalScope  = false;

    // Change all ::'s to /'s
    if (string.startsWith ("::"))
    {
      globalScope = true;
      string = string.substring (2);
    }
    int index = string.indexOf ("::");
    while (index >= 0)
    {
      partialScope = true;
      string = string.substring (0, index) + '/' + string.substring (index + 2);
      index = string.indexOf ("::");
    }

    // Get the entry for that string
    SymtabEntry entry = null;
    if (globalScope)
      entry = parser.recursiveQualifiedEntry (string);
    else if (partialScope)
      entry = parser.recursivePQEntry (string, parser.currentModule);
    else
      entry = parser.unqualifiedEntryWMod (string, parser.currentModule);
    return entry;
  } // getEntryForName

  /**
   * This method returns a string of all of the characters from the
   * input file from the current position up to, but not including,
   * the end-of-line character(s).
   **/
  String getStringToEOL () throws IOException
  {
    return scanner.getStringToEOL ();
  } // getStringToEOL

  /**
   * This method returns a string of all of the characters from the
   * input file from the current position up to, but not including,
   * the given character.  It encapsulates parenthesis and quoted strings,
   * meaning it does not stop if the given character is found within
   * parentheses or quotes.  For instance, given the input of
   * `start(inside)end', getUntil ('n') will return "start(inside)e"
   **/
  String getUntil (char c) throws IOException
  {
    return scanner.getUntil (c);
  } // getUntil

  private boolean lastWasMacroID = false;

  /**
   *
   **/
  private String tokenToString ()
  {
    if (token.equals (Token.MacroIdentifier))
    {
      lastWasMacroID = true;
      return token.name;
    }
    else if (token.equals (Token.Identifier))
      return token.name;
    else
      return token.toString ();
  } // tokenToString

  /**
   * This method returns the next token String from the input file.
   **/
  String nextToken () throws IOException
  {
    if (lastWasMacroID)
    {
      lastWasMacroID = false;
      return "(";
    }
    else
    {
      token = scanner.getToken ();
      return tokenToString ();
    }
  } // nextToken

  /**
   * This method assumes that the current token marks the beginning
   * of a scoped name.  It then parses the subsequent identifier and
   * double colon tokens, builds the scoped name, and finds the symbol
   * table entry with that name.
   **/
  SymtabEntry scopedName () throws IOException
  {
    boolean     globalScope  = false;
    boolean     partialScope = false;
    String      name         = null;
    SymtabEntry entry        = null;
    try
    {
      if (token.equals (Token.DoubleColon))
        globalScope = true;
      else
      {
        if (token.equals (Token.Object))
        {
          name = "Object";
          match (Token.Object);
        }
        else if (token.type == Token.ValueBase)
        {
          name = "ValueBase";
          match (Token.ValueBase);
        }
        else
        {
          name = token.name;
          match (Token.Identifier);
        }
      }
      while (token.equals (Token.DoubleColon))
      {
        match (Token.DoubleColon);
        partialScope = true;
        if (name != null)
          name = name + '/' + token.name;
        else
          name = token.name;
        match (Token.Identifier);
      }
      if (globalScope)
        entry = parser.recursiveQualifiedEntry (name);
      else if (partialScope)
        entry = parser.recursivePQEntry (name, parser.currentModule);
      else
        entry = parser.unqualifiedEntryWMod (name, parser.currentModule);
    }
    catch (ParseException e)
    {
      entry = null;
    }
    return entry;
  } // scopedName

  /**
   * Skip to the end of the line.
   **/
  void skipToEOL () throws IOException
  {
    scanner.skipLineComment ();
  } // skipToEOL

  /**
   * This method skips the data in the input file until the specified
   * character is encountered, then it returns the next token.
   **/
  String skipUntil (char c) throws IOException
  {
    if (!(lastWasMacroID && c == '('))
      token = scanner.skipUntil (c);
    return tokenToString ();
  } // skipUntil

  /**
   * This method displays a Parser Exception complete with line number
   * and position information with the given message string.
   **/
  void parseException (String message)
  {
    // <d62023> Suppress warnings
    if (!parser.noWarn)
      ParseException.warning (scanner, message);
  } // parseException

  // For Pragma
  ///////////////
  // For macro expansion

  /**
   *
   **/
  String expandMacro (String macroDef, Token t) throws IOException, ParseException
  {
    token = t;
    // Get the parameter values from the macro 'call'
    Vector parmValues = getParmValues ();

    // Get the parameter names from the macro definition
    // NOTE:  a newline character is appended here so that when
    // getStringToEOL is called, it stops scanning at the end
    // of this string.
    scanner.scanString (macroDef + '\n');
    Vector parmNames = new Vector ();
    macro (parmNames);

    if (parmValues.size () < parmNames.size ())
      throw ParseException.syntaxError (scanner, Token.Comma, Token.RightParen);
    else if (parmValues.size () > parmNames.size ())
      throw ParseException.syntaxError (scanner, Token.RightParen, Token.Comma);

    macroDef = scanner.getStringToEOL ();
    for (int i = 0; i < parmNames.size (); ++i)
      macroDef = replaceAll (macroDef, (String)parmNames.elementAt (i), (String)parmValues.elementAt (i));
    return removeDoublePound (macroDef);
  } // expandMacro

  // This method is only used by the macro expansion methods.
  /**
   *
   **/
  private void miniMatch (int type) throws ParseException
  {
    // A normal production would now execute:
    // match (type);
    // But match reads the next token.  I don't want to do that now.
    // Just make sure the current token is a 'type'.
    if (!token.equals (type))
      throw ParseException.syntaxError (scanner, type, token.type);
  } // miniMatch

  /**
   *
   **/
  private Vector getParmValues () throws IOException, ParseException
  {
    Vector values = new Vector ();
    if (token.equals (Token.Identifier))
    {
      match (Token.Identifier);
      miniMatch (Token.LeftParen);
    }
    else if (!token.equals (Token.MacroIdentifier))
      throw ParseException.syntaxError (scanner, Token.Identifier, token.type);

    if (!token.equals (Token.RightParen))
    {
      values.addElement (scanner.getUntil (',', ')').trim ());
      token = scanner.getToken ();
      macroParmValues (values);
    }
    return values;
  } // getParmValues

  /**
   *
   **/
  private void macroParmValues (Vector values) throws IOException, ParseException
  {
    while (!token.equals (Token.RightParen))
    {
      miniMatch (Token.Comma);
      values.addElement (scanner.getUntil (',', ')').trim ());
      token = scanner.getToken ();
    }
  } // macroParmValues

  /**
   *
   **/
  private void macro (Vector parmNames) throws IOException, ParseException
  {
    match (token.type);
    match (Token.LeftParen);
    macroParms (parmNames);
    miniMatch (Token.RightParen);
  } // macro

  /**
   *
   **/
  private void macroParms (Vector parmNames) throws IOException, ParseException
  {
    if (!token.equals (Token.RightParen))
    {
      parmNames.addElement (token.name);
      match (Token.Identifier);
      macroParms2 (parmNames);
    }
  } // macroParms

  /**
   *
   **/
  private void macroParms2 (Vector parmNames) throws IOException, ParseException
  {
    while (!token.equals (Token.RightParen))
    {
      match (Token.Comma);
      parmNames.addElement (token.name);
      match (Token.Identifier);
    }
  } // macroParms2

  /**
   *
   **/
  private String replaceAll (String string, String from, String to)
  {
    int index = 0;
    while (index != -1)
    {
      index = string.indexOf (from, index);
      if (index != -1)
      {
        if (!embedded (string, index, index + from.length ()))
          if (index > 0 && string.charAt(index) == '#')
            string = string.substring (0, index) + '"' + to + '"' + string.substring (index + from.length ());
          else
            string = string.substring (0, index) + to + string.substring (index + from.length ());
        index += to.length ();
      }
    }
    return string;
  } // replaceAll

  /**
   *
   **/
  private boolean embedded (String string, int index, int endIndex)
  {
    // Don't replace if found substring is not an independent id.
    // For example, don't replace "thither".indexOf ("it", 0)
    boolean ret    = false;
    char    preCh  = index == 0 ? ' ' : string.charAt (index - 1);
    char    postCh = endIndex >= string.length () - 1 ? ' ' : string.charAt (endIndex);
    if ((preCh >= 'a' && preCh <= 'z') || (preCh >= 'A' && preCh <= 'Z'))
      ret = true;
    else if ((postCh >= 'a' && postCh <= 'z') || (postCh >= 'A' && postCh <= 'Z') || (postCh >= '0' && postCh <= '9') || postCh == '_')
      ret = true;
    else
      ret = inQuotes (string, index);
    return ret;
  } // embedded

  /**
   *
   **/
  private boolean inQuotes (String string, int index)
  {
    int quoteCount = 0;
    for (int i = 0; i < index; ++i)
      if (string.charAt (i) == '"') ++quoteCount;
    // If there are an odd number of quotes before this region,
    // then this region is within quotes
    return quoteCount % 2 != 0;
  } // inQuotes

  /**
   * Remove any occurrences of ##.
   **/
  private String removeDoublePound (String string)
  {
    int index = 0;
    while (index != -1)
    {
      index = string.indexOf ("##", index);
      if (index != -1)
      {
        int startSkip = index - 1;
        int stopSkip  = index + 2;
        if (startSkip < 0)
          startSkip = 0;
        if (stopSkip >= string.length ())
          stopSkip = string.length () - 1;
        while (startSkip > 0 &&
               (string.charAt (startSkip) == ' ' ||
               string.charAt (startSkip) == '\t'))
          --startSkip;
        while (stopSkip < string.length () - 1 &&
               (string.charAt (stopSkip) == ' ' ||
               string.charAt (stopSkip) == '\t'))
          ++stopSkip;
        string = string.substring (0, startSkip + 1) + string.substring (stopSkip);
      }
    }
    return string;
  } // removeDoublePound

  // For macro expansion
  ///////////////

  /**
   *
   **/
  private String getFilename (String name) throws FileNotFoundException
  {
    String fullName = null;
    File file = new File (name);
    if (file.canRead ())
      fullName = name;
    else
    {
      Enumeration pathList = parser.paths.elements ();
      while (!file.canRead () && pathList.hasMoreElements ())
      {
        fullName = (String)pathList.nextElement () + File.separatorChar + name;
        file = new File (fullName);
      }
      if (!file.canRead ())
        throw new FileNotFoundException (name);
    }
    return fullName;
  } // getFilename

  /**
   *
   **/
  private void match (int type) throws IOException, ParseException
  {
    if (!token.equals (type))
      throw ParseException.syntaxError (scanner, type, token.type);
    token = scanner.getToken ();

    // <d62023> Added for convenience, but commented-out because there is
    // no reason to issue warnings for tokens scanned during preprocessing.
    // See issueTokenWarnings().
    //issueTokenWarnings ();

    //System.out.println ("Preprocessor.match token = " + token.type);
    //if (token.equals (Token.Identifier) || token.equals (Token.MacroIdentifier))
    //  System.out.println ("Preprocessor.match token name = " + token.name);

    // If the token is a defined thingy, scan the defined string
    // instead of the input stream for a while.
    if (token.equals (Token.Identifier) || token.equals (Token.MacroIdentifier))
    {
      String string = (String)symbols.get (token.name);
      if (string != null && !string.equals (""))
        // If this is a macro, parse the macro
        if (macros.contains (token.name))
        {
          scanner.scanString (expandMacro (string, token));
          token = scanner.getToken ();
        }
        // else this is just a normal define
        else
        {
          scanner.scanString (string);
          token = scanner.getToken ();
        }
    }
  } // match

  // <d62023>
  /**
   * Issue warnings about tokens scanned during preprocessing.
   **/
  private void issueTokenWarnings ()
  {
    if (parser.noWarn)
      return;

    // There are no keywords defined for preprocessing (only directives), so:
    //
    // 1.) Do not issue warnings for identifiers known to be keywords in
    //     another level of IDL.
    // 2.) Do not issue warnings for identifiers that collide with keywords
    //     in letter, but not case.
    // 3.) Do not issue warnings for deprecated keywords.
    //
    // Should we warn when a macro identifier replaces a keyword?  Hmmm.

    // Deprecated directives?  None to date.
    //if (token.isDirective () && token.isDeprecated ())
    //  ParseException.warning (scanner, Util.getMesage ("Deprecated.directive", token.name));
  } // issueTokenWarnings

  /**
   * This method is called when the parser encounters a left curly brace.
   * An extender of PragmaHandler may find scope information useful.
   * For example, the prefix pragma takes effect as soon as it is
   * encountered and stays in effect until the current scope is closed.
   * If a similar pragma extension is desired, then the openScope and
   * closeScope methods are available for overriding.
   * @param entry the symbol table entry whose scope has just been opened.
   *  Be aware that, since the scope has just been entered, this entry is
   *  incomplete at this point.
   **/
  void openScope (SymtabEntry entry)
  {
    for (int i = pragmaHandlers.size () - 1; i >= 0; --i)
    {
      PragmaHandler handler = (PragmaHandler)pragmaHandlers.elementAt (i);
      handler.openScope (entry);
    }
  } // openScope

  /**
   * This method is called when the parser encounters a right curly brace.
   * An extender of PragmaHandler may find scope information useful.
   * For example, the prefix pragma takes effect as soon as it is
   * encountered and stays in effect until the current scope is closed.
   * If a similar pragma extension is desired, then the openScope and
   * closeScope methods are available for overriding.
   * @param entry the symbol table entry whose scope has just been closed.
   **/
  void closeScope (SymtabEntry entry)
  {
    for (int i = pragmaHandlers.size () - 1; i >= 0; --i)
    {
      PragmaHandler handler = (PragmaHandler)pragmaHandlers.elementAt (i);
      handler.closeScope (entry);
    }
  } // closeScope

  private Parser    parser;
  private Scanner   scanner;
  private Hashtable symbols;
  private Vector    macros;

  // The logic associated with this stack is scattered above.
  // A concise map of the logic is:
  // case #if false, #ifdef false, #ifndef true
  //   push (false);
  //   skipToEndifOrElse ();
  // case #if true, #ifdef true, #ifndef false
  //   push (true);
  // case #elif <conditional>
  //   if (top == true)
  //     skipToEndif ();
  //   else if (conditional == true)
  //     pop ();
  //     push (true);
  //   else if (conditional == false)
  //     skipToEndifOrElse ();
  // case #else
  //   if (top == true)
  //     skipToEndif ();
  //   else
  //     pop ();
  //     push (true);
  // case #endif
  //   pop ();
  private        Stack  alreadyProcessedABranch = new Stack ();
                 Token  token;

  private static String indent = "";
}

Other Java examples (source code examples)

Here is a short list of links related to this Java Preprocessor.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.