blob: a75b59efcf825a3d5c0542dbce7e4a63894980a8 [file] [log] [blame]
/*
* 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 = "";
}