diff options
Diffstat (limited to 'core')
8 files changed, 377 insertions, 35 deletions
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner2/Scanner2Test.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner2/Scanner2Test.java index fd4dc896264..9b6ede46ccd 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner2/Scanner2Test.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner2/Scanner2Test.java @@ -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(); + } } diff --git a/core/org.eclipse.cdt.core/index/org/eclipse/cdt/internal/core/search/indexing/SourceIndexerRequestor.java b/core/org.eclipse.cdt.core/index/org/eclipse/cdt/internal/core/search/indexing/SourceIndexerRequestor.java index 3216a048683..76b88eb1805 100644 --- a/core/org.eclipse.cdt.core/index/org/eclipse/cdt/internal/core/search/indexing/SourceIndexerRequestor.java +++ b/core/org.eclipse.cdt.core/index/org/eclipse/cdt/internal/core/search/indexing/SourceIndexerRequestor.java @@ -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; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IProblem.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IProblem.java index 921f43ac197..8d78ade2af5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IProblem.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IProblem.java @@ -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 */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.properties b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.properties index 206193f5913..02caa2ca944 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.properties +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.properties @@ -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 diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/problem/Problem.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/problem/Problem.java index be0cd2d2e5a..19dcd53f1ac 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/problem/Problem.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/problem/Problem.java @@ -182,6 +182,12 @@ public class Problem implements IProblem { 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$ errorMessages.put( diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateFactory.java index 17da7a03409..4d8fca89204 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateFactory.java @@ -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; + } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/FunctionStyleMacro.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/FunctionStyleMacro.java index 6f650fb1128..aefa0f776b1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/FunctionStyleMacro.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/FunctionStyleMacro.java @@ -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; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/Scanner2.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/Scanner2.java index 25b33f2f565..e22dc09e4ed 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/Scanner2.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/Scanner2.java @@ -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; |