Skip to main content
aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJohn Camelon2004-10-20 13:59:54 -0400
committerJohn Camelon2004-10-20 13:59:54 -0400
commitf479e84d8fefa50fdba6741a77406f2b31fca270 (patch)
treefb4c20717fb16da16fe38801cdac0de17abd466a /core
parenta22cca2f6b980fcdd0df4c6a04b477dff544527f (diff)
downloadorg.eclipse.cdt-f479e84d8fefa50fdba6741a77406f2b31fca270.tar.gz
org.eclipse.cdt-f479e84d8fefa50fdba6741a77406f2b31fca270.tar.xz
org.eclipse.cdt-f479e84d8fefa50fdba6741a77406f2b31fca270.zip
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
Diffstat (limited to 'core')
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner2/Scanner2Test.java178
-rw-r--r--core/org.eclipse.cdt.core/index/org/eclipse/cdt/internal/core/search/indexing/SourceIndexerRequestor.java4
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IProblem.java12
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.properties2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/problem/Problem.java6
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateFactory.java14
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/FunctionStyleMacro.java56
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/Scanner2.java140
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;

Back to the top