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:
parent
a22cca2f6b
commit
f479e84d8f
8 changed files with 377 additions and 35 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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$
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue