1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 17:05:26 +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
// template<class T> class Y { };
// 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 {
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.IASTName;
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.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IBasicType;
@ -4245,4 +4246,58 @@ public class AST2TemplateTests extends AST2BaseTest {
final String code= getAboveComment();
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.IASTCompositeTypeSpecifier;
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.IASTDeclaration;
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.IASTElaboratedTypeSpecifier;
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.IASTFieldReference;
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) {
if (expr instanceof IASTBinaryExpression) {
IASTBinaryExpression bexpr= (IASTBinaryExpression) expr;
@ -5484,7 +5539,24 @@ public class AST2Tests extends AST2BaseTest {
}
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;
polnishNotation(bexpr.getOperand1(), buf);
buf.append(',');

View file

@ -68,12 +68,11 @@ public interface IScanner {
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.
* @since 4.0
*/
@Deprecated
public void setScanComments(boolean val);
public void setSplitShiftROperator(boolean val);
/**
* 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.
*/
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 tDIVASSIGN = 51;
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 #tAMPERASSIGN} */ @Deprecated int t_and_eq = 55;
int t_asm = 56;

View file

@ -147,6 +147,13 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
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 int parseCount = 0;
@ -184,7 +191,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected BacktrackException backtrack = new BacktrackException();
protected ASTCompletionNode completionNode;
protected IASTTypeId fTypeIdForCastAmbiguity;
private final INodeFactory nodeFactory;
private boolean fActiveCode= true;
@ -269,12 +275,13 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
private final IToken nextToken(boolean skipInactive) throws EndOfFileException {
IToken t= nextToken;
if (t == null) {
t= fetchToken(skipInactive);
}
nextToken= t;
return t;
final IToken t= nextToken;
if (t != null)
return t;
final IToken tn= fetchToken(skipInactive);
nextToken= tn;
return tn;
}
private final IToken lookaheadToken(int i, boolean skipInactive) throws EndOfFileException {
@ -457,6 +464,18 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
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
* 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.
* This is done right to left, such that a tree of variants can be built.
*/
protected static class CastExpressionOp {
final CastExpressionOp fLeft;
final IASTExpression fExpression;
protected static class BinaryOperator {
final int fOperatorToken;
final int fLeftPrecedence;
final int fRightPrecedence;
BinaryOperator fNext;
IASTExpression fExpression;
final CastAmbiguityMarker fAmbiguityMarker;
public CastExpressionOp(CastExpressionOp left, IASTExpression expression, int operatorToken, int leftPrecedence, int rightPrecedence) {
fLeft= left;
fExpression= expression;
public BinaryOperator(BinaryOperator left, IASTExpression expression, int operatorToken, int leftPrecedence, int rightPrecedence) {
fNext= left;
fOperatorToken= operatorToken;
fLeftPrecedence= leftPrecedence;
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;
}
}
/**
* Helper class to temporarily store a sequence of operator followed by expression.
*/
private static final class OpCastExpressionStack {
private IASTExpression fExpressions[]= new IASTExpression[128];
private int fPrecedenceAndTokens[]= new int[256];
private int fPos=-1;
boolean isEmpty() {
return fPos<0;
}
public IASTExpression getExpression() {
return fExpressions[fPos];
}
public int getLeftPrecedence() {
return fPrecedenceAndTokens[2*fPos];
}
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;
protected final IASTExpression buildExpression(BinaryOperator leftChain, IASTExpression expr) throws BacktrackException {
BinaryOperator rightChain= null;
for (;;) {
if (leftChain == null) {
if (rightChain == null)
return expr;
expr= buildExpression(expr, rightChain);
rightChain= rightChain.fNext;
} else if (rightChain != null && leftChain.fRightPrecedence < rightChain.fLeftPrecedence) {
expr= buildExpression(expr, rightChain);
rightChain= rightChain.fNext;
} else {
BinaryOperator op= leftChain;
leftChain= leftChain.fNext;
expr= op.exchange(expr);
op.fNext= rightChain;
rightChain= op;
}
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 {
if (exprOp1 == null)
return expr;
// 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) {
private IASTExpression buildExpression(IASTExpression left, BinaryOperator operator) throws BacktrackException {
int op, unaryOp= 0;
final IASTExpression right= operator.fExpression;
switch(operator.fOperatorToken) {
case IToken.tQUESTION:
if (stack == null || stack.isEmpty() || stack.getOperatorToken() != IToken.tCOLON) {
if (operator.fNext == null || operator.fNext.fOperatorToken != IToken.tCOLON) {
assert false;
ASTNode node= (ASTNode) left;
throwBacktrack(node.getOffset(), node.getLength());
return null; // Will never be reached.
}
IASTExpression negative= stack.getExpression();
stack.pop();
IASTExpression negative= operator.fNext.fExpression;
operator.fNext= operator.fNext.fNext;
IASTConditionalExpression conditionalEx = nodeFactory.newConditionalExpession(left, right, negative);
setRange(conditionalEx, left);
if (negative != null) {
@ -1134,35 +1099,20 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
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));
if (lca != null) {
final CastAmbiguityMarker am = operator.fAmbiguityMarker;
if (am != null) {
assert unaryOp != 0;
result = createCastVsBinaryExpressionAmbiguity((IASTBinaryExpression) result,
lca.getTypeIdForCast(), unaryOp, lca.getUnaryOperatorOffset());
am.getTypeIdForCast(), unaryOp, am.getUnaryOperatorOffset());
}
return rca == null ? result : rca.updateExpression(result);
return result;
}
protected abstract IASTExpression expression() throws BacktrackException, EndOfFileException;
protected abstract IASTExpression assignmentExpression() throws EndOfFileException, BacktrackException;
protected abstract IASTExpression constantExpression() throws BacktrackException, EndOfFileException;
protected abstract IASTExpression unaryExpression(boolean inBinary) throws BacktrackException, EndOfFileException;
protected abstract IASTExpression primaryExpression() throws BacktrackException, EndOfFileException;
protected abstract IASTExpression unaryExpression(CastExprCtx ctx) throws BacktrackException, EndOfFileException;
protected abstract IASTExpression primaryExpression(CastExprCtx ctx) throws BacktrackException, EndOfFileException;
protected abstract IASTTypeId typeId(DeclarationOptions option) throws EndOfFileException;
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) {
final IToken mark= mark();
final int startingOffset= mark.getOffset();
@ -1211,7 +1161,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
if (typeId != null && LT(1) == IToken.tRPAREN) {
consume();
boolean unaryFailed= false;
if (inBinaryExpression) {
if (ctx != CastExprCtx.eNotBExpr) {
switch (LT(1)){
// ambiguity with unary operator
case IToken.tPLUS: case IToken.tMINUS:
@ -1220,7 +1170,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
IToken markEnd= mark();
backup(mark);
try {
IASTExpression unary= unaryExpression(false);
IASTExpression unary= unaryExpression(CastExprCtx.eNotBExpr);
return new CastAmbiguityMarker(unary, typeId, operatorOffset);
} catch (BacktrackException bt) {
backup(markEnd);
@ -1230,7 +1180,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
try {
boolean couldBeFunctionCall= LT(1) == IToken.tLPAREN;
IASTExpression rhs= castExpression(inBinaryExpression);
IASTExpression rhs= castExpression(ctx);
CastAmbiguityMarker ca= null;
if (rhs instanceof CastAmbiguityMarker) {
@ -1243,7 +1193,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
IToken markEnd= mark();
backup(mark);
try {
IASTExpression expr= primaryExpression();
IASTExpression expr= primaryExpression(ctx);
IASTFunctionCallExpression fcall = nodeFactory.newFunctionCallExpression(expr, null);
IASTAmbiguousExpression ambiguity = createAmbiguousCastVsFunctionCallExpression(result, fcall);
((ASTNode) ambiguity).setOffsetAndLength((ASTNode) result);
@ -1261,7 +1211,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
backup(mark);
}
return unaryExpression(inBinaryExpression);
return unaryExpression(ctx);
}
protected abstract IASTTranslationUnit getTranslationUnit();
@ -1386,9 +1336,9 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
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();
IASTExpression operand= castExpression(inBinary);
IASTExpression operand= castExpression(ctx);
CastAmbiguityMarker ca= null;
if (operand instanceof CastAmbiguityMarker) {
@ -2185,7 +2135,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
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;
IASTExpression expr= null;
IToken typeidLA= null;
@ -2246,7 +2196,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
expr= expression();
endOffset2= consumeOrEOC(IToken.tRPAREN).getEndOffset();
} else {
expr= unaryExpression(inBinary);
expr= unaryExpression(ctx);
if (expr instanceof CastAmbiguityMarker) {
ca= (CastAmbiguityMarker) expr;
expr= ca.getExpression();

View file

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

View file

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

View file

@ -171,6 +171,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
private int fContentAssistLimit= -1;
private boolean fHandledCompletion= false;
private boolean fSplitShiftRightOperator= false;
// state information
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) {
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 {
if (fIsFirstFetchToken) {
@ -537,7 +542,6 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
StringType st = StringType.fromToken(tt1);
Token t2;
StringBuffer buf= null;
@ -580,6 +584,18 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
image[image.length - 1]= '"';
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) {

View file

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