blob: 6b6959b338454964c85d2361745e95a679a0120f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001 Rational Software Corp. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - initial implementation
******************************************************************************/
package org.eclipse.cdt.internal.core.parser;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;
import org.eclipse.cdt.core.parser.BacktrackException;
import org.eclipse.cdt.core.parser.EndOfFileException;
import org.eclipse.cdt.core.parser.ILineOffsetReconciler;
import org.eclipse.cdt.core.parser.IMacroDescriptor;
import org.eclipse.cdt.core.parser.IParser;
import org.eclipse.cdt.core.parser.IParserLogService;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.IScanner;
import org.eclipse.cdt.core.parser.IScannerInfo;
import org.eclipse.cdt.core.parser.ISourceElementRequestor;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.core.parser.NullSourceElementRequestor;
import org.eclipse.cdt.core.parser.OffsetLimitReachedException;
import org.eclipse.cdt.core.parser.ParserFactory;
import org.eclipse.cdt.core.parser.ParserFactoryException;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ParserMode;
import org.eclipse.cdt.core.parser.ScannerException;
import org.eclipse.cdt.core.parser.ScannerInfo;
import org.eclipse.cdt.core.parser.ast.ExpressionEvaluationException;
import org.eclipse.cdt.core.parser.ast.IASTExpression;
import org.eclipse.cdt.core.parser.ast.IASTFactory;
import org.eclipse.cdt.core.parser.ast.IASTInclusion;
/**
* @author jcamelon
*
*/
public class Scanner implements IScanner {
protected final IParserLogService log;
private final static String SCRATCH = "<scratch>";
private Reader backupReader;
private IProblemFactory problemFactory = new ScannerProblemFactory();
private boolean initialContextInitialized = false;
private final String filename;
private final Reader reader;
protected IToken finalToken;
protected void handleProblem( int problemID, String argument, int beginningOffset, boolean warning, boolean error ) throws ScannerException
{
handleProblem( problemID, argument, beginningOffset, warning, error, true );
}
protected void handleProblem( int problemID, String argument, int beginningOffset, boolean warning, boolean error, boolean extra ) throws ScannerException
{
Map arguments = new HashMap();
if( argument != null )
{
String attributes [] = problemFactory.getRequiredAttributesForId( problemID );
arguments.put( attributes[ 0 ], argument );
}
IProblem p = problemFactory.createProblem( problemID, beginningOffset, getCurrentOffset(), contextStack.getCurrentLineNumber(), getCurrentFile().toCharArray(), arguments, warning, error );
if( (! requestor.acceptProblem( p )) && extra )
throw new ScannerException( p );
}
public Scanner(Reader reader, String filename, IScannerInfo info, ISourceElementRequestor requestor, ParserMode parserMode, ParserLanguage language, IParserLogService log ) {
this.log = log;
this.requestor = requestor;
this.mode = parserMode;
this.filename = filename;
this.reader = reader;
this.language = language;
astFactory = ParserFactory.createASTFactory( mode, language );
this.backupReader = reader;
contextStack = new ContextStack( log );
try {
//this is a hack to get around a sudden EOF experience
contextStack.push(
new ScannerContext(
new StringReader("\n"),
START,
ScannerContext.ContextKind.SENTINEL, null), requestor);
} catch( ContextException ce ) {
//won't happen since we aren't adding an include or a macro
}
originalConfig = info;
if( info.getDefinedSymbols() != null )
definitions.putAll( info.getDefinedSymbols() );
if( info.getIncludePaths() != null )
overwriteIncludePath( info.getIncludePaths() );
}
private void setupInitialContext()
{
String resolvedFilename = filename == null ? TEXT : filename;
IScannerContext context = null;
try
{
if( offsetLimit == NO_OFFSET_LIMIT )
context = new ScannerContext(reader, resolvedFilename, ScannerContext.ContextKind.TOP, null );
else
context = new LimitedScannerContext( reader, resolvedFilename, ScannerContext.ContextKind.TOP, offsetLimit );
contextStack.push( context, requestor );
} catch( ContextException ce )
{
handleInternalError();
}
initialContextInitialized = true;
}
public void addIncludePath(String includePath) {
includePathNames.add(includePath);
includePaths.add( new File( includePath ) );
}
public void overwriteIncludePath(String [] newIncludePaths) {
if( newIncludePaths == null ) return;
includePathNames = null;
includePaths = null;
includePathNames = new ArrayList();
includePaths = new ArrayList();
for( int i = 0; i < newIncludePaths.length; ++i )
includePathNames.add( newIncludePaths[i] );
Iterator i = includePathNames.iterator();
while( i.hasNext() )
{
String path = (String) i.next();
includePaths.add( new File( path ));
}
}
public void addDefinition(String key, IMacroDescriptor macro) {
definitions.put(key, macro);
}
public void addDefinition(String key, String value) {
definitions.put(key, value);
}
public final Object getDefinition(String key) {
return definitions.get(key);
}
public final String[] getIncludePaths() {
return (String[])includePathNames.toArray();
}
protected boolean skipOverWhitespace() throws ScannerException {
int c = getChar();
boolean result = false;
while ((c != NOCHAR) && ((c == ' ') || (c == '\t')))
{
c = getChar();
result = true;
}
if (c != NOCHAR)
ungetChar(c);
return result;
}
protected String getRestOfPreprocessorLine() throws ScannerException {
StringBuffer buffer = new StringBuffer();
skipOverWhitespace();
int c = getChar();
boolean inString = false;
boolean inChar = false;
while (true) {
while ((c != '\n')
&& (c != '\r')
&& (c != '\\')
&& (c != '/')
&& (c != '"' || ( c == '"' && inChar ) )
&& (c != '\'' || ( c == '\'' && inString ) )
&& (c != NOCHAR)) {
buffer.append((char) c);
c = getChar( true );
}
if (c == '/') {
//only care about comments outside of a quote
if( inString || inChar ){
buffer.append( (char) c );
c = getChar( true );
continue;
}
// we need to peek ahead at the next character to see if
// this is a comment or not
int next = getChar();
if (next == '/') {
// single line comment
skipOverSinglelineComment();
break;
} else if (next == '*') {
// multiline comment
if (skipOverMultilineComment())
break;
else
c = getChar( true );
continue;
} else {
// we are not in a comment
buffer.append((char) c);
c = next;
continue;
}
} else if( c == '"' ){
inString = !inString;
buffer.append((char) c);
c = getChar( true );
continue;
} else if( c == '\'' ){
inChar = !inChar;
buffer.append((char) c);
c = getChar( true );
continue;
} else if( c == '\\' ){
c = getChar(true);
if( c == '\r' ){
c = getChar(true);
if( c == '\n' ){
c = getChar(true);
}
} else if( c == '\n' ){
c = getChar(true);
} else {
buffer.append('\\');
if( c == '"' || c == '\'' ){
buffer.append((char)c);
c = getChar( true );
}
}
continue;
} else {
ungetChar(c);
break;
}
}
return buffer.toString();
}
protected void skipOverTextUntilNewline() throws ScannerException {
for (;;) {
switch (getChar()) {
case NOCHAR :
case '\n' :
return;
case '\\' :
getChar();
}
}
}
private void setCurrentToken(IToken t) {
if (currentToken != null)
currentToken.setNext(t);
finalToken = t;
currentToken = t;
}
protected void resetStorageBuffer()
{
if( storageBuffer != null )
storageBuffer = null;
}
protected IToken newToken(int t, String i, IScannerContext c) {
setCurrentToken(new Token(t, i, c));
return currentToken;
}
protected IToken newToken(int t, String i) {
setCurrentToken(new Token(t, i));
return currentToken;
}
protected String getNextIdentifier() throws ScannerException {
StringBuffer buffer = new StringBuffer();
skipOverWhitespace();
int c = getChar();
if (((c >= 'a') && (c <= 'z'))
|| ((c >= 'A') && (c <= 'Z')) | (c == '_')) {
buffer.append((char) c);
c = getChar();
while (((c >= 'a') && (c <= 'z'))
|| ((c >= 'A') && (c <= 'Z'))
|| ((c >= '0') && (c <= '9'))
|| (c == '_')) {
buffer.append((char) c);
c = getChar();
}
}
ungetChar(c);
return buffer.toString();
}
protected void handleInclusion(String fileName, boolean useIncludePaths, int nameOffset, int beginOffset, int endOffset ) throws ScannerException {
FileReader inclusionReader = null;
String newPath = null;
if( useIncludePaths ) // search include paths for this file
{
// iterate through the include paths
Iterator iter = includePaths.iterator();
while (iter.hasNext()) {
File pathFile = (File)iter.next();
String path = pathFile.getPath();
if( !pathFile.exists() && path.indexOf('\"') != -1 )
{
StringTokenizer tokenizer = new StringTokenizer(path, "\"" ); //$NON-NLS-1$
StringBuffer buffer = new StringBuffer(path.length() );
while( tokenizer.hasMoreTokens() ){
buffer.append( tokenizer.nextToken() );
}
pathFile = new File( buffer.toString() );
}
if (pathFile.isDirectory()) {
newPath = pathFile.getPath() + File.separatorChar + fileName;
File includeFile = new File(newPath);
if (includeFile.exists() && includeFile.isFile()) {
try {
inclusionReader = new FileReader(includeFile);
break;
} catch (FileNotFoundException fnf) {
// do nothing - check the next directory
}
}
}
}
if (inclusionReader == null )
{
handleProblem( IProblem.PREPROCESSOR_INCLUSION_NOT_FOUND, fileName, beginOffset, false, true, true );
}
}
else // local inclusion
{
String currentFilename = contextStack.getCurrentContext().getFilename();
File currentIncludeFile = new File( currentFilename );
String parentDirectory = currentIncludeFile.getParentFile().getAbsolutePath();
currentIncludeFile = null;
newPath = parentDirectory + File.separatorChar + fileName;
File includeFile = new File( newPath );
if (includeFile.exists() && includeFile.isFile()) {
try {
inclusionReader =
new FileReader(includeFile);
} catch (FileNotFoundException fnf) {
// the spec says that if finding in the local directory fails, search the include paths
handleInclusion( fileName, true, nameOffset, beginOffset, endOffset );
}
}
else
{
// the spec says that if finding in the local directory fails, search the include paths
handleInclusion( fileName, true, nameOffset, beginOffset, endOffset );
}
}
if (inclusionReader != null) {
IASTInclusion inclusion = null;
try
{
inclusion =
astFactory.createInclusion(
fileName,
newPath,
!useIncludePaths,
beginOffset,
nameOffset,
nameOffset + fileName.length(),
endOffset);
}
catch (Exception e)
{
/* do nothing */
}
try
{
contextStack.updateContext(inclusionReader, newPath, ScannerContext.ContextKind.INCLUSION, inclusion, requestor );
}
catch (ContextException e1)
{
handleProblem( e1.getId(), fileName, beginOffset, false, true, true );
}
}
}
// constants
private static final int NOCHAR = -1;
private static final String TEXT = "<text>";
private static final String START = "<initial reader>";
private static final String EXPRESSION = "<expression>";
private static final String PASTING = "<pasting>";
private static final String DEFINED = "defined";
private static final String _PRAGMA = "_Pragma";
private static final String POUND_DEFINE = "#define ";
private ContextStack contextStack = null;
private IScannerContext lastContext = null;
private IScannerInfo originalConfig;
private List includePathNames = new ArrayList();
private List includePaths = new ArrayList();
private Hashtable definitions = new Hashtable();
private StringBuffer storageBuffer = null;
private int count = 0;
private static HashMap cppKeywords = new HashMap();
private static HashMap cKeywords = new HashMap();
private static HashMap ppDirectives = new HashMap();
private IToken currentToken = null;
private IToken cachedToken = null;
private boolean passOnToClient = true;
private BranchTracker branches = new BranchTracker();
// these are scanner configuration aspects that we perhaps want to tweak
// eventually, these should be configurable by the client, but for now
// we can just leave it internal
private boolean enableDigraphReplacement = true;
private boolean enableTrigraphReplacement = true;
private boolean enableTrigraphReplacementInStrings = true;
private boolean throwExceptionOnBadCharacterRead = false;
private boolean atEOF = false;
private boolean tokenizingMacroReplacementList = false;
public void setTokenizingMacroReplacementList( boolean mr ){
tokenizingMacroReplacementList = mr;
}
private final ParserMode mode;
public int getCharacter() throws ScannerException
{
if( ! initialContextInitialized )
setupInitialContext();
return getChar();
}
private int getChar() throws ScannerException
{
return getChar( false );
}
private int getChar( boolean insideString ) throws ScannerException {
int c = NOCHAR;
lastContext = contextStack.getCurrentContext();
if (contextStack.getCurrentContext() == null)
// past the end of file
return c;
c = accountForUndo(c);
int baseOffset = lastContext.getOffset() - lastContext.undoStackSize() - 1;
if (enableTrigraphReplacement && (!insideString || enableTrigraphReplacementInStrings)) {
// Trigraph processing
enableTrigraphReplacement = false;
if (c == '?') {
c = getChar(insideString);
if (c == '?') {
c = getChar(insideString);
switch (c) {
case '(':
expandDefinition("??(", "[", baseOffset);
c = getChar(insideString);
break;
case ')':
expandDefinition("??)", "]", baseOffset);
c = getChar(insideString);
break;
case '<':
expandDefinition("??<", "{", baseOffset);
c = getChar(insideString);
break;
case '>':
expandDefinition("??>", "}", baseOffset);
c = getChar(insideString);
break;
case '=':
expandDefinition("??=", "#", baseOffset);
c = getChar(insideString);
break;
case '/':
expandDefinition("??/", "\\", baseOffset);
c = getChar(insideString);
break;
case '\'':
expandDefinition("??\'", "^", baseOffset);
c = getChar(insideString);
break;
case '!':
expandDefinition("??!", "|", baseOffset);
c = getChar(insideString);
break;
case '-':
expandDefinition("??-", "~", baseOffset);
c = getChar(insideString);
break;
default:
// Not a trigraph
ungetChar(c);
ungetChar('?');
c = '?';
}
} else {
// Not a trigraph
ungetChar(c);
c = '?';
}
}
enableTrigraphReplacement = true;
}
if (!insideString)
{
if (c == '\\') {
c = getChar(false);
if (c == '\r') {
c = getChar(false);
if (c == '\n')
{
c = getChar(false);
}
} else if (c == '\n')
{
c = getChar(false);
} else // '\' is not the last character on the line
{
ungetChar(c);
c = '\\';
}
} else if (enableDigraphReplacement) {
enableDigraphReplacement = false;
// Digraph processing
if (c == '<') {
c = getChar(false);
if (c == '%') {
expandDefinition("<%", "{", baseOffset);
c = getChar(false);
} else if (c == ':') {
expandDefinition("<:", "[", baseOffset);
c = getChar(false);
} else {
// Not a digraph
ungetChar(c);
c = '<';
}
} else if (c == ':') {
c = getChar(false);
if (c == '>') {
expandDefinition(":>", "]", baseOffset);
c = getChar(false);
} else {
// Not a digraph
ungetChar(c);
c = ':';
}
} else if (c == '%') {
c = getChar(false);
if (c == '>') {
expandDefinition("%>", "}", baseOffset);
c = getChar(false);
} else if (c == ':') {
expandDefinition("%:", "#", baseOffset);
c = getChar(false);
} else {
// Not a digraph
ungetChar(c);
c = '%';
}
}
enableDigraphReplacement = true;
}
}
return c;
}
protected int accountForUndo(int c)
{
boolean done;
do {
done = true;
if (contextStack.getCurrentContext().undoStackSize() != 0 ) {
c = contextStack.getCurrentContext().popUndo();
} else {
try {
c = contextStack.getCurrentContext().read();
if (c == NOCHAR) {
if (contextStack.rollbackContext(requestor) == false) {
c = NOCHAR;
break;
} else {
done = false;
}
}
} catch (IOException e) {
if (contextStack.rollbackContext(requestor) == false) {
c = NOCHAR;
} else {
done = false;
}
}
}
} while (!done);
return c;
}
private void ungetChar(int c) throws ScannerException{
contextStack.getCurrentContext().pushUndo(c);
try
{
contextStack.undoRollback( lastContext, requestor );
}
catch (ContextException e)
{
handleProblem( e.getId(), contextStack.getCurrentContext().getFilename(), getCurrentOffset(), false, true, true );
}
}
protected boolean lookAheadForTokenPasting() throws ScannerException
{
int c = getChar();
if( c == '#' )
{
c = getChar();
if( c == '#' )
{
return true;
}
else
{
ungetChar( c );
}
}
ungetChar( c );
return false;
}
protected void consumeUntilOutOfMacroExpansion() throws ScannerException
{
while( contextStack.getCurrentContext().getKind() == IScannerContext.ContextKind.MACROEXPANSION )
getChar();
}
public IToken nextToken() throws ScannerException, EndOfFileException, OffsetLimitReachedException {
return nextToken( true, false );
}
public IToken nextToken(boolean pasting) throws ScannerException, EndOfFileException, OffsetLimitReachedException {
return nextToken( pasting, false );
}
public IToken nextToken( boolean pasting, boolean lookingForNextAlready ) throws ScannerException, EndOfFileException, OffsetLimitReachedException
{
if( ! initialContextInitialized )
setupInitialContext();
if( cachedToken != null ){
setCurrentToken( cachedToken );
cachedToken = null;
return currentToken;
}
count++;
boolean possibleWideLiteral = true;
boolean wideLiteral = false;
int c = getChar();
while (c != NOCHAR) {
if ( ! passOnToClient ) {
while (c != NOCHAR && c != '#' )
{
c = getChar();
if( c == '/' )
{
c = getChar();
if( c == '/' )
{
skipOverSinglelineComment();
c = getChar();
continue;
}
else if( c == '*' )
{
skipOverMultilineComment();
c = getChar();
continue;
}
}
}
if( c == NOCHAR ) continue;
}
if ((c == ' ') || (c == '\r') || (c == '\t') || (c == '\n')) {
c = getChar();
continue;
} else if (c == 'L' && possibleWideLiteral ) {
int oldChar = c;
c = getChar();
if(!(c == '"' || c == '\'')) {
// we have made a mistake
ungetChar(c);
c = oldChar;
possibleWideLiteral = false;
continue;
}
wideLiteral = true;
continue;
} else if (c == '"') {
int beginOffset = getCurrentOffset();
// string
StringBuffer buff = new StringBuffer();
int beforePrevious = NOCHAR;
int previous = c;
c = getChar(true);
for( ; ; )
{
if ( ( c =='"' ) && ( previous != '\\' || beforePrevious == '\\') ) break;
if ( ( c == '\n' ) && ( previous != '\\' || beforePrevious == '\\') )
{
handleProblem( IProblem.SCANNER_UNBOUNDED_STRING, null, beginOffset, false, true, true );
}
if( c == NOCHAR) break;
buff.append((char) c);
beforePrevious = previous;
previous = c;
c = getChar(true);
}
if (c != NOCHAR )
{
int type = wideLiteral ? IToken.tLSTRING : IToken.tSTRING;
//If the next token is going to be a string as well, we need to concatenate
//it with this token.
IToken returnToken = newToken( type, buff.toString(), contextStack.getCurrentContext());
if (!lookingForNextAlready) {
IToken next = null;
try{
next = nextToken( true, true );
} catch( EndOfFileException e ){
next = null;
}
while( next != null && ( next.getType() == IToken.tSTRING ||
next.getType() == IToken.tLSTRING ) ){
returnToken.setImage( returnToken.getImage() + next.getImage() );
returnToken.setNext( null );
currentToken = returnToken;
try{
next = nextToken( true, true );
} catch( EndOfFileException e ){
next = null;
}
}
cachedToken = next;
}
currentToken = returnToken;
returnToken.setNext( null );
return returnToken;
} else
handleProblem( IProblem.SCANNER_UNBOUNDED_STRING, null, beginOffset, false, true, true );
} else if (
((c >= 'a') && (c <= 'z'))
|| ((c >= 'A') && (c <= 'Z')) || (c == '_')) {
int baseOffset = lastContext.getOffset() - lastContext.undoStackSize() - 1;
// String buffer is slow, we need a better way such as memory mapped files
StringBuffer buff = new StringBuffer();
buff.append((char) c);
c = getChar();
while (((c >= 'a') && (c <= 'z'))
|| ((c >= 'A') && (c <= 'Z'))
|| ((c >= '0') && (c <= '9'))
|| (c == '_')) {
buff.append((char) c);
c = getChar();
}
ungetChar(c);
String ident = buff.toString();
if (ident.equals(DEFINED))
return newToken(IToken.tINTEGER, handleDefinedMacro());
if( ident.equals(_PRAGMA) && language == ParserLanguage.C )
{
handlePragmaOperator();
c = getChar();
continue;
}
Object mapping = definitions.get(ident);
if (mapping != null) {
if( contextStack.shouldExpandDefinition( POUND_DEFINE + ident ) ) {
expandDefinition(ident, mapping, baseOffset);
c = getChar();
continue;
}
}
Object tokenTypeObject;
if( language == ParserLanguage.CPP )
tokenTypeObject = cppKeywords.get(ident);
else
tokenTypeObject = cKeywords.get(ident);
int tokenType = IToken.tIDENTIFIER;
if (tokenTypeObject != null)
tokenType = ((Integer) tokenTypeObject).intValue();
if( pasting )
{
if( lookAheadForTokenPasting() )
{
if( storageBuffer == null )
storageBuffer = buff;
else
storageBuffer.append( ident );
c = getChar();
continue;
}
else
{
if( storageBuffer != null )
{
storageBuffer.append( ident );
try
{
contextStack.updateContext( new StringReader( storageBuffer.toString()), PASTING, IScannerContext.ContextKind.MACROEXPANSION, null, requestor );
}
catch (ContextException e)
{
handleProblem( e.getId(), contextStack.getCurrentContext().getFilename(), getCurrentOffset(), false, true, true );
}
storageBuffer = null;
c = getChar();
continue;
}
}
}
return newToken(tokenType, ident, contextStack.getCurrentContext());
} else if ((c >= '0') && (c <= '9') || c == '.' ) {
int beginOffset = getCurrentOffset();
StringBuffer buff;
if( pasting )
{
if( storageBuffer != null )
buff = storageBuffer;
else
buff = new StringBuffer();
}
else
buff = new StringBuffer();
boolean hex = false;
boolean floatingPoint = ( c == '.' ) ? true : false;
boolean firstCharZero = ( c== '0' )? true : false;
buff.append((char) c);
c = getChar();
if( ! firstCharZero && floatingPoint && !(c >= '0' && c <= '9') ){
//if pasting, there could actually be a float here instead of just a .
if( buff.toString().equals( "." ) ){
if( c == '*' ){
return newToken( IToken.tDOTSTAR, ".*", contextStack.getCurrentContext() );
} else if( c == '.' ){
if( getChar() == '.' )
return newToken( IToken.tELLIPSIS, "..." );
else
handleProblem( IProblem.SCANNER_BAD_FLOATING_POINT, null, beginOffset, false, true, true );
} else {
ungetChar( c );
return newToken( IToken.tDOT, ".", contextStack.getCurrentContext() );
}
}
} else if (c == 'x') {
if( ! firstCharZero )
{
handleProblem( IProblem.SCANNER_BAD_HEX_FORMAT, null, beginOffset, false, true, true );
c = getChar();
continue;
}
buff.append( (char)c );
hex = true;
c = getChar();
}
while ((c >= '0' && c <= '9')
|| (hex
&& ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))) {
buff.append((char) c);
c = getChar();
}
if( c == '.' )
{
buff.append( (char)c);
floatingPoint = true;
c= getChar();
while ((c >= '0' && c <= '9')
|| (hex
&& ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))))
{
buff.append((char) c);
c = getChar();
}
}
if (c == 'e' || c == 'E' || (hex && (c == 'p' || c == 'P')))
{
if( ! floatingPoint ) floatingPoint = true;
// exponent type for floating point
buff.append((char)c);
c = getChar();
// optional + or -
if( c == '+' || c == '-' )
{
buff.append( (char)c );
c = getChar();
}
// digit sequence of exponent part
while ((c >= '0' && c <= '9') )
{
buff.append((char) c);
c = getChar();
}
// optional suffix
if( c == 'l' || c == 'L' || c == 'f' || c == 'F' )
{
buff.append( (char)c );
c = getChar();
}
} else {
if( floatingPoint ){
//floating-suffix
if( c == 'l' || c == 'L' || c == 'f' || c == 'F' ){
c = getChar();
}
} else {
//integer suffix
if( c == 'u' || c == 'U' ){
c = getChar();
if( c == 'l' || c == 'L')
c = getChar();
if( c == 'l' || c == 'L')
c = getChar();
} else if( c == 'l' || c == 'L' ){
c = getChar();
if( c == 'l' || c == 'L')
c = getChar();
if( c == 'u' || c == 'U' )
c = getChar();
}
}
}
ungetChar( c );
if( pasting )
{
if( lookAheadForTokenPasting() )
{
storageBuffer = buff;
c = getChar();
continue;
}
else
{
if( storageBuffer != null )
{
try
{
contextStack.updateContext( new StringReader( buff.toString()), PASTING, IScannerContext.ContextKind.MACROEXPANSION, null, requestor );
}
catch (ContextException e)
{
handleProblem( e.getId(), contextStack.getCurrentContext().getFilename(), getCurrentOffset(), false, true, true );
}
storageBuffer = null;
c = getChar();
continue;
}
}
}
int tokenType;
String result = buff.toString();
if( floatingPoint && result.equals(".") )
tokenType = IToken.tDOT;
else
tokenType = floatingPoint ? IToken.tFLOATINGPT : IToken.tINTEGER;
return newToken(
tokenType,
result,
contextStack.getCurrentContext());
} else if (c == '#') {
int beginningOffset = contextStack.getCurrentContext().getOffset() - 1;
// lets prepare for a preprocessor statement
StringBuffer buff = new StringBuffer();
buff.append((char) c);
// we are allowed arbitrary whitespace after the '#' and before the rest of the text
boolean skipped = skipOverWhitespace();
c = getChar();
if( c == '#' )
{
if( skipped )
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "# #", beginningOffset, false, true, true );
else
return newToken( tPOUNDPOUND, "##" );
} else if( tokenizingMacroReplacementList ) {
ungetChar( c );
return newToken( tPOUND, "#" );
}
while (((c >= 'a') && (c <= 'z'))
|| ((c >= 'A') && (c <= 'Z')) || (c == '_') ) {
buff.append((char) c);
c = getChar();
}
ungetChar(c);
String token = buff.toString();
Object directive = ppDirectives.get(token);
if (directive == null) {
if (true)
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#"+token, beginningOffset, false, true, true );
} else {
int type = ((Integer) directive).intValue();
switch (type) {
case PreprocessorDirectives.DEFINE :
if ( ! passOnToClient ) {
skipOverTextUntilNewline();
c = getChar();
continue;
}
poundDefine(beginningOffset);
c = getChar();
continue;
case PreprocessorDirectives.INCLUDE :
if (! passOnToClient ) {
skipOverTextUntilNewline();
c = getChar();
continue;
}
poundInclude( beginningOffset );
c = getChar();
continue;
case PreprocessorDirectives.UNDEFINE :
if (! passOnToClient) {
skipOverTextUntilNewline();
c = getChar();
continue;
}
skipOverWhitespace();
// definition
String toBeUndefined = getNextIdentifier();
definitions.remove(toBeUndefined);
skipOverTextUntilNewline();
c = getChar();
continue;
case PreprocessorDirectives.IF :
// get the rest of the line
int currentOffset = getCurrentOffset();
String expression = getRestOfPreprocessorLine();
boolean expressionEvalResult = false;
try{
expressionEvalResult = evaluateExpression(expression, currentOffset);
} catch( ScannerException e ){}
passOnToClient = branches.poundif( expressionEvalResult );
c = getChar();
continue;
case PreprocessorDirectives.IFDEF :
skipOverWhitespace();
String definition = getNextIdentifier();
Object mapping = definitions.get(definition);
if (mapping == null) {
// not defined
passOnToClient = branches.poundif( false );
skipOverTextUntilNewline();
} else {
passOnToClient = branches.poundif( true );
// continue along, act like nothing is wrong :-)
c = getChar();
}
continue;
case PreprocessorDirectives.ENDIF :
String restOfLine = getRestOfPreprocessorLine().trim();
if( ! restOfLine.equals( "" ) && true )
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#endif " + restOfLine, beginningOffset, false, true, true );
passOnToClient = branches.poundendif();
c = getChar();
continue;
case PreprocessorDirectives.IFNDEF :
skipOverWhitespace();
String def = getNextIdentifier();
Object map = definitions.get(def);
if (map != null) {
// not defined
skipOverTextUntilNewline();
passOnToClient = branches.poundif( false );
} else {
passOnToClient = branches.poundif( true );
// continue along, act like nothing is wrong :-)
c = getChar();
}
continue;
case PreprocessorDirectives.ELSE :
try
{
passOnToClient = branches.poundelse();
}
catch( EmptyStackException ese )
{
handleProblem( IProblem.PREPROCESSOR_UNBALANCE_CONDITION,
token,
beginningOffset,
false, true, true );
}
skipOverTextUntilNewline();
c = getChar();
continue;
case PreprocessorDirectives.ELIF :
int co = getCurrentOffset();
String elsifExpression = getRestOfPreprocessorLine().trim();
if (elsifExpression.equals(""))
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#elif", beginningOffset, false, true, true );
boolean elsifResult = false;
elsifResult = evaluateExpression(elsifExpression, co );
try
{
passOnToClient = branches.poundelif( elsifResult );
}
catch( EmptyStackException ese )
{
handleProblem( IProblem.PREPROCESSOR_UNBALANCE_CONDITION,
token + ' ' + elsifExpression,
beginningOffset,
false, true, true );
}
c = getChar();
continue;
case PreprocessorDirectives.LINE :
//TO DO
skipOverTextUntilNewline();
c = getChar();
continue;
case PreprocessorDirectives.ERROR :
if (! passOnToClient) {
skipOverTextUntilNewline();
c = getChar();
continue;
}
handleProblem( IProblem.PREPROCESSOR_POUND_ERROR, getRestOfPreprocessorLine(), beginningOffset, false, true, true );
c = getChar();
continue;
case PreprocessorDirectives.PRAGMA :
skipOverTextUntilNewline();
c = getChar();
continue;
case PreprocessorDirectives.BLANK :
String remainderOfLine =
getRestOfPreprocessorLine().trim();
if (!remainderOfLine.equals("")) {
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "# " + remainderOfLine, beginningOffset, false, true, true );
}
c = getChar();
continue;
default :
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#" + token, beginningOffset, false, true, true );
}
}
} else {
switch (c) {
case '\'' :
return processCharacterLiteral( c, wideLiteral );
case ':' :
c = getChar();
switch (c) {
case ':' :
return newToken(
IToken.tCOLONCOLON,
"::",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tCOLON,
":",
contextStack.getCurrentContext());
}
case ';' :
return newToken(IToken.tSEMI, ";", contextStack.getCurrentContext());
case ',' :
return newToken(IToken.tCOMMA, ",", contextStack.getCurrentContext());
case '?' :
return newToken(IToken.tQUESTION, "?", contextStack.getCurrentContext());
case '(' :
return newToken(IToken.tLPAREN, "(", contextStack.getCurrentContext());
case ')' :
return newToken(IToken.tRPAREN, ")", contextStack.getCurrentContext());
case '[' :
return newToken(IToken.tLBRACKET, "[", contextStack.getCurrentContext());
case ']' :
return newToken(IToken.tRBRACKET, "]", contextStack.getCurrentContext());
case '{' :
return newToken(IToken.tLBRACE, "{", contextStack.getCurrentContext());
case '}' :
return newToken(IToken.tRBRACE, "}", contextStack.getCurrentContext());
case '+' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tPLUSASSIGN,
"+=",
contextStack.getCurrentContext());
case '+' :
return newToken(
IToken.tINCR,
"++",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tPLUS,
"+",
contextStack.getCurrentContext());
}
case '-' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tMINUSASSIGN,
"-=",
contextStack.getCurrentContext());
case '-' :
return newToken(
IToken.tDECR,
"--",
contextStack.getCurrentContext());
case '>' :
c = getChar();
switch (c) {
case '*' :
return newToken(
IToken.tARROWSTAR,
"->*",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tARROW,
"->",
contextStack.getCurrentContext());
}
default :
ungetChar(c);
return newToken(
IToken.tMINUS,
"-",
contextStack.getCurrentContext());
}
case '*' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tSTARASSIGN,
"*=",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tSTAR,
"*",
contextStack.getCurrentContext());
}
case '%' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tMODASSIGN,
"%=",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tMOD,
"%",
contextStack.getCurrentContext());
}
case '^' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tXORASSIGN,
"^=",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tXOR,
"^",
contextStack.getCurrentContext());
}
case '&' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tAMPERASSIGN,
"&=",
contextStack.getCurrentContext());
case '&' :
return newToken(
IToken.tAND,
"&&",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tAMPER,
"&",
contextStack.getCurrentContext());
}
case '|' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tBITORASSIGN,
"|=",
contextStack.getCurrentContext());
case '|' :
return newToken(
IToken.tOR,
"||",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tBITOR,
"|",
contextStack.getCurrentContext());
}
case '~' :
return newToken(IToken.tCOMPL, "~", contextStack.getCurrentContext());
case '!' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tNOTEQUAL,
"!=",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tNOT,
"!",
contextStack.getCurrentContext());
}
case '=' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tEQUAL,
"==",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tASSIGN,
"=",
contextStack.getCurrentContext());
}
case '<' :
c = getChar();
switch (c) {
case '<' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tSHIFTLASSIGN,
"<<=",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tSHIFTL,
"<<",
contextStack.getCurrentContext());
}
case '=' :
return newToken(
IToken.tLTEQUAL,
"<=",
contextStack.getCurrentContext());
default :
ungetChar(c);
if( forInclusion )
temporarilyReplaceDefinitionsMap();
return newToken(IToken.tLT, "<", contextStack.getCurrentContext());
}
case '>' :
c = getChar();
switch (c) {
case '>' :
c = getChar();
switch (c) {
case '=' :
return newToken(
IToken.tSHIFTRASSIGN,
">>=",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tSHIFTR,
">>",
contextStack.getCurrentContext());
}
case '=' :
return newToken(
IToken.tGTEQUAL,
">=",
contextStack.getCurrentContext());
default :
ungetChar(c);
if( forInclusion )
restoreDefinitionsMap();
return newToken(IToken.tGT, ">", contextStack.getCurrentContext());
}
case '.' :
c = getChar();
switch (c) {
case '.' :
c = getChar();
switch (c) {
case '.' :
return newToken(
IToken.tELLIPSIS,
"...",
contextStack.getCurrentContext());
default :
break;
}
break;
case '*' :
return newToken(
IToken.tDOTSTAR,
".*",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tDOT,
".",
contextStack.getCurrentContext());
}
break;
case '/' :
c = getChar();
switch (c) {
case '/' :
skipOverSinglelineComment();
c = getChar();
continue;
case '*' :
skipOverMultilineComment();
c = getChar();
continue;
case '=' :
return newToken(
IToken.tDIVASSIGN,
"/=",
contextStack.getCurrentContext());
default :
ungetChar(c);
return newToken(
IToken.tDIV,
"/",
contextStack.getCurrentContext());
}
default :
handleProblem( IProblem.SCANNER_BAD_CHARACTER, new Character( (char)c ).toString(), getCurrentOffset(), false, true, throwExceptionOnBadCharacterRead );
c = getChar();
continue;
}
throwEOF();
}
}
if (( getDepth() != 0) && !atEOF )
{
atEOF = true;
handleProblem( IProblem.SCANNER_UNEXPECTED_EOF, null, getCurrentOffset(), false, true, true );
}
// we're done
throwEOF();
return null;
}
/**
*
*/
protected void handlePragmaOperator() throws ScannerException
{
// until we know what to do with pragmas, do the equivalent as
// to what we do for #pragma blah blah blah (ignore it)
getRestOfPreprocessorLine();
}
/**
* @param c
* @param wideLiteral
*/
protected IToken processCharacterLiteral(int c, boolean wideLiteral)
throws ScannerException
{
int beginOffset = getCurrentOffset();
int type = wideLiteral ? IToken.tLCHAR : IToken.tCHAR;
StringBuffer buffer = new StringBuffer();
int prev = c;
int prevPrev = c;
c = getChar(true);
for( ; ; )
{
// error conditions
if( ( c == '\n' ) ||
( ( c == '\\' || c =='\'' )&& prev == '\\' ) ||
( c == NOCHAR ) )
{
handleProblem( IProblem.SCANNER_BAD_CHARACTER, new Character( (char)c ).toString(),beginOffset, false, true, throwExceptionOnBadCharacterRead );
c = ' ';
}
// exit condition
if ( ( c =='\'' ) && ( prev != '\\' || prevPrev == '\\' ) ) break;
buffer.append( (char)c);
prevPrev = prev;
prev = c;
c = getChar(true);
}
return newToken( type, buffer.toString(), contextStack.getCurrentContext());
}
protected String getCurrentFile()
{
return contextStack.getMostRelevantFileContext() != null ? contextStack.getMostRelevantFileContext().getFilename() : "";
}
protected int getCurrentOffset()
{
return contextStack.getMostRelevantFileContext() != null ? contextStack.getMostRelevantFileContext().getOffset() : -1;
}
protected static class endOfMacroTokenException extends Exception {};
// the static instance we always use
protected static endOfMacroTokenException endOfMacroToken = new endOfMacroTokenException();
public IToken nextTokenForStringizing() throws ScannerException, EndOfFileException, OffsetLimitReachedException
{
int beginOffset = getCurrentOffset();
int c = getChar();
StringBuffer tokenImage = new StringBuffer();
try {
while (c != NOCHAR) {
if ((c == ' ') || (c == '\r') || (c == '\t') || (c == '\n')) {
if (tokenImage.length() > 0) throw endOfMacroToken;
c = getChar();
continue;
} else if (c == '"') {
if (tokenImage.length() > 0) throw endOfMacroToken;
// string
StringBuffer buff = new StringBuffer();
c = getChar(true);
for( ; ; )
{
if ( c =='"' ) break;
if( c == NOCHAR) break;
buff.append((char) c);
c = getChar(true);
}
if (c != NOCHAR )
{
return newToken( IToken.tSTRING, buff.toString(), contextStack.getCurrentContext());
} else {
handleProblem( IProblem.SCANNER_UNBOUNDED_STRING, null, beginOffset, false, true, true );
c = getChar();
continue;
}
} else {
switch (c) {
case '\'' :
if (tokenImage.length() > 0) throw endOfMacroToken;
return processCharacterLiteral( c, false );
case ',' :
if (tokenImage.length() > 0) throw endOfMacroToken;
return newToken(IToken.tCOMMA, ",", contextStack.getCurrentContext());
case '(' :
if (tokenImage.length() > 0) throw endOfMacroToken;
return newToken(IToken.tLPAREN, "(", contextStack.getCurrentContext());
case ')' :
if (tokenImage.length() > 0) throw endOfMacroToken;
return newToken(IToken.tRPAREN, ")", contextStack.getCurrentContext());
case '/' :
if (tokenImage.length() > 0) throw endOfMacroToken;
c = getChar();
switch (c) {
case '/' :
skipOverSinglelineComment();
c = getChar();
continue;
case '*' :
skipOverMultilineComment();
c = getChar();
continue;
default:
tokenImage.append('/');
continue;
}
default :
tokenImage.append((char)c);
c = getChar();
}
}
}
} catch (endOfMacroTokenException e) {
// unget the first character after the end of token
ungetChar(c);
}
// return completed token
if (tokenImage.length() > 0) {
return newToken(IToken.tIDENTIFIER, tokenImage.toString(), contextStack.getCurrentContext());
}
// we're done
throwEOF();
return null;
}
/**
*
*/
protected void throwEOF() throws EndOfFileException, OffsetLimitReachedException {
if( offsetLimit == NO_OFFSET_LIMIT )
throw new EndOfFileException();
if( finalToken.getEndOffset() == offsetLimit )
throw new OffsetLimitReachedException(finalToken);
throw new OffsetLimitReachedException( null );
}
static {
cppKeywords.put( Keywords.AND, new Integer(IToken.t_and));
cppKeywords.put( Keywords.AND_EQ, new Integer(IToken.t_and_eq));
cppKeywords.put( Keywords.ASM, new Integer(IToken.t_asm));
cppKeywords.put( Keywords.AUTO, new Integer(IToken.t_auto));
cppKeywords.put( Keywords.BITAND, new Integer(IToken.t_bitand));
cppKeywords.put( Keywords.BITOR, new Integer(IToken.t_bitor));
cppKeywords.put( Keywords.BOOL, new Integer(IToken.t_bool));
cppKeywords.put( Keywords.BREAK, new Integer(IToken.t_break));
cppKeywords.put( Keywords.CASE, new Integer(IToken.t_case));
cppKeywords.put( Keywords.CATCH, new Integer(IToken.t_catch));
cppKeywords.put( Keywords.CHAR, new Integer(IToken.t_char));
cppKeywords.put( Keywords.CLASS, new Integer(IToken.t_class));
cppKeywords.put( Keywords.COMPL, new Integer(IToken.t_compl));
cppKeywords.put( Keywords.CONST, new Integer(IToken.t_const));
cppKeywords.put( Keywords.CONST_CAST, new Integer(IToken.t_const_cast));
cppKeywords.put( Keywords.CONTINUE, new Integer(IToken.t_continue));
cppKeywords.put( Keywords.DEFAULT, new Integer(IToken.t_default));
cppKeywords.put( Keywords.DELETE, new Integer(IToken.t_delete));
cppKeywords.put( Keywords.DO, new Integer(IToken.t_do));
cppKeywords.put( Keywords.DOUBLE, new Integer(IToken.t_double));
cppKeywords.put( Keywords.DYNAMIC_CAST, new Integer(IToken.t_dynamic_cast));
cppKeywords.put( Keywords.ELSE, new Integer(IToken.t_else));
cppKeywords.put( Keywords.ENUM, new Integer(IToken.t_enum));
cppKeywords.put( Keywords.EXPLICIT, new Integer(IToken.t_explicit));
cppKeywords.put( Keywords.EXPORT, new Integer(IToken.t_export));
cppKeywords.put( Keywords.EXTERN, new Integer(IToken.t_extern));
cppKeywords.put( Keywords.FALSE, new Integer(IToken.t_false));
cppKeywords.put( Keywords.FLOAT, new Integer(IToken.t_float));
cppKeywords.put( Keywords.FOR, new Integer(IToken.t_for));
cppKeywords.put( Keywords.FRIEND, new Integer(IToken.t_friend));
cppKeywords.put( Keywords.GOTO, new Integer(IToken.t_goto));
cppKeywords.put( Keywords.IF, new Integer(IToken.t_if));
cppKeywords.put( Keywords.INLINE, new Integer(IToken.t_inline));
cppKeywords.put( Keywords.INT, new Integer(IToken.t_int));
cppKeywords.put( Keywords.LONG, new Integer(IToken.t_long));
cppKeywords.put( Keywords.MUTABLE, new Integer(IToken.t_mutable));
cppKeywords.put( Keywords.NAMESPACE, new Integer(IToken.t_namespace));
cppKeywords.put( Keywords.NEW, new Integer(IToken.t_new));
cppKeywords.put( Keywords.NOT, new Integer(IToken.t_not));
cppKeywords.put( Keywords.NOT_EQ, new Integer(IToken.t_not_eq));
cppKeywords.put( Keywords.OPERATOR, new Integer(IToken.t_operator));
cppKeywords.put( Keywords.OR, new Integer(IToken.t_or));
cppKeywords.put( Keywords.OR_EQ, new Integer(IToken.t_or_eq));
cppKeywords.put( Keywords.PRIVATE, new Integer(IToken.t_private));
cppKeywords.put( Keywords.PROTECTED, new Integer(IToken.t_protected));
cppKeywords.put( Keywords.PUBLIC, new Integer(IToken.t_public));
cppKeywords.put( Keywords.REGISTER, new Integer(IToken.t_register));
cppKeywords.put( Keywords.REINTERPRET_CAST, new Integer(IToken.t_reinterpret_cast));
cppKeywords.put( Keywords.RETURN, new Integer(IToken.t_return));
cppKeywords.put( Keywords.SHORT, new Integer(IToken.t_short));
cppKeywords.put( Keywords.SIGNED, new Integer(IToken.t_signed));
cppKeywords.put( Keywords.SIZEOF, new Integer(IToken.t_sizeof));
cppKeywords.put( Keywords.STATIC, new Integer(IToken.t_static));
cppKeywords.put( Keywords.STATIC_CAST, new Integer(IToken.t_static_cast));
cppKeywords.put( Keywords.STRUCT, new Integer(IToken.t_struct));
cppKeywords.put( Keywords.SWITCH, new Integer(IToken.t_switch));
cppKeywords.put( Keywords.TEMPLATE, new Integer(IToken.t_template));
cppKeywords.put( Keywords.THIS, new Integer(IToken.t_this));
cppKeywords.put( Keywords.THROW, new Integer(IToken.t_throw));
cppKeywords.put( Keywords.TRUE, new Integer(IToken.t_true));
cppKeywords.put( Keywords.TRY, new Integer(IToken.t_try));
cppKeywords.put( Keywords.TYPEDEF, new Integer(IToken.t_typedef));
cppKeywords.put( Keywords.TYPEID, new Integer(IToken.t_typeid));
cppKeywords.put( Keywords.TYPENAME, new Integer(IToken.t_typename));
cppKeywords.put( Keywords.UNION, new Integer(IToken.t_union));
cppKeywords.put( Keywords.UNSIGNED, new Integer(IToken.t_unsigned));
cppKeywords.put( Keywords.USING, new Integer(IToken.t_using));
cppKeywords.put( Keywords.VIRTUAL, new Integer(IToken.t_virtual));
cppKeywords.put( Keywords.VOID, new Integer(IToken.t_void));
cppKeywords.put( Keywords.VOLATILE, new Integer(IToken.t_volatile));
cppKeywords.put( Keywords.WCHAR_T, new Integer(IToken.t_wchar_t));
cppKeywords.put( Keywords.WHILE, new Integer(IToken.t_while));
cppKeywords.put( Keywords.XOR, new Integer(IToken.t_xor));
cppKeywords.put( Keywords.XOR_EQ, new Integer(IToken.t_xor_eq));
ppDirectives.put("#define", new Integer(PreprocessorDirectives.DEFINE));
ppDirectives.put("#undef",new Integer(PreprocessorDirectives.UNDEFINE));
ppDirectives.put("#if", new Integer(PreprocessorDirectives.IF));
ppDirectives.put("#ifdef", new Integer(PreprocessorDirectives.IFDEF));
ppDirectives.put("#ifndef", new Integer(PreprocessorDirectives.IFNDEF));
ppDirectives.put("#else", new Integer(PreprocessorDirectives.ELSE));
ppDirectives.put("#endif", new Integer(PreprocessorDirectives.ENDIF));
ppDirectives.put(
"#include",
new Integer(PreprocessorDirectives.INCLUDE));
ppDirectives.put("#line", new Integer(PreprocessorDirectives.LINE));
ppDirectives.put("#error", new Integer(PreprocessorDirectives.ERROR));
ppDirectives.put("#pragma", new Integer(PreprocessorDirectives.PRAGMA));
ppDirectives.put("#elif", new Integer(PreprocessorDirectives.ELIF));
ppDirectives.put("#", new Integer(PreprocessorDirectives.BLANK));
cKeywords.put( Keywords.AUTO, new Integer(IToken.t_auto));
cKeywords.put( Keywords.BREAK, new Integer(IToken.t_break));
cKeywords.put( Keywords.CASE, new Integer(IToken.t_case));
cKeywords.put( Keywords.CHAR, new Integer(IToken.t_char));
cKeywords.put( Keywords.CONST, new Integer(IToken.t_const));
cKeywords.put( Keywords.CONTINUE, new Integer(IToken.t_continue));
cKeywords.put( Keywords.DEFAULT, new Integer(IToken.t_default));
cKeywords.put( Keywords.DELETE, new Integer(IToken.t_delete));
cKeywords.put( Keywords.DO, new Integer(IToken.t_do));
cKeywords.put( Keywords.DOUBLE, new Integer(IToken.t_double));
cKeywords.put( Keywords.ELSE, new Integer(IToken.t_else));
cKeywords.put( Keywords.ENUM, new Integer(IToken.t_enum));
cKeywords.put( Keywords.EXTERN, new Integer(IToken.t_extern));
cKeywords.put( Keywords.FLOAT, new Integer(IToken.t_float));
cKeywords.put( Keywords.FOR, new Integer(IToken.t_for));
cKeywords.put( Keywords.GOTO, new Integer(IToken.t_goto));
cKeywords.put( Keywords.IF, new Integer(IToken.t_if));
cKeywords.put( Keywords.INLINE, new Integer(IToken.t_inline));
cKeywords.put( Keywords.INT, new Integer(IToken.t_int));
cKeywords.put( Keywords.LONG, new Integer(IToken.t_long));
cKeywords.put( Keywords.REGISTER, new Integer(IToken.t_register));
cKeywords.put( Keywords.RESTRICT, new Integer(IToken.t_restrict));
cKeywords.put( Keywords.RETURN, new Integer(IToken.t_return));
cKeywords.put( Keywords.SHORT, new Integer(IToken.t_short));
cKeywords.put( Keywords.SIGNED, new Integer(IToken.t_signed));
cKeywords.put( Keywords.SIZEOF, new Integer(IToken.t_sizeof));
cKeywords.put( Keywords.STATIC, new Integer(IToken.t_static));
cKeywords.put( Keywords.STRUCT, new Integer(IToken.t_struct));
cKeywords.put( Keywords.SWITCH, new Integer(IToken.t_switch));
cKeywords.put( Keywords.TYPEDEF, new Integer(IToken.t_typedef));
cKeywords.put( Keywords.UNION, new Integer(IToken.t_union));
cKeywords.put( Keywords.UNSIGNED, new Integer(IToken.t_unsigned));
cKeywords.put( Keywords.VOID, new Integer(IToken.t_void));
cKeywords.put( Keywords.VOLATILE, new Integer(IToken.t_volatile));
cKeywords.put( Keywords.WHILE, new Integer(IToken.t_while));
cKeywords.put( Keywords._BOOL, new Integer(IToken.t__Bool));
cKeywords.put( Keywords._COMPLEX, new Integer(IToken.t__Complex));
cKeywords.put( Keywords._IMAGINARY, new Integer(IToken.t__Imaginary));
}
static public class PreprocessorDirectives {
static public final int DEFINE = 0;
static public final int UNDEFINE = 1;
static public final int IF = 2;
static public final int IFDEF = 3;
static public final int IFNDEF = 4;
static public final int ELSE = 5;
static public final int ENDIF = 6;
static public final int INCLUDE = 7;
static public final int LINE = 8;
static public final int ERROR = 9;
static public final int PRAGMA = 10;
static public final int BLANK = 11;
static public final int ELIF = 12;
}
public final int getCount() {
return count;
}
public final int getDepth() {
return branches.getDepth();
}
protected boolean evaluateExpression(String expression, int beginningOffset )
throws ScannerException {
if( mode == ParserMode.QUICK_PARSE )
{
if( expression.trim().equals( "0" ) )
return false;
return true;
}
else
{
final NullSourceElementRequestor nullCallback = new NullSourceElementRequestor();
IParser parser = null;
try
{
IScanner trial =
ParserFactory.createScanner(
new StringReader(expression + ";"),
EXPRESSION,
new ScannerInfo( definitions, originalConfig.getIncludePaths()),
ParserMode.QUICK_PARSE, language, nullCallback, log );
parser = ParserFactory.createParser(trial, nullCallback, ParserMode.QUICK_PARSE, language, log );
} catch( ParserFactoryException pfe )
{
handleInternalError();
}
try {
IASTExpression exp = parser.expression(null);
if( exp.evaluateExpression() == 0 )
return false;
return true;
} catch( BacktrackException backtrack )
{
handleProblem( IProblem.PREPROCESSOR_CONDITIONAL_EVAL_ERROR, expression, beginningOffset, false, true, true );
}
catch (ExpressionEvaluationException e) {
handleProblem( IProblem.PREPROCESSOR_CONDITIONAL_EVAL_ERROR, expression, beginningOffset, false, true, true );
} catch (EndOfFileException e) {
handleProblem( IProblem.PREPROCESSOR_CONDITIONAL_EVAL_ERROR, expression, beginningOffset, false, true, true );
}
return true;
}
}
protected void skipOverSinglelineComment() throws ScannerException {
StringBuffer comment = new StringBuffer("//");
int c;
loop:
for (;;) {
c = getChar();
comment.append((char)c);
switch (c) {
case NOCHAR :
case '\n' :
break loop;
default :
break;
}
}
}
protected boolean skipOverMultilineComment() throws ScannerException {
int state = 0;
boolean encounteredNewline = false;
StringBuffer comment = new StringBuffer("/*");
// simple state machine to handle multi-line comments
// state 0 == no end of comment in site
// state 1 == encountered *, expecting /
// state 2 == we are no longer in a comment
int c = getChar();
comment.append((char)c);
while (state != 2 && c != NOCHAR) {
if (c == '\n')
encounteredNewline = true;
switch (state) {
case 0 :
if (c == '*')
state = 1;
break;
case 1 :
if (c == '/')
state = 2;
else if (c != '*')
state = 0;
break;
}
c = getChar();
comment.append((char)c);
}
if (c == NOCHAR)
handleProblem( IProblem.SCANNER_UNEXPECTED_EOF, null, getCurrentOffset(), false, true, true );
ungetChar(c);
return encounteredNewline;
}
protected void poundInclude( int beginningOffset ) throws ScannerException {
skipOverWhitespace();
int baseOffset = lastContext.getOffset() - lastContext.undoStackSize();
String includeLine = getRestOfPreprocessorLine();
StringBuffer fileName = new StringBuffer();
boolean useIncludePath = true;
int startOffset = baseOffset;
int endOffset = baseOffset;
if (! includeLine.equals("")) {
Scanner helperScanner = new Scanner(
new StringReader(includeLine),
null,
new ScannerInfo(definitions, originalConfig.getIncludePaths()),
new NullSourceElementRequestor(),
mode,
language, log );
helperScanner.setForInclusion( true );
IToken t = null;
try {
t = helperScanner.nextToken(false);
} catch (OffsetLimitReachedException e) {
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#include " + includeLine, beginningOffset, false, true, true );
return;
} catch (EndOfFileException eof) {
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#include " + includeLine, beginningOffset, false, true, true );
return;
}
try {
if (t.getType() == IToken.tSTRING) {
fileName.append(t.getImage());
startOffset = baseOffset + t.getOffset();
endOffset = baseOffset + t.getEndOffset();
useIncludePath = false;
// This should throw EOF
t = helperScanner.nextToken(false);
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#include " + includeLine, beginningOffset, false, true, true );
return;
} else if (t.getType() == IToken.tLT) {
try {
t = helperScanner.nextToken(false);
startOffset = baseOffset + t.getOffset();
while (t.getType() != IToken.tGT) {
fileName.append(t.getImage());
helperScanner.skipOverWhitespace();
int c = helperScanner.getChar();
if (c == '\\') fileName.append('\\'); else helperScanner.ungetChar(c);
t = helperScanner.nextToken(false);
}
endOffset = baseOffset + t.getEndOffset();
} catch (EndOfFileException eof) {
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#include " + includeLine, beginningOffset, false, true, true );
return;
}
// This should throw EOF
t = helperScanner.nextToken(false);
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#include " + includeLine, beginningOffset, false, true, true );
return;
} else
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#include " + includeLine, beginningOffset, false, true, true );
}
catch (OffsetLimitReachedException e) {
handleInternalError();
}
catch( EndOfFileException eof )
{
// good
}
} else
handleProblem( IProblem.PREPROCESSOR_INVALID_DIRECTIVE, "#include " + includeLine, beginningOffset, false, true, true );
String f = fileName.toString();
if( mode == ParserMode.QUICK_PARSE )
{
if( requestor != null )
{
IASTInclusion i = null;
try
{
i =
astFactory.createInclusion(
f,
"",
!useIncludePath,
beginningOffset,
startOffset,
startOffset + f.length(),
endOffset);
}
catch (Exception e)
{
/* do nothing */
}
if( i != null )
{
i.enterScope( requestor );
i.exitScope( requestor );
}
}
}
else
handleInclusion(f.trim(), useIncludePath, startOffset, beginningOffset, endOffset);
}
protected static final Hashtable emptyMap = new Hashtable();
protected Hashtable holderMap = null;
protected void temporarilyReplaceDefinitionsMap()
{
holderMap = definitions;
definitions = emptyMap;
}
protected void restoreDefinitionsMap()
{
definitions = holderMap;
holderMap = null;
}
protected boolean forInclusion = false;
/**
* @param b
*/
protected void setForInclusion(boolean b)
{
forInclusion = b;
}
protected void poundDefine(int beginning) throws ScannerException, EndOfFileException {
skipOverWhitespace();
// definition
String key = getNextIdentifier();
int offset = contextStack.getCurrentContext().getOffset() - key.length() - contextStack.getCurrentContext().undoStackSize();
// store the previous definition to check against later
Object previousDefinition = definitions.get( key );
// get the next character
// the C++ standard says that macros must not put
// whitespace between the end of the definition
// identifier and the opening parenthesis
int c = getChar();
if (c == '(') {
StringBuffer buffer = new StringBuffer();
c = getChar(true);
while (c != ')') {
if( c == '\\' ){
c = getChar();
if( c == '\r' )
c = getChar();
if( c == '\n' ){
c = getChar();
continue;
} else {
ungetChar( c );
handleProblem( IProblem.PREPROCESSOR_INVALID_MACRO_DEFN, "#define " + buffer.toString() + '\\' + (char)c, beginning, false, true, true );
return;
}
} else if( c == '\r' || c == '\n' ){
handleProblem( IProblem.PREPROCESSOR_INVALID_MACRO_DEFN, "#define " + buffer.toString() + (char)c, beginning, false, true, true );
return;
} else if( c == NOCHAR ){
handleProblem( IProblem.SCANNER_UNEXPECTED_EOF, null, beginning, false, true, true );
return;
}
buffer.append((char) c);
c = getChar(true);
}
String parameters = buffer.toString();
// replace StringTokenizer later -- not performant
StringTokenizer tokenizer = new StringTokenizer(parameters, ",");
ArrayList parameterIdentifiers =
new ArrayList(tokenizer.countTokens());
while (tokenizer.hasMoreTokens()) {
parameterIdentifiers.add(tokenizer.nextToken().trim());
}
skipOverWhitespace();
ArrayList macroReplacementTokens = new ArrayList();
String replacementString = getRestOfPreprocessorLine();
if( ! replacementString.equals( "" ) )
{
IScanner helperScanner=null;
try {
helperScanner =
ParserFactory.createScanner(
new StringReader(replacementString),
SCRATCH,
new ScannerInfo(),
mode,
language,
new NullSourceElementRequestor(), log);
} catch (ParserFactoryException e1) {
}
helperScanner.setTokenizingMacroReplacementList( true );
IToken t = null;
try {
t = helperScanner.nextToken(false);
} catch (OffsetLimitReachedException e2) {
handleInternalError();
}
try {
while (true) {
//each # preprocessing token in the replacement list shall be followed
//by a parameter as the next reprocessing token in the list
if( t.getType() == tPOUND ){
macroReplacementTokens.add( t );
t = helperScanner.nextToken(false);
int index = parameterIdentifiers.indexOf(t.getImage());
if (index == -1 ) {
//not found
handleProblem( IProblem.PREPROCESSOR_MACRO_PASTING_ERROR, "#define " + key + " " + replacementString,
beginning, false, true, true );
return;
}
}
macroReplacementTokens.add(t);
t = helperScanner.nextToken(false);
}
}
catch( OffsetLimitReachedException olre )
{
handleInternalError();
}
catch( EndOfFileException eof )
{
// good
}
}
IMacroDescriptor descriptor = new MacroDescriptor();
descriptor.initialize(
key,
parameterIdentifiers,
macroReplacementTokens,
key + "(" + parameters + ")");
checkValidMacroRedefinition(key, previousDefinition, descriptor, beginning);
addDefinition(key, descriptor);
}
else if ((c == '\n') || (c == '\r'))
{
checkValidMacroRedefinition(key, previousDefinition, "", beginning);
addDefinition( key, "" );
}
else if ((c == ' ') || (c == '\t') ) {
// this is a simple definition
skipOverWhitespace();
// get what we are to map the name to and add it to the definitions list
String value = getRestOfPreprocessorLine();
checkValidMacroRedefinition(key, previousDefinition, value, beginning);
addDefinition( key, value );
} else if (c == '/') {
// this could be a comment
c = getChar();
if (c == '/') // one line comment
{
skipOverSinglelineComment();
checkValidMacroRedefinition(key, previousDefinition, "", beginning);
addDefinition(key, "");
} else if (c == '*') // multi-line comment
{
if (skipOverMultilineComment()) {
// we have gone over a newline
// therefore, this symbol was defined to an empty string
checkValidMacroRedefinition(key, previousDefinition, "", beginning);
addDefinition(key, "");
} else {
String value = getRestOfPreprocessorLine();
checkValidMacroRedefinition(key, previousDefinition, "", beginning);
addDefinition(key, value);
}
} else {
// this is not a comment
// it is a bad statement
handleProblem( IProblem.PREPROCESSOR_INVALID_MACRO_DEFN, "#define " + key + " /" + getRestOfPreprocessorLine(), beginning, false, true, true );
return;
}
} else {
log.traceLog("Scanner : Encountered unexpected character " + ((char) c));
handleProblem( IProblem.PREPROCESSOR_INVALID_MACRO_DEFN, "#define " + key + (char)c + getRestOfPreprocessorLine(), beginning, false, true, true );
return;
}
try
{
astFactory.createMacro( key, beginning, offset, offset + key.length(), contextStack.getCurrentContext().getOffset() ).acceptElement( requestor );
}
catch (Exception e)
{
/* do nothing */
}
}
protected void checkValidMacroRedefinition(
String key,
Object previousDefinition,
Object newDefinition, int beginningOffset )
throws ScannerException
{
if( mode != ParserMode.QUICK_PARSE && previousDefinition != null )
{
if( newDefinition instanceof IMacroDescriptor )
{
if( previousDefinition instanceof IMacroDescriptor )
{
if( ((IMacroDescriptor)previousDefinition).compatible( (IMacroDescriptor) newDefinition ) )
return;
}
}
else if( newDefinition instanceof String )
{
if( previousDefinition instanceof String )
{
Scanner previous = new Scanner( new StringReader( (String)previousDefinition ), "redef-test", new ScannerInfo(), new NullSourceElementRequestor(),
mode, language, log );
Scanner current = new Scanner( new StringReader( (String)newDefinition ), "redef-test", new ScannerInfo(), new NullSourceElementRequestor(),
mode, language, log );
for ( ; ; )
{
IToken p = null;
IToken c = null;
try
{
p = previous.nextToken();
c = current.nextToken();
if ( c.equals( p ) ) continue;
break;
}
catch( OffsetLimitReachedException olre )
{
handleInternalError();
}
catch( EndOfFileException eof )
{
if( ( p != null ) && ( c == null ) )
break;
if( p == null )
{
try
{
c = current.nextToken();
break;
}
catch( OffsetLimitReachedException olre )
{
handleInternalError();
}
catch( EndOfFileException eof2 )
{
return;
}
}
}
}
}
}
handleProblem( IProblem.PREPROCESSOR_INVALID_MACRO_REDEFN, key, beginningOffset, false, true, true );
}
}
/**
*
*/
protected void handleInternalError() {
// TODO Auto-generated method stub
}
protected Vector getMacroParameters (String params, boolean forStringizing) throws ScannerException {
Scanner tokenizer = new Scanner(new StringReader(params), TEXT, new ScannerInfo( definitions, originalConfig.getIncludePaths() ), new NullSourceElementRequestor(), mode, language, log);
tokenizer.setThrowExceptionOnBadCharacterRead(false);
Vector parameterValues = new Vector();
Token t = null;
String str = new String();
boolean space = false;
int nParen = 0;
try {
while (true) {
int c = tokenizer.getCharacter();
if ((c != ' ') && (c != '\t') && (c != '\r') && (c != '\n')) {
space = false;
}
if (c != NOCHAR) tokenizer.ungetChar(c);
t = (Token)(forStringizing ? tokenizer.nextTokenForStringizing() : tokenizer.nextToken(false));
if (t.type == IToken.tLPAREN) {
nParen++;
} else if (t.type == IToken.tRPAREN) {
nParen--;
} else if (t.type == IToken.tCOMMA && nParen == 0) {
parameterValues.add(str);
str = "";
space = false;
continue;
}
if (space)
str += ' ';
switch (t.type) {
case IToken.tSTRING : str += '\"' + t.image + '\"'; break;
case IToken.tLSTRING : str += "L\"" + t.image + '\"'; break;
case IToken.tCHAR : str += '\'' + t.image + '\''; break;
default : str += t.image; break;
}
space = true;
}
}
catch( OffsetLimitReachedException olre )
{
handleInternalError();
}
catch (EndOfFileException e) {
// Good
parameterValues.add(str);
}
return parameterValues;
}
protected void expandDefinition(String symbol, Object expansion, int symbolOffset)
throws ScannerException
{
// All the tokens generated by the macro expansion
// will have dimensions (offset and length) equal to the expanding symbol.
if (expansion instanceof String ) {
String replacementValue = (String) expansion;
try
{
contextStack.updateContext( new StringReader(replacementValue), (POUND_DEFINE + symbol ), ScannerContext.ContextKind.MACROEXPANSION, null, requestor, symbolOffset, symbol.length());
}
catch (ContextException e)
{
handleProblem( e.getId(), contextStack.getCurrentContext().getFilename(), getCurrentOffset(), false, true, true );
consumeUntilOutOfMacroExpansion();
return;
}
} else if (expansion instanceof IMacroDescriptor ) {
IMacroDescriptor macro = (IMacroDescriptor) expansion;
skipOverWhitespace();
int c = getChar();
if (c == '(') {
StringBuffer buffer = new StringBuffer();
int bracketCount = 1;
c = getChar();
while (true) {
if (c == '(')
++bracketCount;
else if (c == ')')
--bracketCount;
if(bracketCount == 0 || c == NOCHAR)
break;
buffer.append((char) c);
c = getChar( true );
}
// Position of the closing ')'
int endMacroOffset = lastContext.getOffset() - lastContext.undoStackSize() - 1;
String betweenTheBrackets = buffer.toString().trim();
Vector parameterValues = getMacroParameters(betweenTheBrackets, false);
Vector parameterValuesForStringizing = getMacroParameters(betweenTheBrackets, true);
Token t = null;
// create a string that represents what needs to be tokenized
buffer = new StringBuffer();
List tokens = macro.getTokenizedExpansion();
List parameterNames = macro.getParameters();
if (parameterNames.size() != parameterValues.size())
{
handleProblem( IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, symbol, getCurrentOffset(), false, true, true );
consumeUntilOutOfMacroExpansion();
return;
}
int numberOfTokens = tokens.size();
for (int i = 0; i < numberOfTokens; ++i) {
t = (Token) tokens.get(i);
if (t.type == IToken.tIDENTIFIER) {
// is this identifier in the parameterNames
// list?
int index = parameterNames.indexOf(t.image);
if (index == -1 ) {
// not found
// just add image to buffer
buffer.append(t.image );
} else {
buffer.append(
(String) parameterValues.elementAt(index) );
}
} else if (t.type == tPOUND) {
//next token should be a parameter which needs to be turned into
//a string literal
t = (Token) tokens.get( ++i );
int index = parameterNames.indexOf(t.image);
if( index == -1 ){
handleProblem( IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, macro.getName(), getCurrentOffset(), false, true, true );
return;
} else {
buffer.append('\"');
String value = (String)parameterValuesForStringizing.elementAt(index);
char val [] = value.toCharArray();
char ch;
int length = value.length();
for( int j = 0; j < length; j++ ){
ch = val[j];
if( ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' ){
//Each occurance of whitespace becomes a single space character
while( ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' ){
ch = val[++j];
}
buffer.append(' ');
}
//a \ character is inserted before each " and \
if( ch == '\"' || ch == '\\' ){
buffer.append('\\');
buffer.append(ch);
} else {
buffer.append(ch);
}
}
buffer.append('\"');
}
} else {
switch( t.type )
{
case IToken.tSTRING: buffer.append('\"' + t.image + '\"'); break;
case IToken.tLSTRING: buffer.append("L\"" + t.image + '\"'); break;
case IToken.tCHAR: buffer.append('\'' + t.image + '\''); break;
default: buffer.append(t.image); break;
}
}
boolean pastingNext = false;
if( i != numberOfTokens - 1)
{
IToken t2 = (IToken) tokens.get(i+1);
if( t2.getType() == tPOUNDPOUND ) {
pastingNext = true;
i++;
}
}
if( t.getType() != tPOUNDPOUND && ! pastingNext )
if (i < (numberOfTokens-1)) // Do not append to the last one
buffer.append( " " );
}
String finalString = buffer.toString();
try
{
contextStack.updateContext(
new StringReader(finalString),
POUND_DEFINE + macro.getSignature(), ScannerContext.ContextKind.MACROEXPANSION, null, requestor, symbolOffset, endMacroOffset - symbolOffset + 1 );
}
catch (ContextException e)
{
handleProblem( e.getId(), contextStack.getCurrentContext().getFilename(), getCurrentOffset(), false, true, true );
consumeUntilOutOfMacroExpansion();
return;
}
} else
{
handleProblem( IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, symbol, getCurrentOffset(), false, true, true );
consumeUntilOutOfMacroExpansion();
return;
}
} else {
log.traceLog(
"Unexpected class stored in definitions table. "
+ expansion.getClass().getName() );
}
}
protected String handleDefinedMacro() throws ScannerException {
int o = getCurrentOffset();
skipOverWhitespace();
int c = getChar();
String definitionIdentifier = null;
if (c == '(') {
definitionIdentifier = getNextIdentifier();
skipOverWhitespace();
c = getChar();
if (c != ')')
{
handleProblem( IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, "defined()", o, false, true, true);
return "0";
}
}
else
{
ungetChar(c);
definitionIdentifier = getNextIdentifier();
}
if (definitions.get(definitionIdentifier) != null)
return "1";
return "0";
}
private ParserLanguage language = ParserLanguage.CPP;
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.parser.IScanner#setCppNature(boolean)
*/
public void setLanguage( ParserLanguage value) {
language = value;
}
public void setThrowExceptionOnBadCharacterRead( boolean throwOnBad ){
throwExceptionOnBadCharacterRead = throwOnBad;
}
private final ISourceElementRequestor requestor;
private IASTFactory astFactory = null;
private static final int NO_OFFSET_LIMIT = -1;
private int offsetLimit = NO_OFFSET_LIMIT;
/* (non-Javadoc)
* @see org.eclipse.cdt.core.parser.IScanner#setASTFactory(org.eclipse.cdt.internal.core.parser.ast.IASTFactory)
*/
public void setASTFactory(IASTFactory f) {
astFactory = f;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.parser.IScanner#getLineNumberForOffset(int)
*/
public int getLineNumberForOffset(int i)
{
ILineOffsetReconciler reconciler = ParserFactory.createLineOffsetReconciler( backupReader );
return reconciler.getLineNumberForOffset(i);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.parser.IScanner#setOffsetBoundary(int)
*/
public void setOffsetBoundary(int offset) {
offsetLimit = offset;
}
}