1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-10 09:45:39 +02:00

Patch for Devin Steffler.

Fixed 39688 [Scanner] Macros with variable number of arguments are not supported (C99) (GCC)
- added support for C99 syntax for macros with variable arguments i.e. "..."
- added support for GCC syntax for macros with variable arguments i.e. "args..."
- added test cases for the above
This commit is contained in:
John Camelon 2004-10-20 17:59:54 +00:00
parent a22cca2f6b
commit f479e84d8f
8 changed files with 377 additions and 35 deletions

View file

@ -16,6 +16,7 @@ import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.ISourceElementRequestor;
@ -26,6 +27,7 @@ import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ParserMode;
import org.eclipse.cdt.core.parser.ast.IASTInclusion;
import org.eclipse.cdt.internal.core.parser.QuickParseCallback;
import org.eclipse.cdt.internal.core.parser.scanner2.FunctionStyleMacro;
/**
* @author jcamelon
@ -2002,4 +2004,180 @@ public class Scanner2Test extends BaseScanner2Test
assertEquals( 0, callback.problems.size() );
}
public void testBug39688A() throws Exception { // test valid IProblems
Writer writer = new StringWriter();
writer.write("#define decl1(type, ... \\\n ) type var;\n"); //$NON-NLS-1$
writer.write("decl1(int, x, y, z)\n"); //$NON-NLS-1$
writer.write("#define decl2(type, args...) type args;"); //$NON-NLS-1$
writer.write("decl2(int, a, b, c, x, y, z)\n"); //$NON-NLS-1$
writer.write("#define decl3(type, args...) \\\n type args;"); //$NON-NLS-1$
writer.write("decl3(int, a, b, c, x, y)\n"); //$NON-NLS-1$
writer.write("#define decl4(type, args... \\\n ) type args;"); //$NON-NLS-1$
writer.write("decl4(int, a, b, z)\n"); //$NON-NLS-1$
writer.write("#define decl5(type, ...) type __VA_ARGS__;"); //$NON-NLS-1$
writer.write("decl5(int, z)\n"); //$NON-NLS-1$
writer.write("#define decl6(type, ... \\\n) type __VA_ARGS__;"); //$NON-NLS-1$
writer.write("decl6(int, a, b, c, x)\n"); //$NON-NLS-1$
writer.write("#define foo(a) a __VA_ARGS__;\n"); //$NON-NLS-1$ C99: 6.10.3.5 this should produce an IProblem
writer.write("#define foo2(a) a #__VA_ARGS__;\n"); //$NON-NLS-1$ C99: 6.10.3.5 this should produce an IProblem
Callback callback = new Callback( ParserMode.COMPLETE_PARSE );
initializeScanner( writer.toString(), ParserMode.COMPLETE_PARSE, callback );
fullyTokenize();
Iterator probs = callback.problems.iterator();
assertTrue( probs.hasNext() );
assertTrue( ((IProblem)probs.next()).getID() == IProblem.PREPROCESSOR_INVALID_VA_ARGS );
assertTrue( probs.hasNext() );
assertTrue( ((IProblem)probs.next()).getID() == IProblem.PREPROCESSOR_MACRO_PASTING_ERROR );
assertFalse( probs.hasNext() );
}
public void testBug39688B() throws Exception { // test C99
Writer writer = new StringWriter();
writer.write("#define debug(...) fprintf(stderr, __VA_ARGS__)\n"); //$NON-NLS-1$
writer.write("#define showlist(...) puts(#__VA_ARGS__)\n"); //$NON-NLS-1$
writer.write("#define report(test, ...) ((test)?puts(#test):\\\n printf(__VA_ARGS__))\n"); //$NON-NLS-1$
writer.write("int main() {\n"); //$NON-NLS-1$
writer.write("debug(\"Flag\");\n"); //$NON-NLS-1$
writer.write("debug(\"X = %d\\n\", x);\n"); //$NON-NLS-1$
writer.write("showlist(The first, second, and third items.);\n"); //$NON-NLS-1$
writer.write("report(x>y, \"x is %d but y is %d\", x, y);\n"); //$NON-NLS-1$
writer.write("return 0; }\n"); //$NON-NLS-1$
Callback callback = new Callback( ParserMode.COMPLETE_PARSE );
initializeScanner( writer.toString(), ParserMode.COMPLETE_PARSE, callback );
fullyTokenize();
Iterator probs = callback.problems.iterator();
assertFalse( probs.hasNext() );
Map defs = scanner.getDefinitions();
assertTrue(defs.containsKey("debug")); //$NON-NLS-1$
assertTrue(defs.containsKey("showlist")); //$NON-NLS-1$
assertTrue(defs.containsKey("report")); //$NON-NLS-1$
FunctionStyleMacro debug = (FunctionStyleMacro)defs.get("debug"); //$NON-NLS-1$
assertTrue(new String(debug.arglist[0]).equals("__VA_ARGS__")); //$NON-NLS-1$
assertTrue(debug.hasVarArgs());
assertFalse(debug.hasGCCVarArgs());
assertTrue(new String(debug.expansion).equals("fprintf(stderr, __VA_ARGS__)") ); //$NON-NLS-1$
FunctionStyleMacro showlist = (FunctionStyleMacro)defs.get("showlist"); //$NON-NLS-1$
assertTrue(new String(showlist.arglist[0]).equals("__VA_ARGS__")); //$NON-NLS-1$
assertTrue(showlist.hasVarArgs());
assertFalse(showlist.hasGCCVarArgs());
assertTrue(new String(showlist.expansion).equals("puts(#__VA_ARGS__)")); //$NON-NLS-1$
FunctionStyleMacro report = (FunctionStyleMacro)defs.get("report"); //$NON-NLS-1$
assertTrue(new String(report.arglist[0]).equals("test")); //$NON-NLS-1$
assertTrue(new String(report.arglist[1]).equals("__VA_ARGS__")); //$NON-NLS-1$
assertTrue(report.hasVarArgs());
assertFalse(report.hasGCCVarArgs());
assertTrue(new String(report.expansion).equals("((test)?puts(#test): printf(__VA_ARGS__))")); //$NON-NLS-1$
validate39688Common(writer, callback);
}
public void testBug39688C() throws Exception { // test GCC
Writer writer = new StringWriter();
writer.write("#define debug(vars...) fprintf(stderr, vars)\n"); //$NON-NLS-1$
writer.write("#define showlist(vars...) puts(#vars)\n"); //$NON-NLS-1$
writer.write("#define report(test, vars...) ((test)?puts(#test):\\\n printf(vars))\n"); //$NON-NLS-1$
writer.write("int main() {\n"); //$NON-NLS-1$
writer.write("debug(\"Flag\");\n"); //$NON-NLS-1$
writer.write("debug(\"X = %d\\n\", x);\n"); //$NON-NLS-1$
writer.write("showlist(The first, second, and third items.);\n"); //$NON-NLS-1$
writer.write("report(x>y, \"x is %d but y is %d\", x, y);\n"); //$NON-NLS-1$
writer.write("return 0; }\n"); //$NON-NLS-1$
Callback callback = new Callback( ParserMode.COMPLETE_PARSE );
initializeScanner( writer.toString(), ParserMode.COMPLETE_PARSE, callback );
fullyTokenize();
Iterator probs = callback.problems.iterator();
assertFalse( probs.hasNext() );
Map defs = scanner.getDefinitions();
assertTrue(defs.containsKey("debug")); //$NON-NLS-1$
assertTrue(defs.containsKey("showlist")); //$NON-NLS-1$
assertTrue(defs.containsKey("report")); //$NON-NLS-1$
FunctionStyleMacro debug = (FunctionStyleMacro)defs.get("debug"); //$NON-NLS-1$
assertTrue(new String(debug.arglist[0]).equals("vars")); //$NON-NLS-1$
assertFalse(debug.hasVarArgs());
assertTrue(debug.hasGCCVarArgs());
assertTrue(new String(debug.expansion).equals("fprintf(stderr, vars)") ); //$NON-NLS-1$
FunctionStyleMacro showlist = (FunctionStyleMacro)defs.get("showlist"); //$NON-NLS-1$
assertTrue(new String(showlist.arglist[0]).equals("vars")); //$NON-NLS-1$
assertFalse(showlist.hasVarArgs());
assertTrue(showlist.hasGCCVarArgs());
assertTrue(new String(showlist.expansion).equals("puts(#vars)")); //$NON-NLS-1$
FunctionStyleMacro report = (FunctionStyleMacro)defs.get("report"); //$NON-NLS-1$
assertTrue(new String(report.arglist[0]).equals("test")); //$NON-NLS-1$
assertTrue(new String(report.arglist[1]).equals("vars")); //$NON-NLS-1$
assertFalse(report.hasVarArgs());
assertTrue(report.hasGCCVarArgs());
assertTrue(new String(report.expansion).equals("((test)?puts(#test): printf(vars))")); //$NON-NLS-1$
validate39688Common(writer, callback);
}
private void validate39688Common(Writer writer, Callback callback) throws Exception {
initializeScanner( writer.toString(), ParserMode.COMPLETE_PARSE, callback );
validateToken(IToken.t_int);
validateIdentifier("main"); //$NON-NLS-1$
validateToken(IToken.tLPAREN);
validateToken(IToken.tRPAREN);
validateToken(IToken.tLBRACE);
validateIdentifier("fprintf"); //$NON-NLS-1$
validateToken(IToken.tLPAREN);
validateIdentifier("stderr"); //$NON-NLS-1$
validateToken(IToken.tCOMMA);
validateString("Flag"); //$NON-NLS-1$
validateToken(IToken.tRPAREN);
validateToken(IToken.tSEMI);
validateIdentifier("fprintf"); //$NON-NLS-1$
validateToken(IToken.tLPAREN);
validateIdentifier("stderr"); //$NON-NLS-1$
validateToken(IToken.tCOMMA);
validateString("X = %d\\n"); //$NON-NLS-1$
validateToken(IToken.tCOMMA);
validateIdentifier("x"); //$NON-NLS-1$
validateToken(IToken.tRPAREN);
validateToken(IToken.tSEMI);
validateIdentifier("puts"); //$NON-NLS-1$
validateToken(IToken.tLPAREN);
validateString("The first, second, and third items."); //$NON-NLS-1$
validateToken(IToken.tRPAREN);
validateToken(IToken.tSEMI);
validateToken(IToken.tLPAREN);
validateToken(IToken.tLPAREN);
validateIdentifier("x"); //$NON-NLS-1$
validateToken(IToken.tGT);
validateIdentifier("y"); //$NON-NLS-1$
validateToken(IToken.tRPAREN);
validateToken(IToken.tQUESTION);
validateIdentifier("puts"); //$NON-NLS-1$
validateToken(IToken.tLPAREN);
validateString("x>y"); //$NON-NLS-1$
validateToken(IToken.tRPAREN);
validateToken(IToken.tCOLON);
validateIdentifier("printf"); //$NON-NLS-1$
validateToken(IToken.tLPAREN);
validateString("x is %d but y is %d"); //$NON-NLS-1$
validateToken(IToken.tCOMMA);
validateIdentifier("x"); //$NON-NLS-1$
validateToken(IToken.tCOMMA);
validateIdentifier("y"); //$NON-NLS-1$
validateToken(IToken.tRPAREN);
validateToken(IToken.tRPAREN);
validateToken(IToken.tSEMI);
validateToken(IToken.t_return);
validateInteger("0"); //$NON-NLS-1$
validateToken(IToken.tSEMI);
validateToken(IToken.tRBRACE);
validateEOF();
}
}

View file

@ -644,8 +644,8 @@ public class SourceIndexerRequestor implements ISourceElementRequestor, IIndexCo
tempMarker = markers[i];
tempInt = (Integer) tempMarker.getAttribute(IMarker.LINE_NUMBER);
tempMsgString = (String) tempMarker.getAttribute(IMarker.MESSAGE);
if (tempInt.intValue()==problem.getSourceLineNumber() &&
tempMsgString.equalsIgnoreCase( INDEXER_MARKER_PREFIX + problem.getMessage()))
if (tempInt != null && tempInt.intValue()==problem.getSourceLineNumber() &&
tempMsgString.equalsIgnoreCase( INDEXER_MARKER_PREFIX + problem.getMessage()))
{
newProblem = false;
break;

View file

@ -401,7 +401,19 @@ public interface IProblem
* @see #A_PREPROC_INCLUDE_FILENAME
*/
public final static int PREPROCESSOR_CIRCULAR_INCLUSION = PREPROCESSOR_RELATED | 0x00B;
/**
* macro argument "..." encountered without the required ')' i.e. must be last argument if used
* Required attributes: none
*/
public final static int PREPROCESSOR_MISSING_RPAREN_PARMLIST = PREPROCESSOR_RELATED | 0x00C;
/**
* __VA_ARGS__ encountered in macro definition without the required '...' parameter
* Required attributes: none
*/
public final static int PREPROCESSOR_INVALID_VA_ARGS = PREPROCESSOR_RELATED | 0x00D;
/*
* Parser Syntactic Problems
*/

