mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Patch for Andrew Niefer:
- Fixed Bug36316 Parser/Scanner in infinite loop
This commit is contained in:
parent
080e040924
commit
0c47e3bed5
5 changed files with 299 additions and 177 deletions
|
@ -0,0 +1,130 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2003 IBM Corporation 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:
|
||||
* IBM Corp. - Rational Software - initial implementation
|
||||
******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.core.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* @author aniefer
|
||||
*
|
||||
* To change the template for this generated type comment go to
|
||||
* Window>Preferences>Java>Code Generation>Code and Comments
|
||||
*/
|
||||
public class ContextStack {
|
||||
|
||||
public ContextStack(){
|
||||
super();
|
||||
}
|
||||
|
||||
public void updateContext(Reader reader, String filename, int type) throws ScannerException {
|
||||
undoStack.clear();
|
||||
|
||||
push( new ScannerContext().initialize(reader, filename, type ) );
|
||||
}
|
||||
|
||||
protected void push( IScannerContext context ) throws ScannerException
|
||||
{
|
||||
if( context.getKind() == IScannerContext.INCLUSION )
|
||||
{
|
||||
if( !inclusions.add( context.getFilename() ) )
|
||||
throw new ScannerException( "Inclusion " + context.getFilename() + " already encountered." );
|
||||
} else if( context.getKind() == IScannerContext.MACROEXPANSION )
|
||||
{
|
||||
if( !defines.add( context.getFilename() ) )
|
||||
throw new ScannerException( "Define " + context.getFilename() + " already encountered." );
|
||||
}
|
||||
if( currentContext != null )
|
||||
contextStack.push(currentContext);
|
||||
|
||||
currentContext = context;
|
||||
}
|
||||
|
||||
public boolean rollbackContext() {
|
||||
try {
|
||||
currentContext.getReader().close();
|
||||
} catch (IOException ie) {
|
||||
System.out.println("Error closing reader");
|
||||
}
|
||||
|
||||
if( currentContext.getKind() == IScannerContext.INCLUSION )
|
||||
{
|
||||
inclusions.remove( currentContext.getFilename() );
|
||||
} else if( currentContext.getKind() == IScannerContext.MACROEXPANSION )
|
||||
{
|
||||
defines.remove( currentContext.getFilename() );
|
||||
}
|
||||
|
||||
undoStack.addFirst( currentContext );
|
||||
|
||||
if (contextStack.isEmpty()) {
|
||||
currentContext = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
currentContext = (ScannerContext) contextStack.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void undoRollback( IScannerContext undoTo ) throws ScannerException {
|
||||
if( currentContext == undoTo ){
|
||||
return;
|
||||
}
|
||||
|
||||
int size = undoStack.size();
|
||||
if( size > 0 )
|
||||
{
|
||||
Iterator iter = undoStack.iterator();
|
||||
for( int i = size; i > 0; i-- )
|
||||
{
|
||||
push( (IScannerContext) undoStack.removeFirst() );
|
||||
|
||||
if( currentContext == undoTo )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param symbol
|
||||
* @return boolean, whether or not we should expand this definition
|
||||
*
|
||||
* 16.3.4-2 If the name of the macro being replaced is found during
|
||||
* this scan of the replacement list it is not replaced. Further, if
|
||||
* any nested replacements encounter the name of the macro being replaced,
|
||||
* it is not replaced.
|
||||
*/
|
||||
protected boolean shouldExpandDefinition( String symbol )
|
||||
{
|
||||
return !defines.contains( symbol );
|
||||
}
|
||||
|
||||
public IScannerContext getCurrentContext(){
|
||||
return currentContext;
|
||||
}
|
||||
|
||||
private IScannerContext currentContext;
|
||||
|
||||
private Stack contextStack = new Stack();
|
||||
private LinkedList undoStack = new LinkedList();
|
||||
|
||||
|
||||
private Set inclusions = new HashSet();
|
||||
private Set defines = new HashSet();
|
||||
|
||||
}
|
|
@ -18,12 +18,9 @@ import java.io.Reader;
|
|||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
|
||||
|
@ -40,18 +37,21 @@ public class Scanner implements IScanner {
|
|||
}
|
||||
|
||||
protected void init(Reader reader, String filename) {
|
||||
// this is a hack to get around a sudden EOF experience
|
||||
contextStack.push(
|
||||
new ScannerContext().initialize(
|
||||
new StringReader("\n"),
|
||||
START,
|
||||
ScannerContext.SENTINEL));
|
||||
if (filename == null)
|
||||
currentContext =
|
||||
new ScannerContext().initialize(reader, TEXT, ScannerContext.TOP );
|
||||
else
|
||||
currentContext =
|
||||
new ScannerContext().initialize(reader, filename, ScannerContext.TOP );
|
||||
try {
|
||||
//this is a hack to get around a sudden EOF experience
|
||||
contextStack.push(
|
||||
new ScannerContext().initialize(
|
||||
new StringReader("\n"),
|
||||
START,
|
||||
ScannerContext.SENTINEL));
|
||||
|
||||
if (filename == null)
|
||||
contextStack.push( new ScannerContext().initialize(reader, TEXT, ScannerContext.TOP ) );
|
||||
else
|
||||
contextStack.push( new ScannerContext().initialize(reader, filename, ScannerContext.TOP ) );
|
||||
} catch( ScannerException se ) {
|
||||
//won't happen since we aren't adding an include or a macro
|
||||
}
|
||||
}
|
||||
|
||||
public Scanner() {
|
||||
|
@ -62,42 +62,7 @@ public class Scanner implements IScanner {
|
|||
definitions = defns;
|
||||
}
|
||||
|
||||
protected void updateContext(Reader reader, String filename, int type) throws ScannerException {
|
||||
if( type == IScannerContext.INCLUSION )
|
||||
{
|
||||
if( !inclusions.add( filename ) )
|
||||
throw new ScannerException( "Inclusion " + filename + " already encountered." );
|
||||
|
||||
System.out.println( "Handle inclusion - " + filename );
|
||||
}
|
||||
|
||||
contextStack.push(currentContext);
|
||||
currentContext =
|
||||
new ScannerContext().initialize(reader, filename, type );
|
||||
|
||||
}
|
||||
|
||||
protected boolean rollbackContext() {
|
||||
try {
|
||||
currentContext.getReader().close();
|
||||
} catch (IOException ie) {
|
||||
System.out.println("Error closing reader");
|
||||
}
|
||||
|
||||
if( currentContext.getKind() == IScannerContext.INCLUSION )
|
||||
{
|
||||
inclusions.remove( currentContext.getFilename() );
|
||||
System.out.println( "Completed inclusion - " + currentContext.getFilename() );
|
||||
}
|
||||
|
||||
if (contextStack.isEmpty()) {
|
||||
currentContext = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
currentContext = (ScannerContext) contextStack.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addIncludePath(String includePath) {
|
||||
includePathNames.add(includePath);
|
||||
|
@ -137,7 +102,7 @@ public class Scanner implements IScanner {
|
|||
return includePathNames.toArray();
|
||||
}
|
||||
|
||||
protected boolean skipOverWhitespace() {
|
||||
protected boolean skipOverWhitespace() throws ScannerException {
|
||||
int c = getChar();
|
||||
boolean result = false;
|
||||
while ((c != NOCHAR) && ((c == ' ') || (c == '\t')))
|
||||
|
@ -233,7 +198,7 @@ public class Scanner implements IScanner {
|
|||
return currentToken;
|
||||
}
|
||||
|
||||
protected String getNextIdentifier() {
|
||||
protected String getNextIdentifier() throws ScannerException {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
skipOverWhitespace();
|
||||
int c = getChar();
|
||||
|
@ -275,7 +240,7 @@ public class Scanner implements IScanner {
|
|||
try {
|
||||
FileReader inclusionReader =
|
||||
new FileReader(includeFile);
|
||||
updateContext(inclusionReader, newPath, ScannerContext.INCLUSION );
|
||||
contextStack.updateContext(inclusionReader, newPath, ScannerContext.INCLUSION );
|
||||
return;
|
||||
} catch (FileNotFoundException fnf) {
|
||||
// do nothing - check the next directory
|
||||
|
@ -286,7 +251,7 @@ public class Scanner implements IScanner {
|
|||
}
|
||||
else // local inclusion
|
||||
{
|
||||
String currentFilename = currentContext.getFilename();
|
||||
String currentFilename = contextStack.getCurrentContext().getFilename();
|
||||
File currentIncludeFile = new File( currentFilename );
|
||||
String parentDirectory = currentIncludeFile.getParent();
|
||||
currentIncludeFile = null;
|
||||
|
@ -296,7 +261,7 @@ public class Scanner implements IScanner {
|
|||
try {
|
||||
FileReader inclusionReader =
|
||||
new FileReader(includeFile);
|
||||
updateContext(inclusionReader, fullPath, ScannerContext.INCLUSION );
|
||||
contextStack.updateContext(inclusionReader, fullPath, ScannerContext.INCLUSION );
|
||||
return;
|
||||
} catch (FileNotFoundException fnf) {
|
||||
if (throwExceptionOnInclusionNotFound)
|
||||
|
@ -321,14 +286,14 @@ public class Scanner implements IScanner {
|
|||
private static final String DEFINED = "defined";
|
||||
private static final String POUND_DEFINE = "#define ";
|
||||
|
||||
private IScannerContext currentContext;
|
||||
private Stack contextStack = new Stack();
|
||||
|
||||
private ContextStack contextStack = new ContextStack();
|
||||
private IScannerContext lastContext = null;
|
||||
|
||||
private List includePathNames = new ArrayList();
|
||||
private List includePaths = new ArrayList();
|
||||
private Hashtable definitions = new Hashtable();
|
||||
private StringBuffer storageBuffer = null;
|
||||
private Set inclusions = new HashSet();
|
||||
|
||||
private int count = 0;
|
||||
private static HashMap keywords = new HashMap();
|
||||
private static HashMap ppDirectives = new HashMap();
|
||||
|
@ -367,7 +332,10 @@ public class Scanner implements IScanner {
|
|||
|
||||
private int getChar( boolean insideString ) {
|
||||
int c = NOCHAR;
|
||||
if (currentContext == null)
|
||||
|
||||
lastContext = contextStack.getCurrentContext();
|
||||
|
||||
if (contextStack.getCurrentContext() == null)
|
||||
// past the end of file
|
||||
return c;
|
||||
|
||||
|
@ -375,13 +343,13 @@ public class Scanner implements IScanner {
|
|||
do {
|
||||
done = true;
|
||||
|
||||
if (currentContext.undoStackSize() != 0 ) {
|
||||
c = currentContext.popUndo();
|
||||
if (contextStack.getCurrentContext().undoStackSize() != 0 ) {
|
||||
c = contextStack.getCurrentContext().popUndo();
|
||||
} else {
|
||||
try {
|
||||
c = currentContext.read();
|
||||
c = contextStack.getCurrentContext().read();
|
||||
if (c == NOCHAR) {
|
||||
if (rollbackContext() == false) {
|
||||
if (contextStack.rollbackContext() == false) {
|
||||
c = NOCHAR;
|
||||
break;
|
||||
} else {
|
||||
|
@ -389,7 +357,7 @@ public class Scanner implements IScanner {
|
|||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (rollbackContext() == false) {
|
||||
if (contextStack.rollbackContext() == false) {
|
||||
c = NOCHAR;
|
||||
} else {
|
||||
done = false;
|
||||
|
@ -413,13 +381,14 @@ public class Scanner implements IScanner {
|
|||
return c;
|
||||
}
|
||||
|
||||
private void ungetChar(int c) {
|
||||
private void ungetChar(int c) throws ScannerException{
|
||||
// Should really check whether there already is a char there
|
||||
// If so, we should be using a buffer, instead of a single char
|
||||
currentContext.pushUndo(c);
|
||||
contextStack.getCurrentContext().pushUndo(c);
|
||||
contextStack.undoRollback( lastContext );
|
||||
}
|
||||
|
||||
protected boolean lookAheadForTokenPasting()
|
||||
protected boolean lookAheadForTokenPasting() throws ScannerException
|
||||
{
|
||||
int c = getChar();
|
||||
if( c == '#' )
|
||||
|
@ -526,7 +495,7 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
type,
|
||||
buff.toString(),
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
|
||||
} else {
|
||||
if (throwExceptionOnUnboundedString)
|
||||
|
@ -563,9 +532,11 @@ public class Scanner implements IScanner {
|
|||
Object mapping = definitions.get(ident);
|
||||
|
||||
if (mapping != null) {
|
||||
expandDefinition(ident, mapping);
|
||||
c = getChar();
|
||||
continue;
|
||||
if( contextStack.shouldExpandDefinition( POUND_DEFINE + ident ) ) {
|
||||
expandDefinition(ident, mapping);
|
||||
c = getChar();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Object tokenTypeObject = keywords.get(ident);
|
||||
|
@ -590,7 +561,7 @@ public class Scanner implements IScanner {
|
|||
if( storageBuffer != null )
|
||||
{
|
||||
storageBuffer.append( ident );
|
||||
updateContext( new StringReader( storageBuffer.toString()), PASTING, IScannerContext.MACROEXPANSION );
|
||||
contextStack.updateContext( new StringReader( storageBuffer.toString()), PASTING, IScannerContext.MACROEXPANSION );
|
||||
storageBuffer = null;
|
||||
c = getChar();
|
||||
continue;
|
||||
|
@ -598,7 +569,7 @@ public class Scanner implements IScanner {
|
|||
}
|
||||
}
|
||||
|
||||
return newToken(tokenType, ident, currentContext);
|
||||
return newToken(tokenType, ident, contextStack.getCurrentContext());
|
||||
} else if ((c >= '0') && (c <= '9') || c == '.' ) {
|
||||
StringBuffer buff;
|
||||
|
||||
|
@ -625,10 +596,10 @@ public class Scanner implements IScanner {
|
|||
if( ! firstCharZero && floatingPoint )
|
||||
{
|
||||
ungetChar( c );
|
||||
return newToken( Token.tDOT, ".", currentContext );
|
||||
return newToken( Token.tDOT, ".", contextStack.getCurrentContext() );
|
||||
}
|
||||
else if( ! firstCharZero )
|
||||
throw new ScannerException( "Invalid Hexidecimal @ offset " + currentContext.getOffset() );
|
||||
throw new ScannerException( "Invalid Hexidecimal @ offset " + contextStack.getCurrentContext().getOffset() );
|
||||
|
||||
hex = true;
|
||||
c = getChar();
|
||||
|
@ -647,7 +618,7 @@ public class Scanner implements IScanner {
|
|||
if( floatingPoint || hex ) {
|
||||
if( buff.toString().equals( "..") && getChar() == '.' )
|
||||
return newToken( Token.tELIPSE, "..." );
|
||||
throw new ScannerException( "Invalid floating point @ offset " + currentContext.getOffset() );
|
||||
throw new ScannerException( "Invalid floating point @ offset " + contextStack.getCurrentContext().getOffset() );
|
||||
}
|
||||
|
||||
floatingPoint = true;
|
||||
|
@ -705,7 +676,7 @@ public class Scanner implements IScanner {
|
|||
{
|
||||
if( storageBuffer != null )
|
||||
{
|
||||
updateContext( new StringReader( buff.toString()), PASTING, IScannerContext.MACROEXPANSION );
|
||||
contextStack.updateContext( new StringReader( buff.toString()), PASTING, IScannerContext.MACROEXPANSION );
|
||||
storageBuffer = null;
|
||||
c = getChar();
|
||||
continue;
|
||||
|
@ -724,10 +695,10 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
tokenType,
|
||||
result,
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
|
||||
} else if (c == '#') {
|
||||
int beginningOffset = currentContext.getOffset() - 1;
|
||||
int beginningOffset = contextStack.getCurrentContext().getOffset() - 1;
|
||||
// lets prepare for a preprocessor statement
|
||||
StringBuffer buff = new StringBuffer();
|
||||
buff.append((char) c);
|
||||
|
@ -740,7 +711,7 @@ public class Scanner implements IScanner {
|
|||
if( c == '#' )
|
||||
{
|
||||
if( skipped )
|
||||
throw new ScannerException(BAD_PP + currentContext.getOffset());
|
||||
throw new ScannerException(BAD_PP + contextStack.getCurrentContext().getOffset());
|
||||
else
|
||||
return newToken( tPOUNDPOUND, "##" );
|
||||
}
|
||||
|
@ -758,7 +729,7 @@ public class Scanner implements IScanner {
|
|||
if (directive == null) {
|
||||
if (throwExceptionOnBadPreprocessorSyntax)
|
||||
throw new ScannerException(
|
||||
BAD_PP + currentContext.getOffset());
|
||||
BAD_PP + contextStack.getCurrentContext().getOffset());
|
||||
|
||||
|
||||
} else {
|
||||
|
@ -832,7 +803,7 @@ public class Scanner implements IScanner {
|
|||
case PreprocessorDirectives.ENDIF :
|
||||
String restOfLine = getRestOfPreprocessorLine().trim();
|
||||
if( ! restOfLine.equals( "" ) && throwExceptionOnBadPreprocessorSyntax )
|
||||
throw new ScannerException( BAD_PP + currentContext.getOffset() );
|
||||
throw new ScannerException( BAD_PP + contextStack.getCurrentContext().getOffset() );
|
||||
passOnToClient = branches.poundendif();
|
||||
c = getChar();
|
||||
continue;
|
||||
|
@ -905,7 +876,7 @@ public class Scanner implements IScanner {
|
|||
if (!remainderOfLine.equals("")) {
|
||||
if (throwExceptionOnBadPreprocessorSyntax)
|
||||
throw new ScannerException(
|
||||
BAD_PP + currentContext.getOffset());
|
||||
BAD_PP + contextStack.getCurrentContext().getOffset());
|
||||
}
|
||||
|
||||
c = getChar();
|
||||
|
@ -913,7 +884,7 @@ public class Scanner implements IScanner {
|
|||
default :
|
||||
if (throwExceptionOnBadPreprocessorSyntax)
|
||||
throw new ScannerException(
|
||||
BAD_PP + currentContext.getOffset());
|
||||
BAD_PP + contextStack.getCurrentContext().getOffset());
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -923,10 +894,10 @@ public class Scanner implements IScanner {
|
|||
c = getChar();
|
||||
int next = getChar();
|
||||
if( next == '\'' )
|
||||
return newToken( Token.tCHAR, new Character( (char)c ).toString(), currentContext );
|
||||
return newToken( Token.tCHAR, new Character( (char)c ).toString(), contextStack.getCurrentContext() );
|
||||
else
|
||||
if( throwExceptionOnBadCharacterRead )
|
||||
throw new ScannerException( "Invalid character '" + (char)c + "' read @ offset " + currentContext.getOffset() + " of file " + currentContext.getFilename() );
|
||||
throw new ScannerException( "Invalid character '" + (char)c + "' read @ offset " + contextStack.getCurrentContext().getOffset() + " of file " + contextStack.getCurrentContext().getFilename() );
|
||||
case ':' :
|
||||
c = getChar();
|
||||
switch (c) {
|
||||
|
@ -934,32 +905,32 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tCOLONCOLON,
|
||||
"::",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tCOLON,
|
||||
":",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case ';' :
|
||||
return newToken(Token.tSEMI, ";", currentContext);
|
||||
return newToken(Token.tSEMI, ";", contextStack.getCurrentContext());
|
||||
case ',' :
|
||||
return newToken(Token.tCOMMA, ",", currentContext);
|
||||
return newToken(Token.tCOMMA, ",", contextStack.getCurrentContext());
|
||||
case '?' :
|
||||
return newToken(Token.tQUESTION, "?", currentContext);
|
||||
return newToken(Token.tQUESTION, "?", contextStack.getCurrentContext());
|
||||
case '(' :
|
||||
return newToken(Token.tLPAREN, "(", currentContext);
|
||||
return newToken(Token.tLPAREN, "(", contextStack.getCurrentContext());
|
||||
case ')' :
|
||||
return newToken(Token.tRPAREN, ")", currentContext);
|
||||
return newToken(Token.tRPAREN, ")", contextStack.getCurrentContext());
|
||||
case '[' :
|
||||
return newToken(Token.tLBRACKET, "[", currentContext);
|
||||
return newToken(Token.tLBRACKET, "[", contextStack.getCurrentContext());
|
||||
case ']' :
|
||||
return newToken(Token.tRBRACKET, "]", currentContext);
|
||||
return newToken(Token.tRBRACKET, "]", contextStack.getCurrentContext());
|
||||
case '{' :
|
||||
return newToken(Token.tLBRACE, "{", currentContext);
|
||||
return newToken(Token.tLBRACE, "{", contextStack.getCurrentContext());
|
||||
case '}' :
|
||||
return newToken(Token.tRBRACE, "}", currentContext);
|
||||
return newToken(Token.tRBRACE, "}", contextStack.getCurrentContext());
|
||||
case '+' :
|
||||
c = getChar();
|
||||
switch (c) {
|
||||
|
@ -967,18 +938,18 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tPLUSASSIGN,
|
||||
"+=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
case '+' :
|
||||
return newToken(
|
||||
Token.tINCR,
|
||||
"++",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tPLUS,
|
||||
"+",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '-' :
|
||||
c = getChar();
|
||||
|
@ -987,12 +958,12 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tMINUSASSIGN,
|
||||
"-=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
case '-' :
|
||||
return newToken(
|
||||
Token.tDECR,
|
||||
"--",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
case '>' :
|
||||
c = getChar();
|
||||
switch (c) {
|
||||
|
@ -1000,20 +971,20 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tARROWSTAR,
|
||||
"->*",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tARROW,
|
||||
"->",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tMINUS,
|
||||
"-",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '*' :
|
||||
c = getChar();
|
||||
|
@ -1022,13 +993,13 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tSTARASSIGN,
|
||||
"*=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tSTAR,
|
||||
"*",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '%' :
|
||||
c = getChar();
|
||||
|
@ -1037,13 +1008,13 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tMODASSIGN,
|
||||
"%=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tMOD,
|
||||
"%",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '^' :
|
||||
c = getChar();
|
||||
|
@ -1052,13 +1023,13 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tXORASSIGN,
|
||||
"^=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tXOR,
|
||||
"^",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '&' :
|
||||
c = getChar();
|
||||
|
@ -1067,18 +1038,18 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tAMPERASSIGN,
|
||||
"&=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
case '&' :
|
||||
return newToken(
|
||||
Token.tAND,
|
||||
"&&",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tAMPER,
|
||||
"&",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '|' :
|
||||
c = getChar();
|
||||
|
@ -1087,21 +1058,21 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tBITORASSIGN,
|
||||
"|=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
case '|' :
|
||||
return newToken(
|
||||
Token.tOR,
|
||||
"||",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tBITOR,
|
||||
"|",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '~' :
|
||||
return newToken(Token.tCOMPL, "~", currentContext);
|
||||
return newToken(Token.tCOMPL, "~", contextStack.getCurrentContext());
|
||||
case '!' :
|
||||
c = getChar();
|
||||
switch (c) {
|
||||
|
@ -1109,13 +1080,13 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tNOTEQUAL,
|
||||
"!=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tNOT,
|
||||
"!",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '=' :
|
||||
c = getChar();
|
||||
|
@ -1124,13 +1095,13 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tEQUAL,
|
||||
"==",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tASSIGN,
|
||||
"=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '<' :
|
||||
c = getChar();
|
||||
|
@ -1142,22 +1113,22 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tSHIFTLASSIGN,
|
||||
"<<=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tSHIFTL,
|
||||
"<<",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '=' :
|
||||
return newToken(
|
||||
Token.tLTEQUAL,
|
||||
"<=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(Token.tLT, "<", currentContext);
|
||||
return newToken(Token.tLT, "<", contextStack.getCurrentContext());
|
||||
}
|
||||
case '>' :
|
||||
c = getChar();
|
||||
|
@ -1169,22 +1140,22 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tSHIFTRASSIGN,
|
||||
">>=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tSHIFTR,
|
||||
">>",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
case '=' :
|
||||
return newToken(
|
||||
Token.tGTEQUAL,
|
||||
">=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(Token.tGT, ">", currentContext);
|
||||
return newToken(Token.tGT, ">", contextStack.getCurrentContext());
|
||||
}
|
||||
case '.' :
|
||||
c = getChar();
|
||||
|
@ -1196,7 +1167,7 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tELIPSE,
|
||||
"...",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
@ -1205,13 +1176,13 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tDOTSTAR,
|
||||
".*",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tDOT,
|
||||
".",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
break;
|
||||
case '/' :
|
||||
|
@ -1230,18 +1201,18 @@ public class Scanner implements IScanner {
|
|||
return newToken(
|
||||
Token.tDIVASSIGN,
|
||||
"/=",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
default :
|
||||
ungetChar(c);
|
||||
return newToken(
|
||||
Token.tDIV,
|
||||
"/",
|
||||
currentContext);
|
||||
contextStack.getCurrentContext());
|
||||
}
|
||||
default :
|
||||
// Bad character
|
||||
if( throwExceptionOnBadCharacterRead )
|
||||
throw new ScannerException( "Invalid character '" + (char)c + "' read @ offset " + currentContext.getOffset() + " of file " + currentContext.getFilename() );
|
||||
throw new ScannerException( "Invalid character '" + (char)c + "' read @ offset " + contextStack.getCurrentContext().getOffset() + " of file " + contextStack.getCurrentContext().getFilename() );
|
||||
else
|
||||
{
|
||||
c = ' ';
|
||||
|
@ -1509,7 +1480,7 @@ public class Scanner implements IScanner {
|
|||
{
|
||||
if( callback != null )
|
||||
{
|
||||
offset = currentContext.getOffset() - f.length() - 1; // -1 for the end quote
|
||||
offset = contextStack.getCurrentContext().getOffset() - f.length() - 1; // -1 for the end quote
|
||||
|
||||
callback.inclusionBegin( f, offset, beginningOffset );
|
||||
callback.inclusionEnd();
|
||||
|
@ -1523,7 +1494,7 @@ public class Scanner implements IScanner {
|
|||
skipOverWhitespace();
|
||||
// definition
|
||||
String key = getNextIdentifier();
|
||||
int offset = currentContext.getOffset() - key.length() - currentContext.undoStackSize();
|
||||
int offset = contextStack.getCurrentContext().getOffset() - key.length() - contextStack.getCurrentContext().undoStackSize();
|
||||
|
||||
if (!quickScan) {
|
||||
String checkForRedefinition = (String) definitions.get(key);
|
||||
|
@ -1617,24 +1588,24 @@ public class Scanner implements IScanner {
|
|||
// it is a bad statement
|
||||
if (throwExceptionOnBadPreprocessorSyntax)
|
||||
throw new ScannerException(
|
||||
BAD_PP + currentContext.getOffset());
|
||||
BAD_PP + contextStack.getCurrentContext().getOffset());
|
||||
}
|
||||
} else {
|
||||
System.out.println("Unexpected character " + ((char) c));
|
||||
if (throwExceptionOnBadPreprocessorSyntax)
|
||||
throw new ScannerException(BAD_PP + currentContext.getOffset());
|
||||
throw new ScannerException(BAD_PP + contextStack.getCurrentContext().getOffset());
|
||||
}
|
||||
|
||||
// call the callback accordingly
|
||||
if( callback != null )
|
||||
callback.macro( key, offset, beginning, currentContext.getOffset() );
|
||||
callback.macro( key, offset, beginning, contextStack.getCurrentContext().getOffset() );
|
||||
}
|
||||
|
||||
|
||||
protected void expandDefinition(String symbol, Object expansion)
|
||||
throws ScannerException {
|
||||
if (expansion instanceof String ) {
|
||||
String replacementValue = (String) expansion;
|
||||
updateContext( new StringReader(replacementValue), (POUND_DEFINE + symbol ), ScannerContext.MACROEXPANSION );
|
||||
contextStack.updateContext( new StringReader(replacementValue), (POUND_DEFINE + symbol ), ScannerContext.MACROEXPANSION );
|
||||
} else if (expansion instanceof IMacroDescriptor ) {
|
||||
IMacroDescriptor macro = (IMacroDescriptor) expansion;
|
||||
skipOverWhitespace();
|
||||
|
@ -1710,7 +1681,7 @@ public class Scanner implements IScanner {
|
|||
buffer.append( " " );
|
||||
}
|
||||
String finalString = buffer.toString();
|
||||
updateContext(
|
||||
contextStack.updateContext(
|
||||
new StringReader(finalString),
|
||||
POUND_DEFINE + macro.getSignature(), ScannerContext.MACROEXPANSION );
|
||||
} else
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2003-04-11 Andrew Niefer
|
||||
Moved ScannerFailedTest::testBug36316 to ScannerTestCase::testBug36316
|
||||
Added ScannerFailedTest::testBug36047
|
||||
Added ScannerTestCase::testNestedRecursiveDefines
|
||||
|
||||
2003-04-10 John Camelon
|
||||
Added DOMTests::testBug36237().
|
||||
|
||||
|
|
|
@ -11,11 +11,14 @@
|
|||
|
||||
package org.eclipse.cdt.core.parser.failedTests;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.eclipse.cdt.core.parser.tests.ScannerTestCase;
|
||||
import org.eclipse.cdt.internal.core.parser.ScannerException;
|
||||
import org.eclipse.cdt.internal.core.parser.Token;
|
||||
|
||||
/**
|
||||
|
@ -34,29 +37,34 @@ public class ScannerFailedTest extends ScannerTestCase {
|
|||
{
|
||||
TestSuite suite = new TestSuite();
|
||||
|
||||
suite.addTest( new ScannerFailedTest( "testBug36316" ) );
|
||||
suite.addTest( new ScannerFailedTest( "testBug36047" ) );
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
public void testBug36316() throws Exception
|
||||
public void testBug36047() throws Exception
|
||||
{
|
||||
boolean testPassed = false;
|
||||
try
|
||||
{
|
||||
initializeScanner( "#define A B->A\nA" );
|
||||
StringWriter writer = new StringWriter();
|
||||
writer.write( "# define MAD_VERSION_STRINGIZE(str) #str\n" );
|
||||
writer.write( "# define MAD_VERSION_STRING(num) MAD_VERSION_STRINGIZE(num)\n" );
|
||||
writer.write( "# define MAD_VERSION MAD_VERSION_STRING(MAD_VERSION_MAJOR) \".\"\n" );
|
||||
initializeScanner( writer.toString() );
|
||||
validateEOF();
|
||||
|
||||
testPassed = true;
|
||||
|
||||
validateIdentifier("B");
|
||||
validateDefinition("A", "B->A");
|
||||
validateToken(Token.tARROW);
|
||||
validateIdentifier("A");
|
||||
validateEOF();
|
||||
|
||||
fail( "This test was expected to fail." );
|
||||
} catch( Throwable e )
|
||||
{
|
||||
if( !( e instanceof AssertionFailedError ) ){
|
||||
fail( "Unexpected failure" );
|
||||
}
|
||||
}
|
||||
catch( ScannerException se )
|
||||
{
|
||||
if( !se.getMessage().equals( "Invalid preprocessor directive encountered at offset 5" ) ){
|
||||
fail( "Unexpected Error: " + se.getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
if( testPassed )
|
||||
fail( "The expected error did not occur." );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1192,23 +1192,6 @@ public class ScannerTestCase extends TestCase
|
|||
}
|
||||
}
|
||||
|
||||
// public void testBug36047()
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// StringWriter writer = new StringWriter();
|
||||
// writer.write( "# define MAD_VERSION_STRINGIZE(str) #str\n" );
|
||||
// writer.write( "# define MAD_VERSION_STRING(num) MAD_VERSION_STRINGIZE(num)\n" );
|
||||
// writer.write( "# define MAD_VERSION MAD_VERSION_STRING(MAD_VERSION_MAJOR) \".\"\n" );
|
||||
// initializeScanner( writer.toString() );
|
||||
// validateEOF();
|
||||
// }
|
||||
// catch( ScannerException se )
|
||||
// {
|
||||
// fail( EXCEPTION_THROWN + se.toString() );
|
||||
// }
|
||||
// }
|
||||
|
||||
public void testBug36045() throws Exception
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
@ -1294,4 +1277,29 @@ public class ScannerTestCase extends TestCase
|
|||
fail(EXCEPTION_THROWN + se.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void testNestedRecursiveDefines() throws Exception
|
||||
{
|
||||
initializeScanner( "#define C B A\n#define B C C\n#define A B\nA" );
|
||||
|
||||
validateIdentifier("B");
|
||||
validateDefinition("A", "B");
|
||||
validateDefinition("B", "C C");
|
||||
validateDefinition("C", "B A");
|
||||
validateIdentifier("A");
|
||||
validateIdentifier("B");
|
||||
validateIdentifier("A");
|
||||
validateEOF();
|
||||
}
|
||||
|
||||
public void testBug36316() throws Exception
|
||||
{
|
||||
initializeScanner( "#define A B->A\nA" );
|
||||
|
||||
validateIdentifier("B");
|
||||
validateDefinition("A", "B->A");
|
||||
validateToken(Token.tARROW);
|
||||
validateIdentifier("A");
|
||||
validateEOF();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue