1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-25 01:45:33 +02:00

C++0x: Right angle brackets, bug 261268.

This commit is contained in:
Markus Schorn 2009-11-17 18:05:06 +00:00
parent aca23fae0e
commit f40c0fc481
10 changed files with 539 additions and 353 deletions

View file

@ -4395,7 +4395,8 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest {
// X<(1>2)> x2; // OK // X<(1>2)> x2; // OK
// template<class T> class Y { }; // template<class T> class Y { };
// Y< X<1> > x3; // OK // Y< X<1> > x3; // OK
// Y<X<6>> 1> > x4; // OK: Y< X< (6>>1) > > // // with C++0x this is no longer valid:
// // Y<X<6>> 1> > x4; // OK: Y< X< (6>>1) > >
public void test14_2s3() throws Exception { public void test14_2s3() throws Exception {
parse(getAboveComment(), ParserLanguage.CPP, true, 0); parse(getAboveComment(), ParserLanguage.CPP, true, 0);
} }

View file

@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTProblemStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBasicType;
@ -4245,4 +4246,58 @@ public class AST2TemplateTests extends AST2BaseTest {
final String code= getAboveComment(); final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP); parseAndCheckBindings(code, ParserLanguage.CPP);
} }
// template<typename T> class CT {};
// template<int I> class CTI {};
//
// int test() {
// int a;
// CT<CT<int>> x;
// a= 1 >> 2;
// return a;
// }
public void testClosingAngleBrackets1_261268() throws Exception {
final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
}
// template<typename T> class CT {};
// template<int I> class CTI {};
//
// int test() {
// int a;
// a= 1 > > 3; // must be syntax error
// return a;
// }
public void testClosingAngleBrackets2_261268() throws Exception {
final String code= getAboveComment();
IASTTranslationUnit tu = parse(code, ParserLanguage.CPP, true, false);
IASTFunctionDefinition fdef= getDeclaration(tu, 2);
IASTProblemStatement p1= getStatement(fdef, 1);
}
// template<typename T> class CT {};
// typedef int TInt;
// int test() {
// int a;
// CT<CT<TInt>> x; // declaration
// int y= a<a<a>> a; // binary expression
// a<a<a>> a; // binary expression via ambiguity
// y= a < a >> (1+2); // binary expression
// a < a >> (1+2); // binary expression via ambiguity
// }
public void testClosingAngleBracketsAmbiguity_261268() throws Exception {
final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
}
// #define OPASSIGN(x) x##=
// int test() {
// int a=1;
// a OPASSIGN(>>) 1;
// }
public void testTokenPasteShiftROperaotr_261268() throws Exception {
final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
}
} }

View file

@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
import org.eclipse.cdt.core.dom.ast.IASTCastExpression; import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
@ -33,6 +34,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTDoStatement; import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpressionList;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference; import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
@ -5434,6 +5436,59 @@ public class AST2Tests extends AST2BaseTest {
} }
} }
// int a,b;
// void test() {
// 1+2+3 // 1,2,+,3,+
// a=b=1 // a,b,1,=,=
// 0, a= 1 ? 2,3 : b= 4, 5 // 0,a,1,2,3,,,b,4,=,?,=,5,,
// 1 ? 2 ? 3 : 4 ? 5 : 6 : 7 // 1,2,3,4,5,6,?,?,7,?
public void testBinaryExpressionBinding() throws Exception {
StringBuffer[] input= getContents(2);
String code= input[0].toString();
String[] samples= input[1].toString().split("\n");
for (ParserLanguage lang : ParserLanguage.values()) {
for (String s : samples) {
final String[] io= s.split("//");
final String exprStr = io[0].trim();
final IASTTranslationUnit tu= parse(code + exprStr + ";}", lang);
final IASTFunctionDefinition fdef= getDeclaration(tu, 1);
IASTExpression expr= getExpressionOfStatement(fdef, 0);
assertEquals("expr: " + exprStr, io[1].trim(), polnishNotation(expr));
assertEquals(exprStr, expr.getRawSignature());
checkOffsets(exprStr, expr);
}
}
}
// int a,b;
// void test(int a=
// 1+2+3 // 1,2,+,3,+
// a=b=1 // a,b,1,=,=
// 1 ? 2,3 : b= 4 // 1,2,3,,,b,4,=,?
// 1 ? 2 ? 3 : 4 ? 5 : 6 : 7 // 1,2,3,4,5,6,?,?,7,?
public void testConstantExpressionBinding() throws Exception {
StringBuffer[] input= getContents(2);
String code= input[0].toString();
String[] samples= input[1].toString().split("\n");
for (ParserLanguage lang : ParserLanguage.values()) {
for (String s : samples) {
final String[] io= s.split("//");
final String exprStr = io[0].trim();
final IASTTranslationUnit tu= parse(code + exprStr + "){}", lang);
final IASTFunctionDefinition fdef= getDeclaration(tu, 1);
IASTFunctionDeclarator fdtor= fdef.getDeclarator();
IASTParameterDeclaration pdecl= (IASTParameterDeclaration) fdtor.getChildren()[1];
IASTExpression expr= ((IASTInitializerExpression) pdecl.getDeclarator().getInitializer()).getExpression();
assertEquals("expr: " + exprStr, io[1].trim(), polnishNotation(expr));
assertEquals(exprStr, expr.getRawSignature());
checkOffsets(exprStr, expr);
}
}
}
private void checkOffsets(String exprStr, IASTExpression expr) { private void checkOffsets(String exprStr, IASTExpression expr) {
if (expr instanceof IASTBinaryExpression) { if (expr instanceof IASTBinaryExpression) {
IASTBinaryExpression bexpr= (IASTBinaryExpression) expr; IASTBinaryExpression bexpr= (IASTBinaryExpression) expr;
@ -5484,7 +5539,24 @@ public class AST2Tests extends AST2BaseTest {
} }
private void polnishNotation(IASTExpression expr, StringBuilder buf) { private void polnishNotation(IASTExpression expr, StringBuilder buf) {
if (expr instanceof IASTBinaryExpression) { if (expr instanceof IASTConditionalExpression) {
IASTConditionalExpression bexpr= (IASTConditionalExpression) expr;
polnishNotation(bexpr.getLogicalConditionExpression(), buf);
buf.append(',');
polnishNotation(bexpr.getPositiveResultExpression(), buf);
buf.append(',');
polnishNotation(bexpr.getNegativeResultExpression(), buf);
buf.append(',');
buf.append('?');
} else if (expr instanceof IASTExpressionList) {
IASTExpressionList bexpr= (IASTExpressionList) expr;
IASTExpression[] args = bexpr.getExpressions();
for (IASTExpression e : args) {
polnishNotation(e, buf);
buf.append(',');
}
buf.append(',');
} else if (expr instanceof IASTBinaryExpression) {
IASTBinaryExpression bexpr= (IASTBinaryExpression) expr; IASTBinaryExpression bexpr= (IASTBinaryExpression) expr;
polnishNotation(bexpr.getOperand1(), buf); polnishNotation(bexpr.getOperand1(), buf);
buf.append(','); buf.append(',');

View file

@ -68,12 +68,11 @@ public interface IScanner {
public void setContentAssistMode(int offset); public void setContentAssistMode(int offset);
/** /**
* Method has no effect. * Instructs the scanner to split tokens of kind {@link IToken#tSHIFTR} into two tokens of
* kind {@link IToken#tGT_in_SHIFTR}.
* @noreference This method is not intended to be referenced by clients. * @noreference This method is not intended to be referenced by clients.
* @since 4.0
*/ */
@Deprecated public void setSplitShiftROperator(boolean val);
public void setScanComments(boolean val);
/** /**
* Turns on/off creation of image locations. * Turns on/off creation of image locations.
@ -106,4 +105,10 @@ public interface IScanner {
* @noreference This method is not intended to be referenced by clients. * @noreference This method is not intended to be referenced by clients.
*/ */
public int getCodeBranchNesting(); public int getCodeBranchNesting();
/**
* @noreference This method is not intended to be referenced by clients.
*/
@Deprecated
public void setScanComments(boolean val);
} }

View file

@ -94,7 +94,11 @@ public interface IToken {
int tDOT = 50; int tDOT = 50;
int tDIVASSIGN = 51; int tDIVASSIGN = 51;
int tDIV = 52; int tDIV = 52;
/**
* @see IScanner#setSplitShiftROperator(boolean)
* @since 5.2
*/
int tGT_in_SHIFTR= 53;
/** @deprecated use {@link #tAND} */ @Deprecated int t_and = 54; /** @deprecated use {@link #tAND} */ @Deprecated int t_and = 54;
/** @deprecated use {@link #tAMPERASSIGN} */ @Deprecated int t_and_eq = 55; /** @deprecated use {@link #tAMPERASSIGN} */ @Deprecated int t_and_eq = 55;
int t_asm = 56; int t_asm = 56;

View file

@ -147,6 +147,13 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return PROCESS_CONTINUE; return PROCESS_CONTINUE;
} }
}; };
/**
* Information about the context in which a cast-expression is parsed:
* in a binary expression, in a binary expression in a template-id, or elsewhere.
*/
protected static enum CastExprCtx {eBExpr, eBExprInTmplID, eNotBExpr}
protected static enum ExprKind {eExpression, eAssignment, eConstant}
protected static final int DEFAULT_DESIGNATOR_LIST_SIZE = 4; protected static final int DEFAULT_DESIGNATOR_LIST_SIZE = 4;
protected static int parseCount = 0; protected static int parseCount = 0;
@ -184,7 +191,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected BacktrackException backtrack = new BacktrackException(); protected BacktrackException backtrack = new BacktrackException();
protected ASTCompletionNode completionNode; protected ASTCompletionNode completionNode;
protected IASTTypeId fTypeIdForCastAmbiguity;
private final INodeFactory nodeFactory; private final INodeFactory nodeFactory;
private boolean fActiveCode= true; private boolean fActiveCode= true;
@ -269,12 +275,13 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
} }
private final IToken nextToken(boolean skipInactive) throws EndOfFileException { private final IToken nextToken(boolean skipInactive) throws EndOfFileException {
IToken t= nextToken; final IToken t= nextToken;
if (t == null) { if (t != null)
t= fetchToken(skipInactive); return t;
}
nextToken= t; final IToken tn= fetchToken(skipInactive);
return t; nextToken= tn;
return tn;
} }
private final IToken lookaheadToken(int i, boolean skipInactive) throws EndOfFileException { private final IToken lookaheadToken(int i, boolean skipInactive) throws EndOfFileException {
@ -457,6 +464,18 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return result; return result;
} }
/**
* If the type of the next token matches, it is consumed and returned. Otherwise a
* {@link BacktrackException} will be thrown.
*/
protected final IToken consume(int type1, int type2) throws EndOfFileException, BacktrackException {
final IToken result= consume();
final int lt1 = result.getType();
if (lt1 != type1 && lt1 != type2)
throwBacktrack(result);
return result;
}
/** /**
* Consume the next token available only if the type is as specified. In case we reached the end of * Consume the next token available only if the type is as specified. In case we reached the end of
* completion, no token is consumed and the eoc-token returned. * completion, no token is consumed and the eoc-token returned.
@ -884,125 +903,71 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
* Models a cast expression followed by an operator. Can be linked into a chain. * Models a cast expression followed by an operator. Can be linked into a chain.
* This is done right to left, such that a tree of variants can be built. * This is done right to left, such that a tree of variants can be built.
*/ */
protected static class CastExpressionOp { protected static class BinaryOperator {
final CastExpressionOp fLeft;
final IASTExpression fExpression;
final int fOperatorToken; final int fOperatorToken;
final int fLeftPrecedence; final int fLeftPrecedence;
final int fRightPrecedence; final int fRightPrecedence;
BinaryOperator fNext;
IASTExpression fExpression;
final CastAmbiguityMarker fAmbiguityMarker;
public CastExpressionOp(CastExpressionOp left, IASTExpression expression, int operatorToken, int leftPrecedence, int rightPrecedence) { public BinaryOperator(BinaryOperator left, IASTExpression expression, int operatorToken, int leftPrecedence, int rightPrecedence) {
fLeft= left; fNext= left;
fExpression= expression;
fOperatorToken= operatorToken; fOperatorToken= operatorToken;
fLeftPrecedence= leftPrecedence; fLeftPrecedence= leftPrecedence;
fRightPrecedence= rightPrecedence; fRightPrecedence= rightPrecedence;
if (expression instanceof CastAmbiguityMarker) {
fAmbiguityMarker= (CastAmbiguityMarker) expression;
fExpression= fAmbiguityMarker.fExpression;
fAmbiguityMarker.fExpression= null;
} else {
fExpression= expression;
fAmbiguityMarker= null;
}
}
public IASTExpression exchange(IASTExpression expr) {
IASTExpression e= fExpression;
fExpression= expr;
return e;
} }
} }
/** protected final IASTExpression buildExpression(BinaryOperator leftChain, IASTExpression expr) throws BacktrackException {
* Helper class to temporarily store a sequence of operator followed by expression. BinaryOperator rightChain= null;
*/ for (;;) {
private static final class OpCastExpressionStack { if (leftChain == null) {
private IASTExpression fExpressions[]= new IASTExpression[128]; if (rightChain == null)
private int fPrecedenceAndTokens[]= new int[256]; return expr;
private int fPos=-1;
expr= buildExpression(expr, rightChain);
boolean isEmpty() { rightChain= rightChain.fNext;
return fPos<0; } else if (rightChain != null && leftChain.fRightPrecedence < rightChain.fLeftPrecedence) {
} expr= buildExpression(expr, rightChain);
rightChain= rightChain.fNext;
public IASTExpression getExpression() { } else {
return fExpressions[fPos]; BinaryOperator op= leftChain;
} leftChain= leftChain.fNext;
expr= op.exchange(expr);
public int getLeftPrecedence() { op.fNext= rightChain;
return fPrecedenceAndTokens[2*fPos]; rightChain= op;
}
public int getOperatorToken() {
return fPrecedenceAndTokens[2*fPos+1];
}
public void push(int leftPrecedence, int operatorToken, IASTExpression trailing) {
final int pos= ++fPos;
if (pos == fExpressions.length) {
IASTExpression newExpressions[]= new IASTExpression[pos*2];
int newPrecedenceAndTokens[]= new int[pos*4];
System.arraycopy(fExpressions, 0, newExpressions, 0, pos);
System.arraycopy(fPrecedenceAndTokens, 0, newPrecedenceAndTokens, 0, 2*pos);
fExpressions= newExpressions;
fPrecedenceAndTokens= newPrecedenceAndTokens;
} }
fExpressions[pos]= trailing;
fPrecedenceAndTokens[2*pos]= leftPrecedence;
fPrecedenceAndTokens[2*pos+1]= operatorToken;
}
public void pop() {
--fPos;
} }
} }
protected final IASTExpression buildExpression(CastExpressionOp exprOp1, IASTExpression expr) throws BacktrackException { private IASTExpression buildExpression(IASTExpression left, BinaryOperator operator) throws BacktrackException {
if (exprOp1 == null) int op, unaryOp= 0;
return expr; final IASTExpression right= operator.fExpression;
switch(operator.fOperatorToken) {
// exprOp1 exprOp2 expr
CastExpressionOp exprOp2= exprOp1;
exprOp1= exprOp1.fLeft;
OpCastExpressionStack stack= null;
while (exprOp1 != null) {
if (exprOp1.fRightPrecedence < exprOp2.fLeftPrecedence) {
// (exprOp2 expr) -> expr2
expr= buildExpression(exprOp2.fExpression, exprOp2.fOperatorToken, expr, stack);
if (stack != null) {
while (!stack.isEmpty() && exprOp1.fRightPrecedence < stack.getLeftPrecedence()) {
final int opToken= stack.getOperatorToken();
final IASTExpression expr2= stack.getExpression();
stack.pop();
expr= buildExpression(expr, opToken, expr2, stack);
}
}
} else {
// expr(Op2 expr) -> expr | op2 expr on stack
if (stack == null) {
stack= new OpCastExpressionStack();
}
stack.push(exprOp2.fLeftPrecedence, exprOp2.fOperatorToken, expr);
expr= exprOp2.fExpression;
}
exprOp2= exprOp1;
exprOp1= exprOp1.fLeft;
}
// (exprOp2 expr) -> expr2
expr= buildExpression(exprOp2.fExpression, exprOp2.fOperatorToken, expr, stack);
if (stack != null) {
while (!stack.isEmpty()) {
final int opToken= stack.getOperatorToken();
final IASTExpression expr2= stack.getExpression();
stack.pop();
expr= buildExpression(expr, opToken, expr2, stack);
}
}
return expr;
}
private IASTExpression buildExpression(IASTExpression left, int token, IASTExpression right, OpCastExpressionStack stack) throws BacktrackException {
int op, unaryOp=0;
switch(token) {
case IToken.tQUESTION: case IToken.tQUESTION:
if (stack == null || stack.isEmpty() || stack.getOperatorToken() != IToken.tCOLON) { if (operator.fNext == null || operator.fNext.fOperatorToken != IToken.tCOLON) {
assert false; assert false;
ASTNode node= (ASTNode) left; ASTNode node= (ASTNode) left;
throwBacktrack(node.getOffset(), node.getLength()); throwBacktrack(node.getOffset(), node.getLength());
return null; // Will never be reached. return null; // Will never be reached.
} }
IASTExpression negative= stack.getExpression(); IASTExpression negative= operator.fNext.fExpression;
stack.pop(); operator.fNext= operator.fNext.fNext;
IASTConditionalExpression conditionalEx = nodeFactory.newConditionalExpession(left, right, negative); IASTConditionalExpression conditionalEx = nodeFactory.newConditionalExpession(left, right, negative);
setRange(conditionalEx, left); setRange(conditionalEx, left);
if (negative != null) { if (negative != null) {
@ -1134,35 +1099,20 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return null; return null;
} }
CastAmbiguityMarker lca= null;
CastAmbiguityMarker rca= null;
if (left instanceof CastAmbiguityMarker) {
lca= (CastAmbiguityMarker) left;
left= lca.getExpression();
assert !(left instanceof CastAmbiguityMarker);
}
if (right instanceof CastAmbiguityMarker) {
rca= (CastAmbiguityMarker) right;
right= rca.getExpression();
assert !(right instanceof CastAmbiguityMarker);
}
IASTExpression result= buildBinaryExpression(op, left, right, calculateEndOffset(right)); IASTExpression result= buildBinaryExpression(op, left, right, calculateEndOffset(right));
final CastAmbiguityMarker am = operator.fAmbiguityMarker;
if (lca != null) { if (am != null) {
assert unaryOp != 0; assert unaryOp != 0;
result = createCastVsBinaryExpressionAmbiguity((IASTBinaryExpression) result, result = createCastVsBinaryExpressionAmbiguity((IASTBinaryExpression) result,
lca.getTypeIdForCast(), unaryOp, lca.getUnaryOperatorOffset()); am.getTypeIdForCast(), unaryOp, am.getUnaryOperatorOffset());
} }
return result;
return rca == null ? result : rca.updateExpression(result);
} }
protected abstract IASTExpression expression() throws BacktrackException, EndOfFileException; protected abstract IASTExpression expression() throws BacktrackException, EndOfFileException;
protected abstract IASTExpression assignmentExpression() throws EndOfFileException, BacktrackException;
protected abstract IASTExpression constantExpression() throws BacktrackException, EndOfFileException; protected abstract IASTExpression constantExpression() throws BacktrackException, EndOfFileException;
protected abstract IASTExpression unaryExpression(boolean inBinary) throws BacktrackException, EndOfFileException; protected abstract IASTExpression unaryExpression(CastExprCtx ctx) throws BacktrackException, EndOfFileException;
protected abstract IASTExpression primaryExpression() throws BacktrackException, EndOfFileException; protected abstract IASTExpression primaryExpression(CastExprCtx ctx) throws BacktrackException, EndOfFileException;
protected abstract IASTTypeId typeId(DeclarationOptions option) throws EndOfFileException; protected abstract IASTTypeId typeId(DeclarationOptions option) throws EndOfFileException;
private final static class CastAmbiguityMarker extends ASTNode implements IASTExpression { private final static class CastAmbiguityMarker extends ASTNode implements IASTExpression {
@ -1202,7 +1152,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
} }
} }
protected final IASTExpression castExpression(boolean inBinaryExpression) throws EndOfFileException, BacktrackException { protected final IASTExpression castExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
if (LT(1) == IToken.tLPAREN) { if (LT(1) == IToken.tLPAREN) {
final IToken mark= mark(); final IToken mark= mark();
final int startingOffset= mark.getOffset(); final int startingOffset= mark.getOffset();
@ -1211,7 +1161,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
if (typeId != null && LT(1) == IToken.tRPAREN) { if (typeId != null && LT(1) == IToken.tRPAREN) {
consume(); consume();
boolean unaryFailed= false; boolean unaryFailed= false;
if (inBinaryExpression) { if (ctx != CastExprCtx.eNotBExpr) {
switch (LT(1)){ switch (LT(1)){
// ambiguity with unary operator // ambiguity with unary operator
case IToken.tPLUS: case IToken.tMINUS: case IToken.tPLUS: case IToken.tMINUS:
@ -1220,7 +1170,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
IToken markEnd= mark(); IToken markEnd= mark();
backup(mark); backup(mark);
try { try {
IASTExpression unary= unaryExpression(false); IASTExpression unary= unaryExpression(CastExprCtx.eNotBExpr);
return new CastAmbiguityMarker(unary, typeId, operatorOffset); return new CastAmbiguityMarker(unary, typeId, operatorOffset);
} catch (BacktrackException bt) { } catch (BacktrackException bt) {
backup(markEnd); backup(markEnd);
@ -1230,7 +1180,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
} }
try { try {
boolean couldBeFunctionCall= LT(1) == IToken.tLPAREN; boolean couldBeFunctionCall= LT(1) == IToken.tLPAREN;
IASTExpression rhs= castExpression(inBinaryExpression); IASTExpression rhs= castExpression(ctx);
CastAmbiguityMarker ca= null; CastAmbiguityMarker ca= null;
if (rhs instanceof CastAmbiguityMarker) { if (rhs instanceof CastAmbiguityMarker) {
@ -1243,7 +1193,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
IToken markEnd= mark(); IToken markEnd= mark();
backup(mark); backup(mark);
try { try {
IASTExpression expr= primaryExpression(); IASTExpression expr= primaryExpression(ctx);
IASTFunctionCallExpression fcall = nodeFactory.newFunctionCallExpression(expr, null); IASTFunctionCallExpression fcall = nodeFactory.newFunctionCallExpression(expr, null);
IASTAmbiguousExpression ambiguity = createAmbiguousCastVsFunctionCallExpression(result, fcall); IASTAmbiguousExpression ambiguity = createAmbiguousCastVsFunctionCallExpression(result, fcall);
((ASTNode) ambiguity).setOffsetAndLength((ASTNode) result); ((ASTNode) ambiguity).setOffsetAndLength((ASTNode) result);
@ -1261,7 +1211,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
} }
backup(mark); backup(mark);
} }
return unaryExpression(inBinaryExpression); return unaryExpression(ctx);
} }
protected abstract IASTTranslationUnit getTranslationUnit(); protected abstract IASTTranslationUnit getTranslationUnit();
@ -1386,9 +1336,9 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return result; return result;
} }
protected IASTExpression unarayExpression(int operator, boolean inBinary) throws EndOfFileException, BacktrackException { protected IASTExpression unaryExpression(int operator, CastExprCtx ctx) throws EndOfFileException, BacktrackException {
final IToken operatorToken= consume(); final IToken operatorToken= consume();
IASTExpression operand= castExpression(inBinary); IASTExpression operand= castExpression(ctx);
CastAmbiguityMarker ca= null; CastAmbiguityMarker ca= null;
if (operand instanceof CastAmbiguityMarker) { if (operand instanceof CastAmbiguityMarker) {
@ -2185,7 +2135,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
} }
protected IASTExpression parseTypeidInParenthesisOrUnaryExpression(boolean exprIsLimitedToParenthesis, protected IASTExpression parseTypeidInParenthesisOrUnaryExpression(boolean exprIsLimitedToParenthesis,
int offset, int typeExprKind, int unaryExprKind, boolean inBinary) throws BacktrackException, EndOfFileException { int offset, int typeExprKind, int unaryExprKind, CastExprCtx ctx) throws BacktrackException, EndOfFileException {
IASTTypeId typeid; IASTTypeId typeid;
IASTExpression expr= null; IASTExpression expr= null;
IToken typeidLA= null; IToken typeidLA= null;
@ -2246,7 +2196,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
expr= expression(); expr= expression();
endOffset2= consumeOrEOC(IToken.tRPAREN).getEndOffset(); endOffset2= consumeOrEOC(IToken.tRPAREN).getEndOffset();
} else { } else {
expr= unaryExpression(inBinary); expr= unaryExpression(ctx);
if (expr instanceof CastAmbiguityMarker) { if (expr instanceof CastAmbiguityMarker) {
ca= (CastAmbiguityMarker) expr; ca= (CastAmbiguityMarker) expr;
expr= ca.getExpression(); expr= ca.getExpression();

View file

@ -145,7 +145,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
protected IASTInitializer cInitializerClause(boolean inAggregate) throws EndOfFileException, BacktrackException { protected IASTInitializer cInitializerClause(boolean inAggregate) throws EndOfFileException, BacktrackException {
final int offset = LA(1).getOffset(); final int offset = LA(1).getOffset();
if (LT(1) != IToken.tLBRACE) { if (LT(1) != IToken.tLBRACE) {
IASTExpression assignmentExpression= assignmentExpression(); IASTExpression assignmentExpression= expression(ExprKind.eAssignment);
if (inAggregate && skipTrivialExpressionsInAggregateInitializers) { if (inAggregate && skipTrivialExpressionsInAggregateInitializers) {
if (!ASTQueries.canContainName(assignmentExpression)) if (!ASTQueries.canContainName(assignmentExpression))
return null; return null;
@ -446,32 +446,29 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
@Override @Override
protected IASTExpression expression() throws BacktrackException, EndOfFileException { protected IASTExpression expression() throws BacktrackException, EndOfFileException {
return expression(true, true); return expression(ExprKind.eExpression);
} }
@Override
protected IASTExpression assignmentExpression() throws EndOfFileException, BacktrackException {
return expression(false, true);
}
@Override @Override
protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException { protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException {
return expression(false, false); return expression(ExprKind.eConstant);
} }
private IASTExpression expression(boolean allowComma, boolean allowAssignment) throws BacktrackException, EndOfFileException { private IASTExpression expression(final ExprKind kind) throws EndOfFileException, BacktrackException {
final boolean allowComma= kind==ExprKind.eExpression;
boolean allowAssignment= kind !=ExprKind.eConstant;
int lt1; int lt1;
int conditionCount= 0; int conditionCount= 0;
CastExpressionOp lastComponent= null; BinaryOperator lastOperator= null;
IASTExpression lastExpression= castExpression(true); IASTExpression lastExpression= castExpression(CastExprCtx.eBExpr);
loop: while(true) { loop: while(true) {
lt1= LT(1); lt1= LT(1);
switch(lt1) { switch(lt1) {
case IToken.tQUESTION: case IToken.tQUESTION:
conditionCount++; conditionCount++;
// <logical-or> ? <expression> : <assignment-expression> // <logical-or> ? <expression> : <assignment-expression>
// Precedence: 25 is lower than precedence of logical or; 1 is lower than precedence of expression // Precedence: 25 is lower than precedence of logical or; 0 is lower than precedence of expression
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 25, 1); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 25, 0);
if (LT(2) == IToken.tCOLON) { if (LT(2) == IToken.tCOLON) {
// Gnu extension: The expression after '?' can be omitted. // Gnu extension: The expression after '?' can be omitted.
consume(); // Consume operator consume(); // Consume operator
@ -487,7 +484,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
// <logical-or> ? <expression> : <assignment-expression> // <logical-or> ? <expression> : <assignment-expression>
// Precedence: 0 is lower than precedence of expression; 15 is lower than precedence of assignment; // Precedence: 0 is lower than precedence of expression; 15 is lower than precedence of assignment;
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 0, 15); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 0, 15);
allowAssignment= true; // assignment expressions will be subsumed by the conditional expression allowAssignment= true; // assignment expressions will be subsumed by the conditional expression
break; break;
@ -495,7 +492,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
if (!allowComma && conditionCount == 0) if (!allowComma && conditionCount == 0)
break loop; break loop;
// Lowest precedence except inside the conditional expression // Lowest precedence except inside the conditional expression
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 10, 11); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 10, 11);
break; break;
case IToken.tASSIGN: case IToken.tASSIGN:
@ -512,27 +509,27 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
if (!allowAssignment && conditionCount == 0) if (!allowAssignment && conditionCount == 0)
break loop; break loop;
// Assignments group right to left // Assignments group right to left
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 21, 20); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 21, 20);
break; break;
case IToken.tOR: case IToken.tOR:
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 30, 31); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 30, 31);
break; break;
case IToken.tAND: case IToken.tAND:
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 40, 41); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 40, 41);
break; break;
case IToken.tBITOR: case IToken.tBITOR:
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 50, 51); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 50, 51);
break; break;
case IToken.tXOR: case IToken.tXOR:
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 60, 61); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 60, 61);
break; break;
case IToken.tAMPER: case IToken.tAMPER:
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 70, 71); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 70, 71);
break; break;
case IToken.tEQUAL: case IToken.tEQUAL:
case IToken.tNOTEQUAL: case IToken.tNOTEQUAL:
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 80, 81); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 80, 81);
break; break;
case IToken.tGT: case IToken.tGT:
case IToken.tLT: case IToken.tLT:
@ -540,70 +537,70 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
case IToken.tGTEQUAL: case IToken.tGTEQUAL:
case IGCCToken.tMAX: case IGCCToken.tMAX:
case IGCCToken.tMIN: case IGCCToken.tMIN:
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 90, 91); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 90, 91);
break; break;
case IToken.tSHIFTL: case IToken.tSHIFTL:
case IToken.tSHIFTR: case IToken.tSHIFTR:
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 100, 101); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 100, 101);
break; break;
case IToken.tPLUS: case IToken.tPLUS:
case IToken.tMINUS: case IToken.tMINUS:
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 110, 111); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 110, 111);
break; break;
case IToken.tSTAR: case IToken.tSTAR:
case IToken.tDIV: case IToken.tDIV:
case IToken.tMOD: case IToken.tMOD:
lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 120, 121); lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 120, 121);
break; break;
default: default:
break loop; break loop;
} }
consume(); // consume operator consume(); // consume operator
lastExpression= castExpression(true); // next cast expression lastExpression= castExpression(CastExprCtx.eBExpr); // next cast expression
} }
// Check for incomplete conditional expression // Check for incomplete conditional expression
if (lt1 != IToken.tEOC && conditionCount > 0) if (lt1 != IToken.tEOC && conditionCount > 0)
throwBacktrack(LA(1)); throwBacktrack(LA(1));
return buildExpression(lastComponent, lastExpression); return buildExpression(lastOperator, lastExpression);
} }
@Override @Override
protected IASTExpression unaryExpression(boolean inBinary) throws EndOfFileException, BacktrackException { protected IASTExpression unaryExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
switch (LT(1)) { switch (LT(1)) {
case IToken.tSTAR: case IToken.tSTAR:
return unarayExpression(IASTUnaryExpression.op_star, inBinary); return unaryExpression(IASTUnaryExpression.op_star, ctx);
case IToken.tAMPER: case IToken.tAMPER:
return unarayExpression(IASTUnaryExpression.op_amper, inBinary); return unaryExpression(IASTUnaryExpression.op_amper, ctx);
case IToken.tPLUS: case IToken.tPLUS:
return unarayExpression(IASTUnaryExpression.op_plus, inBinary); return unaryExpression(IASTUnaryExpression.op_plus, ctx);
case IToken.tMINUS: case IToken.tMINUS:
return unarayExpression(IASTUnaryExpression.op_minus, inBinary); return unaryExpression(IASTUnaryExpression.op_minus, ctx);
case IToken.tNOT: case IToken.tNOT:
return unarayExpression(IASTUnaryExpression.op_not, inBinary); return unaryExpression(IASTUnaryExpression.op_not, ctx);
case IToken.tBITCOMPLEMENT: case IToken.tBITCOMPLEMENT:
return unarayExpression(IASTUnaryExpression.op_tilde, inBinary); return unaryExpression(IASTUnaryExpression.op_tilde, ctx);
case IToken.tINCR: case IToken.tINCR:
return unarayExpression(IASTUnaryExpression.op_prefixIncr, inBinary); return unaryExpression(IASTUnaryExpression.op_prefixIncr, ctx);
case IToken.tDECR: case IToken.tDECR:
return unarayExpression(IASTUnaryExpression.op_prefixDecr, inBinary); return unaryExpression(IASTUnaryExpression.op_prefixDecr, ctx);
case IToken.t_sizeof: case IToken.t_sizeof:
return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof, inBinary); IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof, ctx);
case IGCCToken.t_typeof: case IGCCToken.t_typeof:
return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IASTTypeIdExpression.op_typeof, IASTUnaryExpression.op_typeof, inBinary); IASTTypeIdExpression.op_typeof, IASTUnaryExpression.op_typeof, ctx);
case IGCCToken.t___alignof__: case IGCCToken.t___alignof__:
return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf, inBinary); IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf, ctx);
default: default:
return postfixExpression(); return postfixExpression(ctx);
} }
} }
protected IASTExpression postfixExpression() throws EndOfFileException, BacktrackException { protected IASTExpression postfixExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
IASTExpression firstExpression = null; IASTExpression firstExpression = null;
switch (LT(1)) { switch (LT(1)) {
case IToken.tLPAREN: case IToken.tLPAREN:
@ -625,11 +622,11 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
} catch (BacktrackException bt) { } catch (BacktrackException bt) {
} }
backup(m); backup(m);
firstExpression= primaryExpression(); firstExpression= primaryExpression(ctx);
break; break;
default: default:
firstExpression = primaryExpression(); firstExpression = primaryExpression(ctx);
break; break;
} }
@ -719,7 +716,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
} }
@Override @Override
protected IASTExpression primaryExpression() throws EndOfFileException, BacktrackException { protected IASTExpression primaryExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
IToken t = null; IToken t = null;
IASTLiteralExpression literalExpression = null; IASTLiteralExpression literalExpression = null;
switch (LT(1)) { switch (LT(1)) {
@ -755,7 +752,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
return compoundStatementExpression(); return compoundStatementExpression();
} }
t = consume(); t = consume();
IASTExpression lhs = expression(true, true); // instead of expression(), to keep the stack smaller IASTExpression lhs = expression(ExprKind.eExpression); // instead of expression(), to keep the stack smaller
int finalOffset = 0; int finalOffset = 0;
switch (LT(1)) { switch (LT(1)) {
case IToken.tRPAREN: case IToken.tRPAREN:
@ -1085,7 +1082,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
throwBacktrack(LA(1)); throwBacktrack(LA(1));
typeofExpression = parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), typeofExpression = parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IGNUASTTypeIdExpression.op_typeof, IGNUASTUnaryExpression.op_typeof, false); IGNUASTTypeIdExpression.op_typeof, IGNUASTUnaryExpression.op_typeof, CastExprCtx.eNotBExpr);
encounteredTypename= true; encounteredTypename= true;
endOffset= calculateEndOffset(typeofExpression); endOffset= calculateEndOffset(typeofExpression);
@ -1705,7 +1702,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
if (LT(1) != IToken.tRBRACKET) { if (LT(1) != IToken.tRBRACKET) {
if (!(isStatic || isRestrict || isConst || isVolatile)) if (!(isStatic || isRestrict || isConst || isVolatile))
exp = assignmentExpression(); exp = expression(ExprKind.eAssignment);
else else
exp = constantExpression(); exp = constantExpression();
} }