View file

@ -33,6 +33,8 @@ ScannerProblemFactory.error.preproc.macroUsage=Macro usage error for macro : {0}
ScannerProblemFactory.error.preproc.circularInclusion=Circular inclusion for file : {0}
ScannerProblemFactory.error.preproc.invalidDirective=Invalid preprocessor directive : {0}
ScannerProblemFactory.error.preproc.macroPasting=Invalid use of macro pasting in macro : {0}
ScannerProblemFactory.error.preproc.missingRParen=missing ) in macro parameter list
ScannerProblemFactory.error.preproc.invalidVaArgs=__VA_ARGS__ can only appear in the expansion of a C99 variadic macro
ScannerProblemFactory.error.scanner.invalidEscapeChar=Invalid escape character encountered
ScannerProblemFactory.error.scanner.unboundedString=Unbounded string encountered

View file

@ -181,6 +181,12 @@ public class Problem implements IProblem {
errorMessages.put(
new Integer(IProblem.PREPROCESSOR_MACRO_PASTING_ERROR),
ParserMessages.getString("ScannerProblemFactory.error.preproc.macroPasting")); //$NON-NLS-1$
errorMessages.put(
new Integer(IProblem.PREPROCESSOR_MISSING_RPAREN_PARMLIST),
ParserMessages.getString("ScannerProblemFactory.error.preproc.missingRParen")); //$NON-NLS-1$
errorMessages.put(
new Integer(IProblem.PREPROCESSOR_INVALID_VA_ARGS),
ParserMessages.getString("ScannerProblemFactory.error.preproc.invalidVaArgs")); //$NON-NLS-1$
errorMessages.put(
new Integer(IProblem.SCANNER_INVALID_ESCAPECHAR),
ParserMessages.getString("ScannerProblemFactory.error.scanner.invalidEscapeChar")); //$NON-NLS-1$

View file

@ -178,7 +178,7 @@ public class TemplateFactory extends ExtensibleSymbol implements ITemplateFactor
private void basicTemplateDeclaration( ISymbol symbol ) throws ParserSymbolTableException{
ITemplateSymbol template = (ITemplateSymbol)templates.get( 0 );
if( template == null ) return;
if( template.getParameterList().size() == 0 ){
//explicit specialization, deduce some arguments and use addTemplateId
ISymbol previous = findPreviousSymbol( symbol, new ArrayList() );
@ -380,7 +380,7 @@ public class TemplateFactory extends ExtensibleSymbol implements ITemplateFactor
int size = templates.size();
for( int i = size - 1; i >= 0; i-- ){
ITemplateSymbol template = (ITemplateSymbol) templates.get(i);
if( template == null )continue;
ISymbol look = template.lookupMemberForDefinition( name );
if( look != null && look.isType( type ) ){
return look;
@ -397,10 +397,12 @@ public class TemplateFactory extends ExtensibleSymbol implements ITemplateFactor
int size = templates.size();
for( int i = size - 1; i >= 0; i-- ){
ITemplateSymbol template = (ITemplateSymbol) templates.get(i);
ISymbol look = template.lookupMemberForDefinition( name );
if( look != null ){
return look;
if( template != null )
{
ISymbol look = template.lookupMemberForDefinition( name );
if( look != null ){
return look;
}
}
}

View file

@ -11,17 +11,61 @@
package org.eclipse.cdt.internal.core.parser.scanner2;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
/**
* @author Doug Schaefer
*/
public class FunctionStyleMacro extends ObjectStyleMacro {
private static final char[] VA_ARGS_CHARARRAY = "__VA_ARGS__".toCharArray(); //$NON-NLS-1$
private static final char[] ELLIPSIS_CHARARRAY = "...".toString().toCharArray(); //$NON-NLS-1$
public char[][] arglist;
private char[] sig = null;
private boolean hasVarArgs = false;
private boolean hasGCCVarArgs = false;
private int varArgsPosition = -1;
public FunctionStyleMacro(char[] name, char[] expansion, char[][] arglist) {
super(name, expansion);
this.arglist = arglist;
// determine if there's an argument with "..."
if (arglist != null && arglist[0]!= null && arglist.length > 0) {
int last = -1;
// if the last element in the list is null then binary search for the last non-null element
if (arglist[arglist.length-1] == null) {
int largest = arglist.length - 1;
int smallest = 0;
for (int j=arglist.length/2; last == -1; ) {
if (arglist[j] == null) {
largest = j;
j=smallest + (largest-smallest)/2;
} else {
smallest = j;
j=smallest + (largest - smallest)/2;
if ((j+1 == arglist.length && arglist[j] != null) || (arglist[j] != null && arglist[j+1] == null))
last = j;
}
}
} else
last = arglist.length-1;
if (arglist[last] != null && CharArrayUtils.equals(arglist[last], ELLIPSIS_CHARARRAY)) {
this.hasVarArgs = true;
varArgsPosition = last;
// change the arg to __VA_ARGS__ so this will be replaced properly later on...
arglist[last] = VA_ARGS_CHARARRAY;
} else if (arglist[last] != null && CharArrayUtils.equals(arglist[last], arglist[last].length - ELLIPSIS_CHARARRAY.length, ELLIPSIS_CHARARRAY.length, ELLIPSIS_CHARARRAY)) { // if the last 3 are '...'
this.hasGCCVarArgs = true;
varArgsPosition = last;
// change the arg to "argname" instead of "argname..." so argname will be replaced properly later on...
char[] swap = new char[arglist[last].length - ELLIPSIS_CHARARRAY.length];
System.arraycopy(arglist[last], 0, swap, 0, swap.length);
arglist[last] = swap;
}
}
}
public char[] getSignature(){
@ -53,4 +97,16 @@ public class FunctionStyleMacro extends ObjectStyleMacro {
= new CharArrayObjectMap(FunctionStyleMacro.this.arglist.length);
}
public boolean hasVarArgs() {
return hasVarArgs;
}
public boolean hasGCCVarArgs() {
return hasGCCVarArgs;
}
public int getVarArgsPosition() {
return varArgsPosition;
}
}

View file

@ -57,6 +57,8 @@ import org.eclipse.cdt.internal.core.parser.token.SimpleToken;
*/
public class Scanner2 implements IScanner, IScannerData {
private static final char[] ELLIPSIS_CHARARRAY = "...".toString().toCharArray(); //$NON-NLS-1$
private static final char[] VA_ARGS_CHARARRAY = "__VA_ARGS__".toCharArray(); //$NON-NLS-1$
/**
* @author jcamelon
*
@ -504,7 +506,7 @@ public class Scanner2 implements IScanner, IScannerData {
if (pos + 1 < limit && buffer[pos + 1] == '"')
return scanString();
if (pos + 1 < limit && buffer[pos + 1] == '\'')
return scanCharLiteral(true);
return scanCharLiteral();
IToken t = scanIdentifier();
if (t instanceof MacroExpansionToken)
@ -516,7 +518,7 @@ public class Scanner2 implements IScanner, IScannerData {
return scanString();
case '\'':
return scanCharLiteral(false);
return scanCharLiteral();
case 'a':
case 'b':
@ -1064,7 +1066,7 @@ public class Scanner2 implements IScanner, IScannerData {
return newToken(tokenType, result);
}
private IToken scanCharLiteral(boolean b) {
private IToken scanCharLiteral() {
char[] buffer = bufferStack[bufferStackPos];
int start = bufferPos[bufferStackPos];
int limit = bufferLimit[bufferStackPos];
@ -1735,11 +1737,19 @@ public class Scanner2 implements IScanner, IScannerData {
skipOverWhiteSpace();
int textstart = bufferPos[bufferStackPos] + 1;
int textend = textstart - 1;
int varArgDefinitionInd = -1;
boolean encounteredMultilineComment = false;
boolean usesVarArgInDefinition = false;
while (bufferPos[bufferStackPos] + 1 < limit
&& buffer[bufferPos[bufferStackPos] + 1] != '\n') {
//16.3.2-1 Each # preprocessing token in the replacement list for a function-like-macro shall
if (CharArrayUtils.equals( buffer, bufferPos[bufferStackPos] + 1, VA_ARGS_CHARARRAY.length, VA_ARGS_CHARARRAY )) {
usesVarArgInDefinition = true; // __VA_ARGS__ is in definition, used to check C99 6.10.3-5
varArgDefinitionInd = bufferPos[bufferStackPos] + 1;
}
//16.3.2-1 Each # preprocessing token in the replacement list for a function-like-macro shall
//be followed by a parameter as the next preprocessing token
if( arglist != null && !skipOverNonWhiteSpace( true ) ){
++bufferPos[bufferStackPos]; //advances us to the #
@ -1754,7 +1764,17 @@ public class Scanner2 implements IScanner, IScannerData {
{
if( bufferPos[bufferStackPos] + arglist[i].length - 1 < limit )
{
if( CharArrayUtils.equals( buffer, bufferPos[bufferStackPos], arglist[i].length, arglist[i] ) )
if (arglist[i].length > 3 && arglist[i][arglist[i].length - 3] == '.' && arglist[i][arglist[i].length - 2] == '.' && arglist[i][arglist[i].length - 3] == '.') {
char[] varArgName = new char[arglist[i].length - 3];
System.arraycopy(arglist[i], 0, varArgName, 0, arglist[i].length - 3);
if (CharArrayUtils.equals( buffer, bufferPos[bufferStackPos], varArgName.length, varArgName)) {
isArg = true;
//advance us to the end of the arg
bufferPos[bufferStackPos] += arglist[i].length - 4;
break;
}
} else if ( CharArrayUtils.equals( buffer, bufferPos[bufferStackPos], arglist[i].length, arglist[i] )
|| (CharArrayUtils.equals(arglist[i], ELLIPSIS_CHARARRAY) && CharArrayUtils.equals( buffer, bufferPos[bufferStackPos], VA_ARGS_CHARARRAY.length, VA_ARGS_CHARARRAY )))
{
isArg = true;
//advance us to the end of the arg
@ -1791,6 +1811,9 @@ public class Scanner2 implements IScanner, IScannerData {
? new ObjectStyleMacro(name, text)
: new FunctionStyleMacro(name, text, arglist) );
if (usesVarArgInDefinition && definitions.get(name) instanceof FunctionStyleMacro && !((FunctionStyleMacro)definitions.get(name)).hasVarArgs())
handleProblem(IProblem.PREPROCESSOR_INVALID_VA_ARGS, varArgDefinitionInd, null);
callbackManager.pushCallback( getASTFactory().createMacro( name, startingOffset, startingLineNumber, idstart, idstart + idlen, nameLine, textstart + textlen, endingLine, getCurrentFilename() ) );
}
@ -1805,31 +1828,29 @@ public class Scanner2 implements IScanner, IScannerData {
char[][] arglist = new char[4][];
int currarg = -1;
while (bufferPos[bufferStackPos] < limit) {
int pos = bufferPos[bufferStackPos];
skipOverWhiteSpace();
if (++bufferPos[bufferStackPos] >= limit)
return null;
c = buffer[bufferPos[bufferStackPos]];
int argstart = bufferPos[bufferStackPos];
if (c == ')') {
break;
} else if (c == ',') {
continue;
} else if (c == '.'
&& pos + 1 < limit && buffer[pos + 1] == '.'
&& pos + 2 < limit && buffer[pos + 2] == '.') {
// varargs
// TODO - something better
bufferPos[bufferStackPos] += 2;
arglist[++currarg] = "...".toCharArray(); //$NON-NLS-1$
continue;
} else if (c == '.'
&& bufferPos[bufferStackPos] + 1 < limit && buffer[bufferPos[bufferStackPos] + 1] == '.'
&& bufferPos[bufferStackPos] + 2 < limit && buffer[bufferPos[bufferStackPos] + 2] == '.') {
bufferPos[bufferStackPos]--; // move back and let skipOverIdentifier handle the ellipsis
} else if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || Character.isUnicodeIdentifierPart(c))) {
if( reportProblems )
handleProblem( IProblem.PREPROCESSOR_INVALID_MACRO_DEFN, idstart, name );
// yuck
skipToNewLine();
return null;
if( reportProblems ) {
handleProblem( IProblem.PREPROCESSOR_INVALID_MACRO_DEFN, idstart, name );
// yuck
skipToNewLine();
return null;
}
}
int argstart = bufferPos[bufferStackPos];
skipOverIdentifier();
if (++currarg == arglist.length) {
char[][] oldarglist = arglist;
@ -1858,6 +1879,8 @@ public class Scanner2 implements IScanner, IScannerData {
{
if( text[i] == '\\' && i+ 1 < text.length && text[i+1] == '\n' )
++i;
else if( text[i] == '\\' && i + 1 < text.length && text[i+1] == '\r' && i + 2 < text.length && text[i+2] == '\n' )
i+=2;
else
result[ counter++ ] = text[i];
}
@ -2223,6 +2246,14 @@ public class Scanner2 implements IScanner, IScannerData {
--bufferPos[bufferStackPos];
return true;
}
if( pos + 1 < limit && buffer[ pos + 1 ] == '\r')
{
if( pos + 2 < limit && buffer[ pos + 2] == '\n' )
{
bufferPos[bufferStackPos] +=2;
continue;
}
}
break;
case '"':
boolean escaped = false;
@ -2355,13 +2386,56 @@ public class Scanner2 implements IScanner, IScannerData {
while (++bufferPos[bufferStackPos] < limit) {
char c = buffer[bufferPos[bufferStackPos]];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
if (c == '.' && bufferPos[bufferStackPos] + 1 < limit && buffer[bufferPos[bufferStackPos] + 1] == '.'
&& bufferPos[bufferStackPos] + 2 < limit && buffer[bufferPos[bufferStackPos] + 2] == '.') {
// encountered "..." make sure it's the last argument, if not raise IProblem
bufferPos[bufferStackPos] += 2;
int end = bufferPos[bufferStackPos];
while(++bufferPos[bufferStackPos] < limit) {
char c2 = buffer[bufferPos[bufferStackPos]];
if (c2 == ')') { // good
bufferPos[bufferStackPos] = end; // point at the end of ... to get the argument
return;
}
switch (c2) {
case ' ':
case '\t':
case '\r':
continue;
case '\\':
if (bufferPos[bufferStackPos] + 1 < limit && buffer[bufferPos[bufferStackPos] + 1] == '\n') {
// \n is a whitespace
++bufferPos[bufferStackPos];
continue;
}
if( bufferPos[bufferStackPos] + 1 < limit && buffer[ bufferPos[bufferStackPos] + 1 ] == '\r')
{
if( bufferPos[bufferStackPos] + 2 < limit && buffer[ bufferPos[bufferStackPos] + 2] == '\n' )
{
bufferPos[bufferStackPos] +=2;
continue;
}
}
break;
default:
// bad
handleProblem( IProblem.PREPROCESSOR_MISSING_RPAREN_PARMLIST, bufferPos[bufferStackPos], String.valueOf(c2).toCharArray() );
return;
}
}
// "..." was the last macro argument
break;
} else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| c == '_' || (c >= '0' && c <= '9') || Character.isUnicodeIdentifierPart(c)) {
continue;
}
break;
}
break; // found the end of the argument
}
--bufferPos[bufferStackPos];
}
@ -2466,14 +2540,26 @@ public class Scanner2 implements IScanner, IScannerData {
continue;
}
if (++currarg >= arglist.length || arglist[currarg] == null){
// too many args
if ((++currarg >= arglist.length || arglist[currarg] == null) && !macro.hasVarArgs() && !macro.hasGCCVarArgs()) {
// too many args and no variable argument
handleProblem( IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, bufferPos[bufferStackPos], macro.name );
break;
}
int argstart = bufferPos[bufferStackPos];
int argend = skipOverMacroArg();
int argend = -1;
if ((macro.hasGCCVarArgs() || macro.hasVarArgs()) && currarg == macro.getVarArgsPosition()) {
// there are varargs and the other parms have been accounted for, the rest will replace __VA_ARGS__ or name where "name..." is the parm
while (++bufferPos[bufferStackPos] < limit) {
if (buffer[bufferPos[bufferStackPos]] == ')') {
--bufferPos[bufferStackPos];
break;
}
}
argend = bufferPos[bufferStackPos];
} else
argend = skipOverMacroArg();
char[] arg = emptyCharArray;
int arglen = argend - argstart + 1;