View file

@ -150,7 +150,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
protected ICPPASTTranslationUnit translationUnit; protected ICPPASTTranslationUnit translationUnit;
private int functionBodyCount= 0; private int functionBodyCount= 0;
private int rejectLogicalOperatorInTemplateID= 0;
private char[] currentClassName; private char[] currentClassName;
private final ICPPNodeFactory nodeFactory; private final ICPPNodeFactory nodeFactory;
@ -181,6 +180,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
functionCallCanBeLValue= true; functionCallCanBeLValue= true;
this.index= index; this.index= index;
this.nodeFactory = CPPNodeFactory.getDefault(); this.nodeFactory = CPPNodeFactory.getDefault();
scanner.setSplitShiftROperator(true);
} }
@Override @Override
@ -195,15 +195,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
throw backtrack; throw backtrack;
} }
protected IASTName idExpression() throws EndOfFileException, BacktrackException {
try {
rejectLogicalOperatorInTemplateID++;
return qualifiedName();
} finally {
rejectLogicalOperatorInTemplateID--;
}
}
/** /**
* Parse a name. * Parse a name.
* name ::= ("::")? name2 ("::" name2)* * name ::= ("::")? name2 ("::" name2)*
@ -211,7 +202,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
* *
* @throws BacktrackException request a backtrack * @throws BacktrackException request a backtrack
*/ */
private IASTName qualifiedName() throws BacktrackException, EndOfFileException { private IASTName qualifiedName(CastExprCtx ctx) throws BacktrackException, EndOfFileException {
ICPPASTQualifiedName qname= null; ICPPASTQualifiedName qname= null;
IASTName name= null; IASTName name= null;
final int offset= LA(1).getOffset(); final int offset= LA(1).getOffset();
@ -261,7 +252,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
} }
haveName= true; haveName= true;
name= addTemplateArguments(name); name= addTemplateArguments(name, ctx);
endOffset= calculateEndOffset(name); endOffset= calculateEndOffset(name);
if (qname != null) { if (qname != null) {
qname.addName(name); qname.addName(name);
@ -309,24 +300,23 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return name; return name;
} }
private IASTName addTemplateArguments(IASTName templateName) throws EndOfFileException, BacktrackException { private IASTName addTemplateArguments(IASTName templateName, CastExprCtx ctx) throws EndOfFileException, BacktrackException {
if (!canBeTemplateArguments()) boolean isAmbiguous= false;
return templateName; switch(canBeTemplateArguments(ctx)) {
case -1:
return templateName;
case 0:
isAmbiguous= true;
break;
}
IToken secondMark = mark(); IToken secondMark = mark();
consume(IToken.tLT); consume(IToken.tLT);
try { try {
// bug 229062: content assist after '<' needs to prefer to backtrack here List<IASTNode> list = templateArgumentList(isAmbiguous);
if (rejectLogicalOperatorInTemplateID == 1) {
final int lt1= LT(1);
if (lt1 == IToken.tCOMPLETION || lt1 == IToken.tEOC) {
throw backtrack;
}
}
List<IASTNode> list = templateArgumentList();
IToken end= LA(1); IToken end= LA(1);
switch(end.getType()) { switch(end.getType()) {
case IToken.tGT_in_SHIFTR:
case IToken.tGT: case IToken.tGT:
consume(); consume();
break; break;
@ -360,34 +350,109 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
/** /**
* Makes a fast check whether there could be template arguments. * Makes a fast check whether there could be template arguments.
*/ */
private boolean canBeTemplateArguments() throws EndOfFileException, BacktrackException { private int canBeTemplateArguments(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
if (LTcatchEOF(1) != IToken.tLT) if (LTcatchEOF(1) != IToken.tLT)
return false; return -1;
final IToken mark= mark(); final IToken mark= mark();
try { try {
consume(); consume();
int nk= 0; int nk= 0;
int depth= 0; int depth= 0;
int angleDepth= 0; int angleDepth= 0;
int limit= 100; int limit= 10000;
while(--limit > 0) { while(--limit > 0) {
switch(consume().getType()) { switch(consume().getType()) {
case IToken.tEOC: case IToken.tEOC:
case IToken.tCOMPLETION: case IToken.tCOMPLETION:
return true; return ctx == CastExprCtx.eNotBExpr ? 0 : -1;
case IToken.tLT: case IToken.tLT:
if (nk == 0) { if (nk == 0) {
angleDepth++; angleDepth++;
} }
break; break;
case IToken.tGT_in_SHIFTR:
case IToken.tGT: case IToken.tGT:
if (nk == 0) { if (nk == 0) {
if (--angleDepth < 0) { if (--angleDepth < 0) {
final int lt1= LTcatchEOF(1); if (ctx == CastExprCtx.eNotBExpr)
return (lt1 != IToken.tINTEGER && lt1 != IToken.tFLOATINGPT); return 1;
int lt1= LTcatchEOF(1);
if (lt1 == IToken.tGT_in_SHIFTR) {
if (ctx != CastExprCtx.eBExprInTmplID)
return -1;
// do the same check for the enclosing template
lt1= LTcatchEOF(2);
}
switch(lt1) {
// can be some cast-expression or continuation after template-id
case IToken.tCOLONCOLON: // CT<int>::member
case IToken.tLPAREN: // ft<int>(args)
return 0;
// end of an expression
// unary expression
case IToken.tMINUS:
case IToken.tPLUS:
case IToken.tAMPER:
case IToken.tSTAR:
case IToken.tNOT:
case IToken.tBITCOMPLEMENT:
case IToken.tINCR:
case IToken.tDECR:
case IToken.t_new:
case IToken.t_delete:
case IToken.t_sizeof:
case IGCCToken.t_typeof:
case IGCCToken.t___alignof__:
// postfix expression
case IToken.t_typename:
case IToken.t_char:
case IToken.t_wchar_t:
case IToken.t_bool:
case IToken.t_short:
case IToken.t_int:
case IToken.t_long:
case IToken.t_signed:
case IToken.t_unsigned:
case IToken.t_float:
case IToken.t_double:
case IToken.t_dynamic_cast:
case IToken.t_static_cast:
case IToken.t_reinterpret_cast:
case IToken.t_const_cast:
case IToken.t_typeid:
// primary expression
case IToken.tINTEGER:
case IToken.tFLOATINGPT:
case IToken.tSTRING:
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
case IToken.tCHAR:
case IToken.tLCHAR:
case IToken.tUTF16CHAR:
case IToken.tUTF32CHAR:
case IToken.t_false:
case IToken.t_true:
case IToken.t_this:
case IToken.tIDENTIFIER:
case IToken.t_operator:
case IToken.tCOMPLETION:
return -1;
// ending an expression
case IToken.tSEMI:
case IToken.tCOMMA:
case IToken.tRBRACE:
case IToken.tRBRACKET:
case IToken.tRPAREN:
return 1;
// don't know
default:
return 0;
}
} }
} }
break; break;
@ -426,31 +491,33 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
case IToken.tLBRACE: case IToken.tLBRACE:
case IToken.tRBRACE: case IToken.tRBRACE:
if (nk == 0) { if (nk == 0) {
return false; return -1;
} }
break; break;
} }
} }
return true; return 0;
} finally { } finally {
backup(mark); backup(mark);
} }
} }
private List<IASTNode> templateArgumentList() throws EndOfFileException, BacktrackException { private List<IASTNode> templateArgumentList(boolean isAmbiguous) throws EndOfFileException, BacktrackException {
IToken start = LA(1); IToken start = LA(1);
int startingOffset = start.getOffset(); int startingOffset = start.getOffset();
int endOffset = 0; int endOffset = 0;
start = null; start = null;
List<IASTNode> list = new ArrayList<IASTNode>(); List<IASTNode> list = new ArrayList<IASTNode>();
final BinaryExprCtx exprCtx = isAmbiguous ? BinaryExprCtx.eAmbigTmplID : BinaryExprCtx.eTmplID;
boolean failed = false; boolean failed = false;
int lt1= LT(1);
while (LT(1) != IToken.tGT && LT(1) != IToken.tEOC) { while (lt1 != IToken.tGT && lt1 != IToken.tGT_in_SHIFTR && lt1 != IToken.tEOC) {
IToken argStart = mark(); IToken argStart = mark();
IASTTypeId typeId = typeId(DeclarationOptions.TYPEID); IASTTypeId typeId = typeId(DeclarationOptions.TYPEID);
if(typeId != null && (LT(1)==IToken.tCOMMA || LT(1)==IToken.tGT || LT(1)==IToken.tEOC)) { lt1 = LT(1);
if(typeId != null && (lt1==IToken.tCOMMA || lt1==IToken.tGT || lt1 == IToken.tGT_in_SHIFTR || lt1==IToken.tEOC)) {
// potentially a type-id - check for id-expression ambiguity // potentially a type-id - check for id-expression ambiguity
IToken typeIdEnd= mark(); IToken typeIdEnd= mark();
try { try {
@ -470,7 +537,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
throw backtrack; throw backtrack;
backup(argStart); backup(argStart);
IASTExpression expression = expression(false, true, true); IASTExpression expression = expression(ExprKind.eAssignment, exprCtx);
if (expression instanceof IASTIdExpression) { if (expression instanceof IASTIdExpression) {
if (mark() != typeIdEnd) if (mark() != typeIdEnd)
throw backtrack; throw backtrack;
@ -491,13 +558,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
} else { } else {
// not a type-id - try as expression // not a type-id - try as expression
backup(argStart); backup(argStart);
IASTExpression expression = expression(false, true, true); IASTExpression expression = expression(ExprKind.eAssignment, exprCtx);
list.add(expression); list.add(expression);
} }
if (LT(1) == IToken.tCOMMA) { lt1= LT(1);
if (lt1 == IToken.tCOMMA) {
consume(); consume();
} else if (LT(1) != IToken.tGT && LT(1) != IToken.tEOC) { lt1= LT(1);
} else if (lt1 != IToken.tGT && lt1 != IToken.tGT_in_SHIFTR && lt1 != IToken.tEOC) {
failed = true; failed = true;
endOffset = LA(1).getEndOffset(); endOffset = LA(1).getEndOffset();
break; break;
@ -539,6 +608,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
op= OverloadableOperator.valueOf(t); op= OverloadableOperator.valueOf(t);
} }
break; break;
case IToken.tGT_in_SHIFTR:
consume();
endOffset= consume(IToken.tGT_in_SHIFTR).getEndOffset();
op= OverloadableOperator.SHIFTR;
break;
default: default:
op= OverloadableOperator.valueOf(LA(1)); op= OverloadableOperator.valueOf(LA(1));
if (op != null) { if (op != null) {
@ -564,30 +638,36 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return name; return name;
} }
/**
* Information for the parser, whether a binary expression is parsed in the context of a
* template-id an ambiguous template-id (one where the '<' could be a greater sign) or
* else where.
*/
private enum BinaryExprCtx {eTmplID, eAmbigTmplID, eNoTmplID}
@Override @Override
protected IASTExpression expression() throws BacktrackException, EndOfFileException { protected IASTExpression expression() throws BacktrackException, EndOfFileException {
return expression(true, true, false); return expression(ExprKind.eExpression, BinaryExprCtx.eNoTmplID);
} }
@Override
protected IASTExpression assignmentExpression() throws EndOfFileException, BacktrackException {
return expression(false, true, false);
}
@Override @Override
protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException { protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException {
return expression(false, false, false); return expression(ExprKind.eConstant, BinaryExprCtx.eNoTmplID);
} }
private IASTExpression expression(boolean allowComma, boolean allowAssignment, boolean onTopOfTemplateArgs) throws EndOfFileException, BacktrackException { private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx) throws EndOfFileException, BacktrackException {
final boolean allowComma= kind==ExprKind.eExpression;
boolean allowAssignment= kind !=ExprKind.eConstant;
final CastExprCtx castCtx= ctx == BinaryExprCtx.eNoTmplID ? CastExprCtx.eBExpr : CastExprCtx.eBExprInTmplID;
if (allowAssignment && LT(1) == IToken.t_throw) { if (allowAssignment && LT(1) == IToken.t_throw) {
return throwExpression(); return throwExpression();
} }
int lt1; int lt1;
int conditionCount= 0; int conditionCount= 0;
CastExpressionOp lastComponent= null; BinaryOperator lastOperator= null;
IASTExpression expr= castExpression(true); IASTExpression expr= castExpression(castCtx);
loop: while(true) { loop: while(true) {
// typically after a binary operator there cannot be a throw expression // typically after a binary operator there cannot be a throw expression
@ -595,13 +675,13 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
lt1= LT(1); lt1= LT(1);
switch(lt1) { switch(lt1) {
case IToken.tQUESTION: case IToken.tQUESTION:
if (onTopOfTemplateArgs && rejectLogicalOperatorInTemplateID > 0) { if (ctx == BinaryExprCtx.eAmbigTmplID) {
throwBacktrack(LA(1)); throwBacktrack(LA(1));
} }
conditionCount++; conditionCount++;
// <logical-or> ? <expression> : <assignment-expression> // <logical-or> ? <expression> : <assignment-expression>
// Precedence: 25 is lower than precedence of logical or; 1 is lower than precedence of expression // Precedence: 25 is lower than precedence of logical or; 0 is lower than precedence of expression
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 25, 1); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 25, 0);
if (LT(2) == IToken.tCOLON) { if (LT(2) == IToken.tCOLON) {
// Gnu extension: The expression after '?' can be omitted. // Gnu extension: The expression after '?' can be omitted.
consume(); // Consume operator consume(); // Consume operator
@ -618,7 +698,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// <logical-or> ? <expression> : <assignment-expression> // <logical-or> ? <expression> : <assignment-expression>
// Precedence: 0 is lower than precedence of expression; 15 is lower than precedence of assignment; // Precedence: 0 is lower than precedence of expression; 15 is lower than precedence of assignment;
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 0, 15); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 0, 15);
allowAssignment= true; // assignment expressions will be subsumed by the conditional expression allowAssignment= true; // assignment expressions will be subsumed by the conditional expression
allowThrow= true; allowThrow= true;
break; break;
@ -628,7 +708,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
if (!allowComma && conditionCount == 0) if (!allowComma && conditionCount == 0)
break loop; break loop;
// Lowest precedence except inside the conditional expression // Lowest precedence except inside the conditional expression
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 10, 11); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 10, 11);
break; break;
case IToken.tASSIGN: case IToken.tASSIGN:
@ -645,36 +725,36 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
if (!allowAssignment && conditionCount == 0) if (!allowAssignment && conditionCount == 0)
break loop; break loop;
// Assignments group right to left // Assignments group right to left
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 21, 20); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 21, 20);
break; break;
case IToken.tOR: case IToken.tOR:
if (onTopOfTemplateArgs && rejectLogicalOperatorInTemplateID > 0) { if (ctx == BinaryExprCtx.eAmbigTmplID) {
throwBacktrack(LA(1)); throwBacktrack(LA(1));
} }
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 30, 31); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 30, 31);
break; break;
case IToken.tAND: case IToken.tAND:
if (onTopOfTemplateArgs && rejectLogicalOperatorInTemplateID > 0) { if (ctx == BinaryExprCtx.eAmbigTmplID) {
throwBacktrack(LA(1)); throwBacktrack(LA(1));
} }
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 40, 41); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 40, 41);
break; break;
case IToken.tBITOR: case IToken.tBITOR:
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 50, 51); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 50, 51);
break; break;
case IToken.tXOR: case IToken.tXOR:
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 60, 61); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 60, 61);
break; break;
case IToken.tAMPER: case IToken.tAMPER:
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 70, 71); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 70, 71);
break; break;
case IToken.tEQUAL: case IToken.tEQUAL:
case IToken.tNOTEQUAL: case IToken.tNOTEQUAL:
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 80, 81); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 80, 81);
break; break;
case IToken.tGT: case IToken.tGT:
if (onTopOfTemplateArgs) if (ctx != BinaryExprCtx.eNoTmplID)
break loop; break loop;
//$FALL-THROUGH$ //$FALL-THROUGH$
case IToken.tLT: case IToken.tLT:
@ -682,24 +762,33 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
case IToken.tGTEQUAL: case IToken.tGTEQUAL:
case IGCCToken.tMAX: case IGCCToken.tMAX:
case IGCCToken.tMIN: case IGCCToken.tMIN:
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 90, 91); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 90, 91);
break; break;
case IToken.tSHIFTL: case IToken.tGT_in_SHIFTR:
if (ctx != BinaryExprCtx.eNoTmplID)
break loop;
if (LT(2) != IToken.tGT_in_SHIFTR) {
throwBacktrack(LA(1));
}
lt1= IToken.tSHIFTR; // convert back
consume(); // consume the extra token
//$FALL-THROUGH$
case IToken.tSHIFTL:
case IToken.tSHIFTR: case IToken.tSHIFTR:
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 100, 101); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 100, 101);
break; break;
case IToken.tPLUS: case IToken.tPLUS:
case IToken.tMINUS: case IToken.tMINUS:
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 110, 111); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 110, 111);
break; break;
case IToken.tSTAR: case IToken.tSTAR:
case IToken.tDIV: case IToken.tDIV:
case IToken.tMOD: case IToken.tMOD:
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 120, 121); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 120, 121);
break; break;
case IToken.tDOTSTAR: case IToken.tDOTSTAR:
case IToken.tARROWSTAR: case IToken.tARROWSTAR:
lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 130, 131); lastOperator= new BinaryOperator(lastOperator, expr, lt1, 130, 131);
break; break;
default: default:
break loop; break loop;
@ -716,14 +805,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
break loop; break loop;
} }
} }
expr= castExpression(true); // next cast expression expr= castExpression(castCtx); // next cast expression
} }
// Check for incomplete conditional expression // Check for incomplete conditional expression
if (lt1 != IToken.tEOC && conditionCount > 0) if (lt1 != IToken.tEOC && conditionCount > 0)
throwBacktrack(LA(1)); throwBacktrack(LA(1));
return buildExpression(lastComponent, expr); return buildExpression(lastOperator, expr);
} }
private IASTExpression throwExpression() throws EndOfFileException, BacktrackException { private IASTExpression throwExpression() throws EndOfFileException, BacktrackException {
@ -759,7 +848,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
consume(IToken.tRBRACKET); consume(IToken.tRBRACKET);
vectored = true; vectored = true;
} }
IASTExpression castExpression = castExpression(false); IASTExpression castExpression = castExpression(CastExprCtx.eNotBExpr);
ICPPASTDeleteExpression deleteExpression = nodeFactory.newDeleteExpression(castExpression); ICPPASTDeleteExpression deleteExpression = nodeFactory.newDeleteExpression(castExpression);
((ASTNode) deleteExpression).setOffsetAndLength(startingOffset, calculateEndOffset(castExpression) - startingOffset); ((ASTNode) deleteExpression).setOffsetAndLength(startingOffset, calculateEndOffset(castExpression) - startingOffset);
deleteExpression.setIsGlobal(global); deleteExpression.setIsGlobal(global);
@ -901,24 +990,24 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
@Override @Override
protected IASTExpression unaryExpression(boolean inBinaryExpression) throws EndOfFileException, BacktrackException { protected IASTExpression unaryExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
switch (LT(1)) { switch (LT(1)) {
case IToken.tSTAR: case IToken.tSTAR:
return unarayExpression(IASTUnaryExpression.op_star, inBinaryExpression); return unaryExpression(IASTUnaryExpression.op_star, ctx);
case IToken.tAMPER: case IToken.tAMPER:
return unarayExpression(IASTUnaryExpression.op_amper, inBinaryExpression); return unaryExpression(IASTUnaryExpression.op_amper, ctx);
case IToken.tPLUS: case IToken.tPLUS:
return unarayExpression(IASTUnaryExpression.op_plus, inBinaryExpression); return unaryExpression(IASTUnaryExpression.op_plus, ctx);
case IToken.tMINUS: case IToken.tMINUS:
return unarayExpression(IASTUnaryExpression.op_minus, inBinaryExpression); return unaryExpression(IASTUnaryExpression.op_minus, ctx);
case IToken.tNOT: case IToken.tNOT:
return unarayExpression(IASTUnaryExpression.op_not, inBinaryExpression); return unaryExpression(IASTUnaryExpression.op_not, ctx);
case IToken.tBITCOMPLEMENT: case IToken.tBITCOMPLEMENT:
return unarayExpression(IASTUnaryExpression.op_tilde, inBinaryExpression); return unaryExpression(IASTUnaryExpression.op_tilde, ctx);
case IToken.tINCR: case IToken.tINCR:
return unarayExpression(IASTUnaryExpression.op_prefixIncr, inBinaryExpression); return unaryExpression(IASTUnaryExpression.op_prefixIncr, ctx);
case IToken.tDECR: case IToken.tDECR:
return unarayExpression(IASTUnaryExpression.op_prefixDecr, inBinaryExpression); return unaryExpression(IASTUnaryExpression.op_prefixDecr, ctx);
case IToken.t_new: case IToken.t_new:
return newExpression(); return newExpression();
case IToken.t_delete: case IToken.t_delete:
@ -930,23 +1019,23 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
case IToken.t_delete: case IToken.t_delete:
return deleteExpression(); return deleteExpression();
default: default:
return postfixExpression(inBinaryExpression); return postfixExpression(ctx);
} }
case IToken.t_sizeof: case IToken.t_sizeof:
return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof, inBinaryExpression); IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof, ctx);
case IGCCToken.t_typeof: case IGCCToken.t_typeof:
return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IASTTypeIdExpression.op_typeof, IASTUnaryExpression.op_typeof, inBinaryExpression); IASTTypeIdExpression.op_typeof, IASTUnaryExpression.op_typeof, ctx);
case IGCCToken.t___alignof__: case IGCCToken.t___alignof__:
return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf, inBinaryExpression); IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf, ctx);
default: default:
return postfixExpression(inBinaryExpression); return postfixExpression(ctx);
} }
} }
private IASTExpression postfixExpression(boolean inBinaryExpression) throws EndOfFileException, BacktrackException { private IASTExpression postfixExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
IASTExpression firstExpression = null; IASTExpression firstExpression = null;
boolean isTemplate = false; boolean isTemplate = false;
@ -970,7 +1059,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
} catch (BacktrackException bt) { } catch (BacktrackException bt) {
} }
backup(m); backup(m);
firstExpression= primaryExpression(); firstExpression= primaryExpression(ctx);
break; break;
case IToken.t_typename: case IToken.t_typename:
@ -981,7 +1070,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
consume(); consume();
templateTokenConsumed = true; templateTokenConsumed = true;
} }
IASTName name = idExpression(); IASTName name = qualifiedName(CastExprCtx.eNotBExpr); // treat as not in binary to force template arguments
if (LT(1) != IToken.tLPAREN) { if (LT(1) != IToken.tLPAREN) {
throwBacktrack(LA(1)); throwBacktrack(LA(1));
} }
@ -1036,11 +1125,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
case IToken.t_typeid: case IToken.t_typeid:
int so = consume().getOffset(); int so = consume().getOffset();
firstExpression = parseTypeidInParenthesisOrUnaryExpression(true, so, firstExpression = parseTypeidInParenthesisOrUnaryExpression(true, so,
ICPPASTTypeIdExpression.op_typeid, ICPPASTUnaryExpression.op_typeid, inBinaryExpression); ICPPASTTypeIdExpression.op_typeid, ICPPASTUnaryExpression.op_typeid, ctx);
break; break;
default: default:
firstExpression = primaryExpression(); firstExpression = primaryExpression(ctx);
break; break;
} }
IASTExpression secondExpression = null; IASTExpression secondExpression = null;
@ -1107,7 +1196,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
isTemplate = true; isTemplate = true;
} }
IASTName name = idExpression(); IASTName name = qualifiedName(ctx);
if (name == null) if (name == null)
throwBacktrack(((ASTNode) firstExpression).getOffset(), throwBacktrack(((ASTNode) firstExpression).getOffset(),
@ -1130,7 +1219,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
isTemplate = true; isTemplate = true;
} }
name = idExpression(); name = qualifiedName(ctx);
if (name == null) if (name == null)
throwBacktrack(((ASTNode) firstExpression).getOffset(), throwBacktrack(((ASTNode) firstExpression).getOffset(),
@ -1185,7 +1274,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
@Override @Override
protected IASTExpression primaryExpression() throws EndOfFileException, BacktrackException { protected IASTExpression primaryExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
IToken t = null; IToken t = null;
IASTLiteralExpression literalExpression = null; IASTLiteralExpression literalExpression = null;
switch (LT(1)) { switch (LT(1)) {
@ -1238,7 +1327,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
} }
t = consume(); t = consume();
int finalOffset= 0; int finalOffset= 0;
IASTExpression lhs= expression(true, true, false); // instead of expression(), to keep the stack smaller IASTExpression lhs= expression(ExprKind.eExpression, BinaryExprCtx.eNoTmplID); // instead of expression(), to keep the stack smaller
switch (LT(1)) { switch (LT(1)) {
case IToken.tRPAREN: case IToken.tRPAREN:
case IToken.tEOC: case IToken.tEOC:
@ -1253,7 +1342,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
case IToken.t_operator: case IToken.t_operator:
case IToken.tCOMPLETION: case IToken.tCOMPLETION:
case IToken.tBITCOMPLEMENT: { case IToken.tBITCOMPLEMENT: {
IASTName name = idExpression(); IASTName name = qualifiedName(ctx);
IASTIdExpression idExpression = nodeFactory.newIdExpression(name); IASTIdExpression idExpression = nodeFactory.newIdExpression(name);
((ASTNode) idExpression).setOffsetAndLength(((ASTNode) name).getOffset(), ((ASTNode) name).getOffset() ((ASTNode) idExpression).setOffsetAndLength(((ASTNode) name).getOffset(), ((ASTNode) name).getOffset()
+ ((ASTNode) name).getLength() - ((ASTNode) name).getOffset()); + ((ASTNode) name).getLength() - ((ASTNode) name).getOffset());
@ -1320,7 +1409,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
case IToken.tIDENTIFIER: case IToken.tIDENTIFIER:
case IToken.tCOLONCOLON: case IToken.tCOLONCOLON:
case IToken.tCOMPLETION: case IToken.tCOMPLETION:
name = qualifiedName(); name = qualifiedName(CastExprCtx.eNotBExpr);
break; break;
default: default:
throwBacktrack(offset, endOffset - offset); throwBacktrack(offset, endOffset - offset);
@ -1351,7 +1440,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
consume(); consume();
} }
IASTName name = idExpression(); IASTName name = qualifiedName(CastExprCtx.eNotBExpr);
int end; int end;
switch (LT(1)) { switch (LT(1)) {
case IToken.tSEMI: case IToken.tSEMI:
@ -1469,7 +1558,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
} }
List<ICPPASTTemplateParameter> parms= templateParameterList(); List<ICPPASTTemplateParameter> parms= templateParameterList();
consume(IToken.tGT); consume(IToken.tGT, IToken.tGT_in_SHIFTR);
IASTDeclaration d = declaration(option); IASTDeclaration d = declaration(option);
ICPPASTTemplateDeclaration templateDecl = nodeFactory.newTemplateDeclaration(d); ICPPASTTemplateDeclaration templateDecl = nodeFactory.newTemplateDeclaration(d);
((ASTNode) templateDecl).setOffsetAndLength(firstToken.getOffset(), calculateEndOffset(d) - firstToken.getOffset()); ((ASTNode) templateDecl).setOffsetAndLength(firstToken.getOffset(), calculateEndOffset(d) - firstToken.getOffset());
@ -1503,7 +1592,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
for (;;) { for (;;) {
final int lt1= LT(1); final int lt1= LT(1);
if (lt1 == IToken.tGT || lt1 == IToken.tEOC) if (lt1 == IToken.tGT || lt1 == IToken.tEOC || lt1 == IToken.tGT_in_SHIFTR)
return returnValue; return returnValue;
if (lt1 == IToken.t_class || lt1 == IToken.t_typename) { if (lt1 == IToken.t_class || lt1 == IToken.t_typename) {
IToken startingToken = LA(1); IToken startingToken = LA(1);
@ -1537,7 +1626,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
consume(IToken.tLT); consume(IToken.tLT);
List<ICPPASTTemplateParameter> subResult = templateParameterList(); List<ICPPASTTemplateParameter> subResult = templateParameterList();
consume(IToken.tGT); consume(IToken.tGT, IToken.tGT_in_SHIFTR);
int last = consume(IToken.t_class).getEndOffset(); int last = consume(IToken.t_class).getEndOffset();
IASTName identifierName = null; IASTName identifierName = null;
IASTExpression optionalExpression = null; IASTExpression optionalExpression = null;
@ -1547,7 +1636,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
last = calculateEndOffset(identifierName); last = calculateEndOffset(identifierName);
if (LT(1) == IToken.tASSIGN) { // optional = type-id if (LT(1) == IToken.tASSIGN) { // optional = type-id
consume(); consume();
optionalExpression = primaryExpression(); optionalExpression = primaryExpression(CastExprCtx.eNotBExpr);
last = calculateEndOffset(optionalExpression); last = calculateEndOffset(optionalExpression);
} }
} else } else
@ -1690,7 +1779,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return null; return null;
} }
IASTName qualifiedName= qualifiedName(); IASTName qualifiedName= qualifiedName(CastExprCtx.eNotBExpr);
endOffset = consume(IToken.tSEMI).getEndOffset(); endOffset = consume(IToken.tSEMI).getEndOffset();
ICPPASTNamespaceAlias alias = nodeFactory.newNamespaceAlias(name, qualifiedName); ICPPASTNamespaceAlias alias = nodeFactory.newNamespaceAlias(name, qualifiedName);
@ -1892,7 +1981,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
consume(); consume();
ctorLoop: for (;;) { ctorLoop: for (;;) {
int offset= LA(1).getOffset(); int offset= LA(1).getOffset();
IASTName name = qualifiedName(); IASTName name = qualifiedName(CastExprCtx.eNotBExpr);
int endOffset; int endOffset;
IASTExpression expressionList = null; IASTExpression expressionList = null;
@ -2161,7 +2250,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
if (encounteredTypename || encounteredRawType) if (encounteredTypename || encounteredRawType)
break declSpecifiers; break declSpecifiers;
consume(); consume();
identifier= qualifiedName(); identifier= qualifiedName(CastExprCtx.eNotBExpr);
endOffset= calculateEndOffset(identifier); endOffset= calculateEndOffset(identifier);
isTypename = true; isTypename = true;
encounteredTypename= true; encounteredTypename= true;
@ -2180,7 +2269,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
} }
} }
identifier= qualifiedName(); identifier= qualifiedName(CastExprCtx.eNotBExpr);
if (identifier.getLookupKey().length == 0 && LT(1) != IToken.tEOC) if (identifier.getLookupKey().length == 0 && LT(1) != IToken.tEOC)
throwBacktrack(LA(1)); throwBacktrack(LA(1));
@ -2235,7 +2324,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
throwBacktrack(LA(1)); throwBacktrack(LA(1));
typeofExpression= parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), typeofExpression= parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IGNUASTTypeIdExpression.op_typeof, IGNUASTUnaryExpression.op_typeof, false); IGNUASTTypeIdExpression.op_typeof, IGNUASTUnaryExpression.op_typeof, CastExprCtx.eNotBExpr);
encounteredTypename= true; encounteredTypename= true;
endOffset= calculateEndOffset(typeofExpression); endOffset= calculateEndOffset(typeofExpression);
@ -2374,7 +2463,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// if __attribute__ or __declspec occurs after struct/union/class and before the identifier // if __attribute__ or __declspec occurs after struct/union/class and before the identifier
__attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers);
IASTName name = qualifiedName(); IASTName name = qualifiedName(CastExprCtx.eNotBExpr);
ICPPASTElaboratedTypeSpecifier elaboratedTypeSpec = nodeFactory.newElaboratedTypeSpecifier(eck, name); ICPPASTElaboratedTypeSpecifier elaboratedTypeSpec = nodeFactory.newElaboratedTypeSpecifier(eck, name);
((ASTNode) elaboratedTypeSpec).setOffsetAndLength(t.getOffset(), calculateEndOffset(name) - t.getOffset()); ((ASTNode) elaboratedTypeSpec).setOffsetAndLength(t.getOffset(), calculateEndOffset(name) - t.getOffset());
@ -2628,51 +2717,50 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
} }
protected IASTInitializer initializerClause(boolean inAggregateInitializer) throws EndOfFileException, BacktrackException { protected IASTInitializer initializerClause(boolean inAggregateInitializer) throws EndOfFileException,
if (LT(1) == IToken.tLBRACE) { BacktrackException {
int startingOffset = consume().getOffset(); if (LT(1) == IToken.tLBRACE) {
int startingOffset = consume().getOffset();
IASTInitializerList result = nodeFactory.newInitializerList(); IASTInitializerList result = nodeFactory.newInitializerList();
((ASTNode) result).setOffset(startingOffset); ((ASTNode) result).setOffset(startingOffset);
if (LT(1) == (IToken.tRBRACE)) { if (LT(1) == (IToken.tRBRACE)) {
int l = consume().getEndOffset(); int endOffset = consume().getEndOffset();
((ASTNode) result).setLength(l - startingOffset); setRange(result, startingOffset, endOffset);
return result; return result;
} }
// otherwise it is a list of initializer clauses // otherwise it is a list of initializer clauses
for (;;) {
if (LT(1) == IToken.tRBRACE)
break;
for (;;) { // clause may be null, add to initializer anyways, such that the
if (LT(1) == IToken.tRBRACE) // actual size can be computed.
break; IASTInitializer clause = initializerClause(true);
result.addInitializer(clause);
if (LT(1) == IToken.tRBRACE || LT(1) == IToken.tEOC)
break;
consume(IToken.tCOMMA);
}
int endOffset = consume().getEndOffset(); // tRBRACE
setRange(result, startingOffset, endOffset);
return result;
}
// clause may be null, add to initializer anyways, such that the // no brace, so try an assignment expression
// actual size can be computed. final BinaryExprCtx ctx = fInTemplateParameterList ? BinaryExprCtx.eTmplID : BinaryExprCtx.eNoTmplID;
IASTInitializer clause = initializerClause(true); IASTExpression assignmentExpression = expression(ExprKind.eAssignment, ctx);
result.addInitializer(clause); if (inAggregateInitializer && skipTrivialExpressionsInAggregateInitializers) {
if (LT(1) == IToken.tRBRACE || LT(1) == IToken.tEOC) if (!ASTQueries.canContainName(assignmentExpression))
break; return null;
consume(IToken.tCOMMA); }
}
int l = consume().getEndOffset(); // tRBRACE
((ASTNode) result).setLength(l - startingOffset);
return result;
}
// if we get this far, it means that we did not IASTInitializerExpression result = nodeFactory.newInitializerExpression(assignmentExpression);
// try this now instead setRange(result, assignmentExpression);
// assignmentExpression return result;
IASTExpression assignmentExpression = expression(false, true, fInTemplateParameterList); }
if (inAggregateInitializer && skipTrivialExpressionsInAggregateInitializers) {
if (!ASTQueries.canContainName(assignmentExpression))
return null;
}
IASTInitializerExpression result = nodeFactory.newInitializerExpression(assignmentExpression);
((ASTNode) result).setOffsetAndLength(((ASTNode) assignmentExpression));
return result;
}
@Override @Override
@ -2684,7 +2772,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
IASTDeclSpecifier declSpecifier = null; IASTDeclSpecifier declSpecifier = null;
IASTDeclarator declarator = null; IASTDeclarator declarator = null;
rejectLogicalOperatorInTemplateID++;
try { try {
Decl decl= declSpecifierSequence_initDeclarator(option, false); Decl decl= declSpecifierSequence_initDeclarator(option, false);
declSpecifier= decl.fDeclSpec1; declSpecifier= decl.fDeclSpec1;
@ -2694,9 +2781,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return null; return null;
} catch (BacktrackException bt) { } catch (BacktrackException bt) {
return null; return null;
} finally { }
rejectLogicalOperatorInTemplateID--;
}
IASTTypeId result = nodeFactory.newTypeId(declSpecifier, declarator); IASTTypeId result = nodeFactory.newTypeId(declSpecifier, declarator);
setRange(result, offset, figureEndOffset(declSpecifier, declarator)); setRange(result, offset, figureEndOffset(declSpecifier, declarator));
return result; return result;
@ -2744,7 +2829,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
if (option.fRequireAbstract) if (option.fRequireAbstract)
throwBacktrack(LA(1)); throwBacktrack(LA(1));
final IASTName declaratorName= qualifiedName(); final IASTName declaratorName= qualifiedName(CastExprCtx.eNotBExpr);
endOffset= calculateEndOffset(declaratorName); endOffset= calculateEndOffset(declaratorName);
return declarator(pointerOps, declaratorName, null, startingOffset, endOffset, strategy, option); return declarator(pointerOps, declaratorName, null, startingOffset, endOffset, strategy, option);
} }
@ -2860,7 +2945,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
} }
if (coloncolon != 0) { if (coloncolon != 0) {
try { try {
name= qualifiedName(); name= qualifiedName(CastExprCtx.eNotBExpr);
if (name.getLookupKey().length != 0) { if (name.getLookupKey().length != 0) {
backup(mark); backup(mark);
return; return;
@ -3167,7 +3252,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// class name // class name
IASTName name = null; IASTName name = null;
if (LT(1) == IToken.tIDENTIFIER) if (LT(1) == IToken.tIDENTIFIER)
name = qualifiedName(); name = qualifiedName(CastExprCtx.eNotBExpr);
else else
name = nodeFactory.newName(); name = nodeFactory.newName();
@ -3253,7 +3338,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
case IToken.tIDENTIFIER: case IToken.tIDENTIFIER:
case IToken.tCOMPLETION: case IToken.tCOMPLETION:
// to get templates right we need to use the class as the scope // to get templates right we need to use the class as the scope
name = qualifiedName(); name = qualifiedName(CastExprCtx.eNotBExpr);
endOffset= calculateEndOffset(name); endOffset= calculateEndOffset(name);
break; break;
case IToken.tCOMMA: case IToken.tCOMMA:

View file

@ -171,6 +171,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
private int fContentAssistLimit= -1; private int fContentAssistLimit= -1;
private boolean fHandledCompletion= false; private boolean fHandledCompletion= false;
private boolean fSplitShiftRightOperator= false;
// state information // state information
private final CharArrayMap<PreprocessorMacro> fMacroDictionary = new CharArrayMap<PreprocessorMacro>(512); private final CharArrayMap<PreprocessorMacro> fMacroDictionary = new CharArrayMap<PreprocessorMacro>(512);
@ -238,6 +239,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
} }
} }
public void setSplitShiftROperator(boolean val) {
fSplitShiftRightOperator= val;
}
public void setComputeImageLocations(boolean val) { public void setComputeImageLocations(boolean val) {
fLexOptions.fCreateImageLocations= val; fLexOptions.fCreateImageLocations= val;
@ -442,7 +446,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
} }
/** /**
* Returns the next token from the preprocessor without concatenating string literals. * Returns the next token from the preprocessor without concatenating string literals
* and also without splitting the shift-right operator.
*/ */
private Token fetchToken() throws OffsetLimitReachedException { private Token fetchToken() throws OffsetLimitReachedException {
if (fIsFirstFetchToken) { if (fIsFirstFetchToken) {
@ -537,7 +542,6 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
case IToken.tLSTRING: case IToken.tLSTRING:
case IToken.tUTF16STRING: case IToken.tUTF16STRING:
case IToken.tUTF32STRING: case IToken.tUTF32STRING:
StringType st = StringType.fromToken(tt1); StringType st = StringType.fromToken(tt1);
Token t2; Token t2;
StringBuffer buf= null; StringBuffer buf= null;
@ -580,6 +584,18 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
image[image.length - 1]= '"'; image[image.length - 1]= '"';
t1= new TokenWithImage(st.getTokenValue(), null, t1.getOffset(), endOffset, image); t1= new TokenWithImage(st.getTokenValue(), null, t1.getOffset(), endOffset, image);
} }
break;
case IToken.tSHIFTR:
if (fSplitShiftRightOperator) {
int offset= t1.getOffset();
endOffset= t1.getEndOffset();
t1.setType(IToken.tGT_in_SHIFTR);
t1.setOffset(offset, offset+1);
t2= new Token(IToken.tGT_in_SHIFTR, t1.fSource, offset+1, endOffset);
pushbackToken(t2);
}
} }
if (fLastToken != null) { if (fLastToken != null) {

View file

@ -112,6 +112,7 @@ public class TokenUtil {
case IToken.tSHIFTRASSIGN: return Keywords.cpSHIFTRASSIGN; case IToken.tSHIFTRASSIGN: return Keywords.cpSHIFTRASSIGN;
case IToken.tSHIFTR: return Keywords.cpSHIFTR; case IToken.tSHIFTR: return Keywords.cpSHIFTR;
case IToken.tGTEQUAL: return Keywords.cpGTEQUAL; case IToken.tGTEQUAL: return Keywords.cpGTEQUAL;
case IToken.tGT_in_SHIFTR:
case IToken.tGT: return Keywords.cpGT; case IToken.tGT: return Keywords.cpGT;
case IToken.tSHIFTLASSIGN: return Keywords.cpSHIFTLASSIGN; case IToken.tSHIFTLASSIGN: return Keywords.cpSHIFTLASSIGN;
case IToken.tELLIPSIS: return Keywords.cpELLIPSIS; case IToken.tELLIPSIS: return Keywords.cpELLIPSIS;