blob: 45e842e31a9db43e17d500af75534098edcd525b [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
package org.eclipse.cdt.internal.core.parser;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import org.eclipse.cdt.core.parser.BacktrackException;
import org.eclipse.cdt.core.parser.EndOfFileException;
import org.eclipse.cdt.core.parser.IParser;
import org.eclipse.cdt.core.parser.IParserLogService;
import org.eclipse.cdt.core.parser.IScanner;
import org.eclipse.cdt.core.parser.ISourceElementRequestor;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.ITokenDuple;
import org.eclipse.cdt.core.parser.OffsetLimitReachedException;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ScannerException;
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
import org.eclipse.cdt.core.parser.ast.ASTClassKind;
import org.eclipse.cdt.core.parser.ast.ASTPointerOperator;
import org.eclipse.cdt.core.parser.ast.ASTSemanticException;
import org.eclipse.cdt.core.parser.ast.IASTASMDefinition;
import org.eclipse.cdt.core.parser.ast.IASTArrayModifier;
import org.eclipse.cdt.core.parser.ast.IASTClassSpecifier;
import org.eclipse.cdt.core.parser.ast.IASTCodeScope;
import org.eclipse.cdt.core.parser.ast.IASTCompilationUnit;
import org.eclipse.cdt.core.parser.ast.IASTCompletionNode;
import org.eclipse.cdt.core.parser.ast.IASTDeclaration;
import org.eclipse.cdt.core.parser.ast.IASTDesignator;
import org.eclipse.cdt.core.parser.ast.IASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.parser.ast.IASTEnumerationSpecifier;
import org.eclipse.cdt.core.parser.ast.IASTExpression;
import org.eclipse.cdt.core.parser.ast.IASTFactory;
import org.eclipse.cdt.core.parser.ast.IASTInitializerClause;
import org.eclipse.cdt.core.parser.ast.IASTLinkageSpecification;
import org.eclipse.cdt.core.parser.ast.IASTNamespaceDefinition;
import org.eclipse.cdt.core.parser.ast.IASTNode;
import org.eclipse.cdt.core.parser.ast.IASTOffsetableElement;
import org.eclipse.cdt.core.parser.ast.IASTScope;
import org.eclipse.cdt.core.parser.ast.IASTSimpleTypeSpecifier;
import org.eclipse.cdt.core.parser.ast.IASTTemplate;
import org.eclipse.cdt.core.parser.ast.IASTTemplateDeclaration;
import org.eclipse.cdt.core.parser.ast.IASTTemplateInstantiation;
import org.eclipse.cdt.core.parser.ast.IASTTemplateParameter;
import org.eclipse.cdt.core.parser.ast.IASTTemplateSpecialization;
import org.eclipse.cdt.core.parser.ast.IASTTypeId;
import org.eclipse.cdt.core.parser.ast.IASTTypeSpecifier;
import org.eclipse.cdt.core.parser.ast.IASTUsingDeclaration;
import org.eclipse.cdt.core.parser.ast.IASTUsingDirective;
import org.eclipse.cdt.core.parser.ast.IASTClassSpecifier.ClassNameType;
import org.eclipse.cdt.core.parser.ast.IASTCompletionNode.CompletionKind;
import org.eclipse.cdt.core.parser.ast.IASTExpression.Kind;
import org.eclipse.cdt.internal.core.parser.KeywordSets.Key;
/**
* This is our first implementation of the IParser interface, serving as a parser for
* ANSI C and C++.
*
* From time to time we will make reference to the ANSI ISO specifications.
*
* @author jcamelon
*/
public abstract class Parser implements IParser
{
protected final IParserLogService log;
private static final List EMPTY_LIST = new ArrayList();
private static int FIRST_ERROR_OFFSET_UNSET = -1;
// sentinel initial value for offsets
protected int firstErrorOffset = FIRST_ERROR_OFFSET_UNSET;
// offset where the first parse error occurred
// are we doing the high-level parse, or an in depth parse?
protected boolean parsePassed = true; // did the parse pass?
protected ParserLanguage language = ParserLanguage.CPP; // C or CPP
protected ISourceElementRequestor requestor = null;
// new callback mechanism
protected IASTFactory astFactory = null; // ast factory
/**
* This is the single entry point for setting parsePassed to
* false, and also making note what token offset we failed upon.
*
* @throws EndOfFileException
*/
protected void failParse()
{
try
{
if (firstErrorOffset == FIRST_ERROR_OFFSET_UNSET )
firstErrorOffset = LA(1).getOffset();
} catch( EndOfFileException eof )
{
// do nothing
}
finally
{
parsePassed = false;
}
}
/**
* This is the standard cosntructor that we expect the Parser to be instantiated
* with.
*
* @param s IScanner instance that has been initialized to the code input
* @param c IParserCallback instance that will receive callbacks as we parse
* @param quick Are we asking for a high level parse or not?
*/
public Parser(
IScanner scanner,
ISourceElementRequestor callback,
ParserLanguage language,
IParserLogService log )
{
this.scanner = scanner;
this.requestor = callback;
this.language = language;
this.log = log;
}
// counter that keeps track of the number of times Parser.parse() is called
private static int parseCount = 0;
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.parser.IParser#parse()
*/
public boolean parse()
{
long startTime = System.currentTimeMillis();
translationUnit();
// For the debuglog to take place, you have to call
// Util.setDebugging(true);
// Or set debug to true in the core plugin preference
log.traceLog(
"Parse "
+ (++parseCount)
+ ": "
+ (System.currentTimeMillis() - startTime)
+ "ms"
+ (parsePassed ? "" : " - parse failure") );
return parsePassed;
}
/**
* This is the top-level entry point into the ANSI C++ grammar.
*
* translationUnit : (declaration)*
*/
protected void translationUnit()
{
IASTCompilationUnit compilationUnit;
try
{
compilationUnit = astFactory.createCompilationUnit();
}
catch (Exception e2)
{
return;
}
compilationUnit.enterScope( requestor );
IToken lastBacktrack = null;
IToken checkToken = null;
while (true)
{
try
{
checkToken = LA(1);
declaration(compilationUnit, null);
if (LA(1) == checkToken)
errorHandling();
}
catch (EndOfFileException e)
{
// Good
break;
}
catch (BacktrackException b)
{
try
{
// Mark as failure and try to reach a recovery point
failParse();
if (lastBacktrack != null && lastBacktrack == LA(1))
{
// we haven't progressed from the last backtrack
// try and find tne next definition
errorHandling();
}
else
{
// start again from here
lastBacktrack = LA(1);
}
}
catch (EndOfFileException e)
{
break;
}
}
catch (Exception e)
{
failParse();
break;
}
}
compilationUnit.exitScope( requestor );
}
/**
* This function is called whenever we encounter and error that we cannot backtrack out of and we
* still wish to try and continue on with the parse to do a best-effort parse for our client.
*
* @throws EndOfFileException We can potentially hit EndOfFile here as we are skipping ahead.
*/
protected void errorHandling() throws EndOfFileException
{
failParse();
consume();
int depth = 0;
while (!((LT(1) == IToken.tSEMI && depth == 0)
|| (LT(1) == IToken.tRBRACE && depth == 1)))
{
switch (LT(1))
{
case IToken.tLBRACE :
++depth;
break;
case IToken.tRBRACE :
--depth;
break;
}
consume();
}
// eat the SEMI/RBRACE as well
consume();
}
/**
* The merger of using-declaration and using-directive in ANSI C++ grammar.
*
* using-declaration:
* using typename? ::? nested-name-specifier unqualified-id ;
* using :: unqualified-id ;
* using-directive:
* using namespace ::? nested-name-specifier? namespace-name ;
*
* @param container Callback object representing the scope these definitions fall into.
* @throws BacktrackException request for a backtrack
*/
protected void usingClause(IASTScope scope)
throws EndOfFileException, BacktrackException
{
IToken firstToken = consume(IToken.t_using);
if (LT(1) == IToken.t_namespace)
{
// using-directive
consume(IToken.t_namespace);
// optional :: and nested classes handled in name
TokenDuple duple = null;
if (LT(1) == IToken.tIDENTIFIER || LT(1) == IToken.tCOLONCOLON)
duple = name();
else
throw backtrack;
if (LT(1) == IToken.tSEMI)
{
IToken last = consume(IToken.tSEMI);
IASTUsingDirective astUD = null;
try
{
astUD = astFactory.createUsingDirective(scope, duple, firstToken.getOffset(), last.getEndOffset());
}
catch (Exception e1)
{
throw backtrack;
}
astUD.acceptElement(requestor);
return;
}
else
{
throw backtrack;
}
}
else
{
boolean typeName = false;
if (LT(1) == IToken.t_typename)
{
typeName = true;
consume(IToken.t_typename);
}
TokenDuple name = null;
if (LT(1) == IToken.tIDENTIFIER || LT(1) == IToken.tCOLONCOLON)
{
// optional :: and nested classes handled in name
name = name();
}
else
{
throw backtrack;
}
if (LT(1) == IToken.tSEMI)
{
IToken last = consume(IToken.tSEMI);
IASTUsingDeclaration declaration = null;
try
{
declaration =
astFactory.createUsingDeclaration(
scope,
typeName,
name,
firstToken.getOffset(),
last.getEndOffset());
}
catch (Exception e1)
{
throw backtrack;
}
declaration.acceptElement( requestor );
}
else
{
throw backtrack;
}
}
}
/**
* Implements Linkage specification in the ANSI C++ grammar.
*
* linkageSpecification
* : extern "string literal" declaration
* | extern "string literal" { declaration-seq }
*
* @param container Callback object representing the scope these definitions fall into.
* @throws BacktrackException request for a backtrack
*/
protected void linkageSpecification(IASTScope scope)
throws EndOfFileException, BacktrackException
{
IToken firstToken = consume(IToken.t_extern);
if (LT(1) != IToken.tSTRING)
throw backtrack;
IToken spec = consume(IToken.tSTRING);
if (LT(1) == IToken.tLBRACE)
{
consume(IToken.tLBRACE);
IASTLinkageSpecification linkage;
try
{
linkage =
astFactory.createLinkageSpecification(
scope,
spec.getImage(),
firstToken.getOffset());
}
catch (Exception e)
{
throw backtrack;
}
linkage.enterScope( requestor );
linkageDeclarationLoop : while (LT(1) != IToken.tRBRACE)
{
IToken checkToken = LA(1);
switch (LT(1))
{
case IToken.tRBRACE :
consume(IToken.tRBRACE);
break linkageDeclarationLoop;
default :
try
{
declaration(linkage, null);
}
catch (BacktrackException bt)
{
failParse();
if (checkToken == LA(1))
errorHandling();
}
}
if (checkToken == LA(1))
errorHandling();
}
// consume the }
IToken lastToken = consume();
linkage.setEndingOffset(lastToken.getEndOffset());
linkage.exitScope( requestor );
}
else // single declaration
{
IASTLinkageSpecification linkage;
try
{
linkage =
astFactory.createLinkageSpecification(
scope,
spec.getImage(),
firstToken.getOffset());
}
catch (Exception e)
{
throw backtrack;
}
linkage.enterScope( requestor );
declaration(linkage, null);
linkage.exitScope( requestor );
}
}
/**
*
* Represents the emalgamation of template declarations, template instantiations and
* specializations in the ANSI C++ grammar.
*
* template-declaration: export? template < template-parameter-list > declaration
* explicit-instantiation: template declaration
* explicit-specialization: template <> declaration
*
* @param container Callback object representing the scope these definitions fall into.
* @throws BacktrackException request for a backtrack
*/
protected void templateDeclaration(IASTScope scope)
throws EndOfFileException, BacktrackException
{
IToken firstToken = null;
boolean exported = false;
if (LT(1) == IToken.t_export)
{
exported = true;
firstToken = consume(IToken.t_export);
consume(IToken.t_template);
}
else
firstToken = consume(IToken.t_template);
if (LT(1) != IToken.tLT)
{
// explicit-instantiation
IASTTemplateInstantiation templateInstantiation;
try
{
templateInstantiation =
astFactory.createTemplateInstantiation(
scope,
firstToken.getOffset());
}
catch (Exception e)
{
throw backtrack;
}
templateInstantiation.enterScope( requestor );
declaration(scope, templateInstantiation);
templateInstantiation.setEndingOffset(lastToken.getEndOffset());
templateInstantiation.exitScope( requestor );
return;
}
else
{
consume(IToken.tLT);
if (LT(1) == IToken.tGT)
{
consume(IToken.tGT);
// explicit-specialization
IASTTemplateSpecialization templateSpecialization;
try
{
templateSpecialization =
astFactory.createTemplateSpecialization(
scope,
firstToken.getOffset());
}
catch (Exception e)
{
throw backtrack;
}
templateSpecialization.enterScope(requestor);
declaration(scope, templateSpecialization);
templateSpecialization.setEndingOffset(
lastToken.getEndOffset());
templateSpecialization.exitScope(requestor);
return;
}
}
try
{
List parms = templateParameterList(scope);
consume(IToken.tGT);
IASTTemplateDeclaration templateDecl;
try
{
templateDecl =
astFactory.createTemplateDeclaration(
scope,
parms,
exported,
firstToken.getOffset());
}
catch (Exception e)
{
throw backtrack;
}
templateDecl.enterScope( requestor );
declaration(scope, templateDecl );
templateDecl.setEndingOffset(
lastToken.getEndOffset() );
templateDecl.exitScope( requestor );
}
catch (BacktrackException bt)
{
throw bt;
}
}
/**
*
*
*
* template-parameter-list: template-parameter
* template-parameter-list , template-parameter
* template-parameter: type-parameter
* parameter-declaration
* type-parameter: class identifier?
* class identifier? = type-id
* typename identifier?
* typename identifier? = type-id
* template < template-parameter-list > class identifier?
* template < template-parameter-list > class identifier? = id-expression
* template-id: template-name < template-argument-list?>
* template-name: identifier
* template-argument-list: template-argument
* template-argument-list , template-argument
* template-argument: assignment-expression
* type-id
* id-expression
*
* @param templateDeclaration Callback's templateDeclaration which serves as a scope to this list.
* @throws BacktrackException request for a backtrack
*/
protected List templateParameterList(IASTScope scope)
throws BacktrackException, EndOfFileException
{
// if we have gotten this far then we have a true template-declaration
// iterate through the template parameter list
List returnValue = new ArrayList();
for (;;)
{
if (LT(1) == IToken.tGT)
return returnValue;
if (LT(1) == IToken.t_class || LT(1) == IToken.t_typename)
{
IASTTemplateParameter.ParamKind kind =
(consume().getType() == IToken.t_class)
? IASTTemplateParameter.ParamKind.CLASS
: IASTTemplateParameter.ParamKind.TYPENAME;
IToken id = null;
IASTTypeId typeId = null;
try
{
if (LT(1) == IToken.tIDENTIFIER) // optional identifier
{
id = identifier();
if (LT(1) == IToken.tASSIGN) // optional = type-id
{
consume(IToken.tASSIGN);
typeId = typeId(scope, false); // type-id
}
}
}
catch (BacktrackException bt)
{
throw bt;
}
try
{
returnValue.add(
astFactory.createTemplateParameter(
kind,
( id == null )? "" : id.getImage(),
(typeId == null) ? null : typeId.getTypeOrClassName(),
null,
null));
}
catch (Exception e)
{
throw backtrack;
}
}
else if (LT(1) == IToken.t_template)
{
consume(IToken.t_template);
consume(IToken.tLT);
List subResult = templateParameterList(scope);
consume(IToken.tGT);
consume(IToken.t_class);
IToken optionalId = null;
IASTTypeId optionalTypeId = null;
if (LT(1) == IToken.tIDENTIFIER) // optional identifier
{
optionalId = identifier();
if (LT(1) == IToken.tASSIGN) // optional = type-id
{
consume(IToken.tASSIGN);
optionalTypeId = typeId(scope, false);
}
}
try
{
returnValue.add(
astFactory.createTemplateParameter(
IASTTemplateParameter.ParamKind.TEMPLATE_LIST,
( optionalId == null )? "" : optionalId.getImage(),
( optionalTypeId == null ) ? "" : optionalTypeId.toString(),
null,
subResult));
}
catch (Exception e)
{
throw backtrack;
}
}
else if (LT(1) == IToken.tCOMMA)
{
consume(IToken.tCOMMA);
continue;
}
else
{
ParameterCollection c = new ParameterCollection();
parameterDeclaration(c, scope);
DeclarationWrapper wrapper =
(DeclarationWrapper)c.getParameters().get(0);
Declarator declarator =
(Declarator)wrapper.getDeclarators().next();
try
{
returnValue.add(
astFactory.createTemplateParameter(
IASTTemplateParameter.ParamKind.PARAMETER,
null,
null,
astFactory.createParameterDeclaration(
wrapper.isConst(),
wrapper.isVolatile(),
wrapper.getTypeSpecifier(),
declarator.getPointerOperators(),
declarator.getArrayModifiers(),
null, null, declarator.getName() == null
? ""
: declarator.getName(), declarator.getInitializerClause(), wrapper.getStartingOffset(), declarator.getNameStartOffset(), declarator.getNameEndOffset(), wrapper.getEndOffset()),
null));
}
catch (Exception e)
{
throw backtrack;
}
}
}
}
/**
* The most abstract construct within a translationUnit : a declaration.
*
* declaration
* : {"asm"} asmDefinition
* | {"namespace"} namespaceDefinition
* | {"using"} usingDeclaration
* | {"export"|"template"} templateDeclaration
* | {"extern"} linkageSpecification
* | simpleDeclaration
*
* Notes:
* - folded in blockDeclaration
* - merged alternatives that required same LA
* - functionDefinition into simpleDeclaration
* - namespaceAliasDefinition into namespaceDefinition
* - usingDirective into usingDeclaration
* - explicitInstantiation and explicitSpecialization into
* templateDeclaration
*
* @param container IParserCallback object which serves as the owner scope for this declaration.
* @throws BacktrackException request a backtrack
*/
protected void declaration(
IASTScope scope,
IASTTemplate ownerTemplate)
throws EndOfFileException, BacktrackException
{
setCurrentScope(scope);
setCompletionKeywords( Key.DECLARATION );
switch (LT(1))
{
case IToken.t_asm :
IToken first = consume(IToken.t_asm);
setCompletionKind( CompletionKind.NO_SUCH_KIND );
consume(IToken.tLPAREN);
String assembly = consume(IToken.tSTRING).getImage();
consume(IToken.tRPAREN);
IToken last = consume(IToken.tSEMI);
IASTASMDefinition asmDefinition;
try
{
asmDefinition =
astFactory.createASMDefinition(
scope,
assembly,
first.getOffset(),
last.getEndOffset());
}
catch (Exception e)
{
throw backtrack;
}
// if we made it this far, then we have all we need
// do the callback
asmDefinition.acceptElement(requestor);
return;
case IToken.t_namespace :
namespaceDefinition(scope);
return;
case IToken.t_using :
usingClause(scope);
return;
case IToken.t_export :
case IToken.t_template :
templateDeclaration(scope);
return;
case IToken.t_extern :
if (LT(2) == IToken.tSTRING)
{
linkageSpecification(scope);
return;
}
default :
simpleDeclarationStrategyUnion(scope, ownerTemplate);
}
setCurrentScope(scope);
setCompletionKeywords( Key.DECLARATION );
}
protected void simpleDeclarationStrategyUnion(
IASTScope scope,
IASTTemplate ownerTemplate)
throws EndOfFileException, BacktrackException
{
IToken mark = mark();
if( scope instanceof IASTClassSpecifier )
setCompletionKind( CompletionKind.FIELD_TYPE );
else if (scope instanceof IASTCodeScope)
setCompletionKind( CompletionKind.SINGLE_NAME_REFERENCE);
else
setCompletionKind( CompletionKind.VARIABLE_TYPE );
try
{
simpleDeclaration(
SimpleDeclarationStrategy.TRY_CONSTRUCTOR,
scope,
ownerTemplate);
// try it first with the original strategy
}
catch (BacktrackException bt)
{
// did not work
backup(mark);
try
{
simpleDeclaration(
SimpleDeclarationStrategy.TRY_FUNCTION,
scope,
ownerTemplate);
}
catch( BacktrackException bt2 )
{
backup( mark );
try
{
simpleDeclaration(
SimpleDeclarationStrategy.TRY_VARIABLE,
scope,
ownerTemplate);
}
catch( BacktrackException b3 )
{
backup( mark );
throw b3;
}
}
}
}
/**
* Serves as the namespace declaration portion of the ANSI C++ grammar.
*
* namespace-definition:
* namespace identifier { namespace-body } | namespace { namespace-body }
* namespace-body:
* declaration-seq?
* @param container IParserCallback object which serves as the owner scope for this declaration.
* @throws BacktrackException request a backtrack
*/
protected void namespaceDefinition(IASTScope scope)
throws BacktrackException, EndOfFileException
{
IToken first = consume(IToken.t_namespace);
IToken identifier = null;
// optional name
if (LT(1) == IToken.tIDENTIFIER)
identifier = identifier();
if (LT(1) == IToken.tLBRACE)
{
consume();
IASTNamespaceDefinition namespaceDefinition = null;
try
{
namespaceDefinition =
astFactory.createNamespaceDefinition(
scope,
(identifier == null ? "" : identifier.getImage()),
first.getOffset(),
(identifier == null ? first.getOffset() : identifier.getOffset()),
(identifier == null ? first.getEndOffset() : identifier.getEndOffset() ));
}
catch (Exception e1)
{
throw backtrack;
}
namespaceDefinition.enterScope( requestor );
namepsaceDeclarationLoop : while (LT(1) != IToken.tRBRACE)
{
IToken checkToken = LA(1);
switch (LT(1))
{
case IToken.tRBRACE :
//consume(Token.tRBRACE);
break namepsaceDeclarationLoop;
default :
try
{
declaration(namespaceDefinition, null);
}
catch (BacktrackException bt)
{
failParse();
if (checkToken == LA(1))
errorHandling();
}
}
if (checkToken == LA(1))
errorHandling();
}
// consume the }
IToken last = consume(IToken.tRBRACE);
namespaceDefinition.setEndingOffset(
last.getOffset() + last.getLength());
namespaceDefinition.exitScope( requestor );
}
else if( LT(1) == IToken.tASSIGN )
{
consume( IToken.tASSIGN );
if( identifier == null )
throw backtrack;
ITokenDuple duple = name();
consume( IToken.tSEMI );
try
{
astFactory.createNamespaceAlias(
scope, identifier.getImage(), duple, first.getOffset(),
identifier.getOffset(), identifier.getEndOffset(), duple.getLastToken().getEndOffset() );
}
catch (Exception e1)
{
throw backtrack;
}
}
else
{
throw backtrack;
}
}
/**
* Serves as the catch-all for all complicated declarations, including function-definitions.
*
* simpleDeclaration
* : (declSpecifier)* (initDeclarator ("," initDeclarator)*)?
* (";" | { functionBody }
*
* Notes:
* - append functionDefinition stuff to end of this rule
*
* To do:
* - work in functionTryBlock
*
* @param container IParserCallback object which serves as the owner scope for this declaration.
* @param tryConstructor true == take strategy1 (constructor ) : false == take strategy 2 ( pointer to function)
* @throws BacktrackException request a backtrack
*/
protected void simpleDeclaration(
SimpleDeclarationStrategy strategy,
IASTScope scope,
IASTTemplate ownerTemplate)
throws BacktrackException, EndOfFileException
{
IToken firstToken = LA(1);
DeclarationWrapper sdw =
new DeclarationWrapper(scope, firstToken.getOffset(), ownerTemplate);
setCompletionKeywords( Key.DECL_SPECIFIER_SEQUENCE );
declSpecifierSeq(sdw, false, strategy == SimpleDeclarationStrategy.TRY_CONSTRUCTOR );
if (sdw.getTypeSpecifier() == null && sdw.getSimpleType() != IASTSimpleTypeSpecifier.Type.UNSPECIFIED )
try
{
sdw.setTypeSpecifier(
astFactory.createSimpleTypeSpecifier(
scope,
sdw.getSimpleType(),
sdw.getName(),
sdw.isShort(),
sdw.isLong(),
sdw.isSigned(),
sdw.isUnsigned(), sdw.isTypeNamed(), sdw.isComplex(), sdw.isImaginary()));
}
catch (Exception e1)
{
throw backtrack;
}
Declarator declarator = null;
if (LT(1) != IToken.tSEMI)
{
declarator = initDeclarator(sdw, strategy);
while (LT(1) == IToken.tCOMMA)
{
consume();
initDeclarator(sdw, strategy);
}
}
boolean hasFunctionBody = false;
boolean hasFunctionTryBlock = false;
boolean consumedSemi = false;
switch (LT(1))
{
case IToken.tSEMI :
consume(IToken.tSEMI);
consumedSemi = true;
break;
case IToken.t_try :
consume( IToken.t_try );
if( LT(1) == IToken.tCOLON )
ctorInitializer( declarator );
hasFunctionTryBlock = true;
declarator.setFunctionTryBlock( true );
break;
case IToken.tCOLON :
ctorInitializer(declarator);
break;
case IToken.tLBRACE:
break;
default:
throw backtrack;
}
if( ! consumedSemi )
{
if( LT(1) == IToken.tLBRACE )
{
if( firstToken == LA(1) )
throw backtrack;
declarator.setHasFunctionBody(true);
hasFunctionBody = true;
}
if( hasFunctionTryBlock && ! hasFunctionBody )
throw backtrack;
}
List l = null;
try
{
l = sdw.createASTNodes(astFactory);
}
catch (ASTSemanticException e)
{
throw backtrack;
}
Iterator i = l.iterator();
if (hasFunctionBody && l.size() != 1)
{
throw backtrack; //TODO Should be an IProblem
}
if (i.hasNext()) // no need to do this unless we have a declarator
{
if (!hasFunctionBody)
{
while (i.hasNext())
{
IASTDeclaration declaration = (IASTDeclaration)i.next();
((IASTOffsetableElement)declaration).setEndingOffset(
lastToken.getEndOffset());
declaration.acceptElement( requestor );
}
}
else
{
IASTDeclaration declaration = (IASTDeclaration)i.next();
declaration.enterScope( requestor );
if ( !( declaration instanceof IASTScope ) )
throw backtrack;
handleFunctionBody((IASTScope)declaration,
sdw.isInline() );
((IASTOffsetableElement)declaration).setEndingOffset(
lastToken.getEndOffset());
declaration.exitScope( requestor );
if( hasFunctionTryBlock )
catchHandlerSequence( scope );
}
}
else
{
try
{
astFactory
.createTypeSpecDeclaration(
sdw.getScope(),
sdw.getTypeSpecifier(),
ownerTemplate,
sdw.getStartingOffset(),
lastToken.getEndOffset())
.acceptElement(requestor);
}
catch (Exception e1)
{
throw backtrack;
}
}
}
protected abstract void handleFunctionBody(IASTScope scope, boolean isInlineFunction) throws BacktrackException, EndOfFileException;
protected void skipOverCompoundStatement() throws BacktrackException, EndOfFileException
{
// speed up the parser by skiping the body
// simply look for matching brace and return
consume(IToken.tLBRACE);
int depth = 1;
while (depth > 0)
{
switch (consume().getType())
{
case IToken.tRBRACE :
--depth;
break;
case IToken.tLBRACE :
++depth;
break;
}
}
}
/**
* This method parses a constructor chain
* ctorinitializer: : meminitializerlist
* meminitializerlist: meminitializer | meminitializer , meminitializerlist
* meminitializer: meminitializerid | ( expressionlist? )
* meminitializerid: ::? nestednamespecifier?
* classname
* identifier
* @param declarator IParserCallback object that represents the declarator (constructor) that owns this initializer
* @throws BacktrackException request a backtrack
*/
protected void ctorInitializer(Declarator d )
throws EndOfFileException, BacktrackException
{
consume(IToken.tCOLON);
try
{
for (;;)
{
if (LT(1) == IToken.tLBRACE)
break;
ITokenDuple duple = name();
consume(IToken.tLPAREN);
IASTExpression expressionList = null;
expressionList = expression(d.getDeclarationWrapper().getScope());
consume(IToken.tRPAREN);
try
{
d.addConstructorMemberInitializer(
astFactory.createConstructorMemberInitializer(
d.getDeclarationWrapper().getScope(),
duple, expressionList));
}
catch (Exception e1)
{
throw backtrack;
}
if (LT(1) == IToken.tLBRACE)
break;
consume(IToken.tCOMMA);
}
}
catch (BacktrackException bt)
{
throw backtrack;
}
}
/**
* This routine parses a parameter declaration
*
* @param containerObject The IParserCallback object representing the parameterDeclarationClause owning the parm.
* @throws BacktrackException request a backtrack
*/
protected void parameterDeclaration(
IParameterCollection collection, IASTScope scope)
throws BacktrackException, EndOfFileException
{
IToken current = LA(1);
DeclarationWrapper sdw =
new DeclarationWrapper(scope, current.getOffset(), null);
declSpecifierSeq(sdw, true, false);
if (sdw.getTypeSpecifier() == null
&& sdw.getSimpleType()
!= IASTSimpleTypeSpecifier.Type.UNSPECIFIED)
try
{
sdw.setTypeSpecifier(
astFactory.createSimpleTypeSpecifier(
scope,
sdw.getSimpleType(),
sdw.getName(),
sdw.isShort(),
sdw.isLong(),
sdw.isSigned(),
sdw.isUnsigned(), sdw.isTypeNamed(), sdw.isComplex(), sdw.isImaginary()));
}
catch (ASTSemanticException e)
{
throw backtrack;
}
catch (Exception e)
{
throw backtrack;
}
if (LT(1) != IToken.tSEMI)
initDeclarator(sdw, SimpleDeclarationStrategy.TRY_FUNCTION );
if( lastToken != null )
sdw.setEndingOffset( lastToken.getEndOffset() );
if (current == LA(1))
throw backtrack;
collection.addParameter(sdw);
}
/**
* This class represents the state and strategy for parsing declarationSpecifierSequences
*/
private class Flags
{
private boolean encounteredTypename = false;
// have we encountered a typeName yet?
private boolean encounteredRawType = false;
// have we encountered a raw type yet?
private final boolean parm;
// is this for a simpleDeclaration or parameterDeclaration?
private final boolean constructor;
// are we attempting the constructor strategy?
public Flags(boolean parm, boolean c)
{
this.parm = parm;
constructor = c;
}
/**
* @return true if we have encountered a simple type up to this point, false otherwise
*/
public boolean haveEncounteredRawType()
{
return encounteredRawType;
}
/**
* @return true if we have encountered a typename up to this point, false otherwise
*/
public boolean haveEncounteredTypename()
{
return encounteredTypename;
}
/**
* @param b - set to true if we encounter a raw type (int, short, etc.)
*/
public void setEncounteredRawType(boolean b)
{
encounteredRawType = b;
}
/**
* @param b - set to true if we encounter a typename
*/
public void setEncounteredTypename(boolean b)
{
encounteredTypename = b;
}
/**
* @return true if we are parsing for a ParameterDeclaration
*/
public boolean isForParameterDeclaration()
{
return parm;
}
/**
* @return whether or not we are attempting the constructor strategy or not
*/
public boolean isForConstructor()
{
return constructor;
}
}
/**
* @param flags input flags that are used to make our decision
* @return whether or not this looks like a constructor (true or false)
* @throws EndOfFileException we could encounter EOF while looking ahead
*/
private boolean lookAheadForConstructorOrConversion(Flags flags, DeclarationWrapper sdw )
throws EndOfFileException
{
if (flags.isForParameterDeclaration())
return false;
if (LT(2) == IToken.tLPAREN && flags.isForConstructor())
return true;
IToken mark = mark();
Declarator d = new Declarator( sdw );
try
{
consumeTemplatedOperatorName( d );
}
catch (BacktrackException e)
{
backup( mark );
return false;
}
ITokenDuple duple = d.getNameDuple();
if( duple == null )
{
backup( mark );
return false;
}
int lastColon = duple.findLastTokenType(IToken.tCOLON);
if( lastColon == -1 )
{
int lt1 = LT(1);
backup( mark );
return flags.isForConstructor() && (lt1 == IToken.tLPAREN);
}
IToken className = null;
int index = lastColon - 1;
if( duple.getToken( index ).getType() == IToken.tGT )
{
int depth = -1;
while( depth == -1 )
{
if( duple.getToken( --index ).getType() == IToken.tLT )
++depth;
}
className = duple.getToken( index );
}
boolean result = className.getImage().equals( duple.getLastToken());
backup( mark );
return result;
}
/**
* @param flags input flags that are used to make our decision
* @return whether or not this looks like a a declarator follows
* @throws EndOfFileException we could encounter EOF while looking ahead
*/
private boolean lookAheadForDeclarator(Flags flags) throws EndOfFileException
{
return flags.haveEncounteredTypename()
&& ((LT(2) != IToken.tIDENTIFIER
|| (LT(3) != IToken.tLPAREN && LT(3) != IToken.tASSIGN))
&& !LA(2).isPointer());
}
private void callbackSimpleDeclToken(Flags flags) throws BacktrackException, EndOfFileException
{
flags.setEncounteredRawType(true);
consume();
}
/**
* This function parses a declaration specifier sequence, as according to the ANSI C++ spec.
*
* declSpecifier
* : "auto" | "register" | "static" | "extern" | "mutable"
* | "inline" | "virtual" | "explicit"
* | "char" | "wchar_t" | "bool" | "short" | "int" | "long"
* | "signed" | "unsigned" | "float" | "double" | "void"
* | "const" | "volatile"
* | "friend" | "typedef"
* | ("typename")? name
* | {"class"|"struct"|"union"} classSpecifier
* | {"enum"} enumSpecifier
*
* Notes:
* - folded in storageClassSpecifier, typeSpecifier, functionSpecifier
* - folded elaboratedTypeSpecifier into classSpecifier and enumSpecifier
* - find template names in name
*
* @param decl IParserCallback object representing the declaration that owns this specifier sequence
* @param parm Is this for a parameter declaration (true) or simple declaration (false)
* @param tryConstructor true for constructor, false for pointer to function strategy
* @throws BacktrackException request a backtrack
*/
protected void declSpecifierSeq(
DeclarationWrapper sdw,
boolean parm,
boolean tryConstructor )
throws BacktrackException, EndOfFileException
{
Flags flags = new Flags(parm, tryConstructor);
IToken typeNameBegin = null;
IToken typeNameEnd = null;
declSpecifiers : for (;;)
{
switch (LT(1))
{
case IToken.t_inline :
consume();
sdw.setInline(true);
break;
case IToken.t_auto :
consume();
sdw.setAuto(true);
break;
case IToken.t_register :
sdw.setRegister(true);
consume();
break;
case IToken.t_static :
sdw.setStatic(true);
consume();
break;
case IToken.t_extern :
sdw.setExtern(true);
consume();
break;
case IToken.t_mutable :
sdw.setMutable(true);
consume();
break;
case IToken.t_virtual :
sdw.setVirtual(true);
consume();
break;
case IToken.t_explicit :
sdw.setExplicit(true);
consume();
break;
case IToken.t_typedef :
sdw.setTypedef(true);
consume();
break;
case IToken.t_friend :
sdw.setFriend(true);
consume();
break;
case IToken.t_const :
sdw.setConst(true);
consume();
break;
case IToken.t_volatile :
sdw.setVolatile(true);
consume();
break;
case IToken.t_signed :
sdw.setSigned(true);
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(IASTSimpleTypeSpecifier.Type.INT);
break;
case IToken.t_unsigned :
sdw.setUnsigned(true);
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(IASTSimpleTypeSpecifier.Type.INT);
break;
case IToken.t_short :
sdw.setShort(true);
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(IASTSimpleTypeSpecifier.Type.INT);
break;
case IToken.t_long :
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(IASTSimpleTypeSpecifier.Type.INT);
sdw.setLong(true);
break;
case IToken.t__Complex :
consume( IToken.t__Complex );
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
sdw.setComplex( true );
break;
case IToken.t__Imaginary :
consume( IToken.t__Imaginary );
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
sdw.setImaginary( true );
break;
case IToken.t_char :
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(IASTSimpleTypeSpecifier.Type.CHAR);
break;
case IToken.t_wchar_t :
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(
IASTSimpleTypeSpecifier.Type.WCHAR_T);
break;
case IToken.t_bool :
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(IASTSimpleTypeSpecifier.Type.BOOL);
break;
case IToken.t__Bool:
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(IASTSimpleTypeSpecifier.Type._BOOL);
break;
case IToken.t_int :
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(IASTSimpleTypeSpecifier.Type.INT);
break;
case IToken.t_float :
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(IASTSimpleTypeSpecifier.Type.FLOAT);
break;
case IToken.t_double :
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(
IASTSimpleTypeSpecifier.Type.DOUBLE);
break;
case IToken.t_void :
if (typeNameBegin == null)
typeNameBegin = LA(1);
typeNameEnd = LA(1);
callbackSimpleDeclToken(flags);
sdw.setSimpleType(IASTSimpleTypeSpecifier.Type.VOID);
break;
case IToken.t_typename :
sdw.setTypenamed(true);
consume(IToken.t_typename );
IToken first = LA(1);
IToken last = null;
last = name().getLastToken();
if (LT(1) == IToken.t_template)
{
consume(IToken.t_template);
last = templateId();
}
ITokenDuple duple = new TokenDuple(first, last);
sdw.setTypeName(duple);
break;
case IToken.tCOLONCOLON :
consume(IToken.tCOLONCOLON);
case IToken.tIDENTIFIER :
// TODO - Kludgy way to handle constructors/destructors
if (flags.haveEncounteredRawType())
{
if (typeNameBegin != null)
sdw.setTypeName(
new TokenDuple(typeNameBegin, typeNameEnd));
return;
}
if (parm && flags.haveEncounteredTypename())
{
if (typeNameBegin != null)
sdw.setTypeName(
new TokenDuple(typeNameBegin, typeNameEnd));
return;
}
if (lookAheadForConstructorOrConversion(flags, sdw))
{
if (typeNameBegin != null)
sdw.setTypeName(
new TokenDuple(typeNameBegin, typeNameEnd));
return;
}
if (lookAheadForDeclarator(flags))
{
if (typeNameBegin != null)
sdw.setTypeName(
new TokenDuple(typeNameBegin, typeNameEnd));
return;
}
ITokenDuple d = name();
sdw.setTypeName(d);
sdw.setSimpleType( IASTSimpleTypeSpecifier.Type.CLASS_OR_TYPENAME );
flags.setEncounteredTypename(true);
break;
case IToken.t_class :
case IToken.t_struct :
case IToken.t_union :
try
{
classSpecifier(sdw);
flags.setEncounteredTypename(true);
break;
}
catch (BacktrackException bt)
{
elaboratedTypeSpecifier(sdw);
flags.setEncounteredTypename(true);
break;
}
case IToken.t_enum :
try
{
enumSpecifier(sdw);
flags.setEncounteredTypename(true);
break;
}
catch (BacktrackException bt)
{
// this is an elaborated class specifier
elaboratedTypeSpecifier(sdw);
flags.setEncounteredTypename(true);
break;
}
default :
break declSpecifiers;
}
}
if (typeNameBegin != null)
sdw.setTypeName(new TokenDuple(typeNameBegin, typeNameEnd));
}
/**
* Parse an elaborated type specifier.
*
* @param decl Declaration which owns the elaborated type
* @throws BacktrackException request a backtrack
*/
protected void elaboratedTypeSpecifier(DeclarationWrapper sdw)
throws BacktrackException, EndOfFileException
{
// this is an elaborated class specifier
IToken t = consume();
ASTClassKind eck = null;
switch (t.getType())
{
case Token.t_class :
eck = ASTClassKind.CLASS;
break;
case Token.t_struct :
eck = ASTClassKind.STRUCT;
break;
case Token.t_union :
eck = ASTClassKind.UNION;
break;
case Token.t_enum :
eck = ASTClassKind.ENUM;
break;
default :
break;
}
ITokenDuple d = name();
IASTTypeSpecifier elaboratedTypeSpec = null;
final boolean isForewardDecl = ( LT(1) == IToken.tSEMI );
try
{
elaboratedTypeSpec =
astFactory.createElaboratedTypeSpecifier(
sdw.getScope(),
eck,
d,
t.getOffset(),
d.getLastToken().getEndOffset(),
isForewardDecl, sdw.isFriend() );
}
catch (ASTSemanticException e)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
sdw.setTypeSpecifier(elaboratedTypeSpec);
if( isForewardDecl )
((IASTElaboratedTypeSpecifier)elaboratedTypeSpec).acceptElement( requestor );
}
/**
* Consumes template parameters.
*
* @param previousLast Previous "last" token (returned if nothing was consumed)
* @return Last consumed token, or <code>previousLast</code> if nothing was consumed
* @throws BacktrackException request a backtrack
*/
protected IToken consumeTemplateParameters(IToken previousLast)
throws EndOfFileException, BacktrackException
{
IToken last = previousLast;
if (LT(1) == IToken.tLT)
{
last = consume(IToken.tLT);
// until we get all the names sorted out
Stack scopes = new Stack();
scopes.push(new Integer(IToken.tLT));
while (!scopes.empty())
{
int top;
last = consume();
switch (last.getType()) {
case IToken.tGT :
if (((Integer)scopes.peek()).intValue() == IToken.tLT) {
scopes.pop();
}
break;
case IToken.tRBRACKET :
do {
top = ((Integer)scopes.pop()).intValue();
} while (!scopes.empty() && (top == IToken.tGT || top == IToken.tLT));
if (top != IToken.tLBRACKET) throw backtrack;
break;
case IToken.tRPAREN :
do {
top = ((Integer)scopes.pop()).intValue();
} while (!scopes.empty() && (top == IToken.tGT || top == IToken.tLT));
if (top != IToken.tLPAREN) throw backtrack;
break;
case IToken.tLT :
case IToken.tLBRACKET:
case IToken.tLPAREN:
scopes.push(new Integer(last.getType()));
break;
}
}
}
return last;
}
/**
* Parse an identifier.
*
* @throws BacktrackException request a backtrack
*/
protected IToken identifier() throws EndOfFileException, BacktrackException
{
IToken first = consume(IToken.tIDENTIFIER); // throws backtrack if its not that
return first;
}
/**
* Parses a className.
*
* class-name: identifier | template-id
*
* @throws BacktrackException
*/
protected ITokenDuple className() throws EndOfFileException, BacktrackException
{
ITokenDuple duple = name();
IToken last = duple.getLastToken();
if (LT(1) == IToken.tLT) {
last = consumeTemplateParameters(duple.getLastToken());
}
return new TokenDuple(duple.getFirstToken(), last);
}
/**
* Parse a template-id, according to the ANSI C++ spec.
*
* template-id: template-name < template-argument-list opt >
* template-name : identifier
*
* @return the last token that we consumed in a successful parse
*
* @throws BacktrackException request a backtrack
*/
protected IToken templateId() throws EndOfFileException, BacktrackException
{
ITokenDuple duple = name();
IToken last = consumeTemplateParameters(duple.getLastToken());
return last;
}
/**
* Parse a name.
*
* name
* : ("::")? name2 ("::" name2)*
*
* name2
* : IDENTIFER
*
* @throws BacktrackException request a backtrack
*/
protected TokenDuple name() throws BacktrackException, EndOfFileException
{
IToken first = LA(1);
IToken last = null;
IToken mark = mark();
try
{
if (LT(1) == IToken.tCOLONCOLON)
last = consume( IToken.tCOLONCOLON );
// TODO - whacky way to deal with destructors, please revisit
if (LT(1) == IToken.tCOMPL)
consume();
switch (LT(1))
{
case IToken.tIDENTIFIER :
last = consume(IToken.tIDENTIFIER);
IToken secondMark = null;
try
{
secondMark = mark();
}
catch( OffsetLimitReachedException olre )
{
return new TokenDuple(last, last);
}
try
{
last = consumeTemplateParameters(last);
} catch( BacktrackException bt )
{
backup( secondMark );
}
break;
default :
backup(mark);
throw backtrack;
}
while (LT(1) == IToken.tCOLONCOLON)
{
last = consume();
if (LT(1) == IToken.t_template)
consume();
if (LT(1) == IToken.tCOMPL)
consume();
switch (LT(1))
{
case IToken.t_operator :
backup(mark);
throw backtrack;
case IToken.tIDENTIFIER :
last = consume();
last = consumeTemplateParameters(last);
}
}
return new TokenDuple(first, last);
} catch( OffsetLimitReachedException olre )
{
backup(mark);
throw backtrack;
}
}
/**
* Parse a const-volatile qualifier.
*
* cvQualifier
* : "const" | "volatile"
*
* TODO: fix this
* @param ptrOp Pointer Operator that const-volatile applies to.
* @return Returns the same object sent in.
* @throws BacktrackException
*/
protected IToken cvQualifier(
IDeclarator declarator)
throws EndOfFileException, BacktrackException
{
IToken result = null;
switch (LT(1))
{
case IToken.t_const :
result = consume( IToken.t_const );
declarator.addPointerOperator(ASTPointerOperator.CONST_POINTER);
break;
case IToken.t_volatile :
result = consume( IToken.t_volatile );
declarator.addPointerOperator(ASTPointerOperator.VOLATILE_POINTER);
break;
case IToken.t_restrict :
if( language == ParserLanguage.C )
{
result = consume( IToken.t_restrict );
declarator.addPointerOperator(ASTPointerOperator.RESTRICT_POINTER);
break;
}
else
throw backtrack;
default :
}
return result;
}
/**
* Parses the initDeclarator construct of the ANSI C++ spec.
*
* initDeclarator
* : declarator ("=" initializerClause | "(" expressionList ")")?
* @param owner IParserCallback object that represents the owner declaration object.
* @return declarator that this parsing produced.
* @throws BacktrackException request a backtrack
*/
protected Declarator initDeclarator(
DeclarationWrapper sdw, SimpleDeclarationStrategy strategy )
throws EndOfFileException, BacktrackException
{
Declarator d = declarator(sdw, sdw.getScope(), strategy );
if( language == ParserLanguage.CPP )
optionalCPPInitializer(d);
else if( language == ParserLanguage.C )
optionalCInitializer(d);
sdw.addDeclarator(d);
return d;
}
protected void optionalCPPInitializer(Declarator d)
throws EndOfFileException, BacktrackException
{
// handle initializer
if (LT(1) == IToken.tASSIGN)
{
consume(IToken.tASSIGN);
d.setInitializerClause(initializerClause(d.getDeclarationWrapper().getScope()));
}
else if (LT(1) == IToken.tLPAREN )
{
IToken mark = mark();
// initializer in constructor
try
{
consume(IToken.tLPAREN); // EAT IT!
IASTExpression astExpression = null;
astExpression = expression(d.getDeclarationWrapper().getScope());
consume(IToken.tRPAREN);
d.setConstructorExpression(astExpression);
} catch( BacktrackException bt )
{
backup( mark );
throw bt;
}
}
}
protected void optionalCInitializer( Declarator d ) throws EndOfFileException, BacktrackException
{
if( LT(1) == IToken.tASSIGN )
{
consume( IToken.tASSIGN );
d.setInitializerClause( cInitializerClause(d.getDeclarationWrapper().getScope(), EMPTY_LIST ) );
}
}
/**
* @param scope
* @return
*/
protected IASTInitializerClause cInitializerClause(
IASTScope scope,
List designators)
throws EndOfFileException, BacktrackException
{
if (LT(1) == IToken.tLBRACE)
{
consume(IToken.tLBRACE);
List initializerList = new ArrayList();
for (;;)
{
// required at least one initializer list
// get designator list
List newDesignators = designatorList(scope);
if( newDesignators.size() != 0 )
consume( IToken.tASSIGN );
IASTInitializerClause initializer =
cInitializerClause(scope, newDesignators );
initializerList.add(initializer);
// can end with just a '}'
if (LT(1) == IToken.tRBRACE)
break;
// can end with ", }"
if (LT(1) == IToken.tCOMMA)
consume(IToken.tCOMMA);
if (LT(1) == IToken.tRBRACE)
break;
// otherwise, its another initializer in the list
}
// consume the closing brace
consume(IToken.tRBRACE);
return astFactory.createInitializerClause(
scope,
(
( designators.size() == 0 ) ?
IASTInitializerClause.Kind.INITIALIZER_LIST :
IASTInitializerClause.Kind.DESIGNATED_INITIALIZER_LIST ),
null, initializerList, designators );
}
// if we get this far, it means that we have not yet succeeded
// try this now instead
// assignmentExpression
try
{
IASTExpression assignmentExpression = assignmentExpression(scope);
try
{
return astFactory.createInitializerClause(
scope,
(
( designators.size() == 0 ) ?
IASTInitializerClause.Kind.ASSIGNMENT_EXPRESSION :
IASTInitializerClause.Kind.DESIGNATED_ASSIGNMENT_EXPRESSION ),
assignmentExpression, null, designators );
}
catch (Exception e)
{
throw backtrack;
}
}
catch (BacktrackException b)
{
// do nothing
}
throw backtrack;
}
/**
*
*/
protected IASTInitializerClause initializerClause(IASTScope scope)
throws EndOfFileException, BacktrackException
{
if (LT(1) == IToken.tLBRACE)
{
consume(IToken.tLBRACE);
if (LT(1) == (IToken.tRBRACE))
{
consume(IToken.tRBRACE);
try
{
return astFactory.createInitializerClause(
scope,
IASTInitializerClause.Kind.EMPTY,
null, null, EMPTY_LIST );
}
catch (Exception e)
{
throw backtrack;
}
}
// otherwise it is a list of initializer clauses
List initializerClauses = new ArrayList();
for (;;)
{
IASTInitializerClause clause = initializerClause(scope);
initializerClauses.add(clause);
if (LT(1) == IToken.tRBRACE)
break;
consume(IToken.tCOMMA);
}
consume(IToken.tRBRACE);
try
{
return astFactory.createInitializerClause(
scope,
IASTInitializerClause.Kind.INITIALIZER_LIST,
null, initializerClauses, EMPTY_LIST );
}
catch (Exception e)
{
throw backtrack;
}
}
// if we get this far, it means that we did not
// try this now instead
// assignmentExpression
try
{
IASTExpression assignmentExpression =
assignmentExpression(scope);
try
{
return astFactory.createInitializerClause(
scope,
IASTInitializerClause.Kind.ASSIGNMENT_EXPRESSION,
assignmentExpression, null, EMPTY_LIST );
}
catch (Exception e)
{
throw backtrack;
}
}
catch (BacktrackException b)
{
// do nothing
}
catch ( EndOfFileException eof )
{
}
throw backtrack;
}
protected List designatorList(IASTScope scope) throws EndOfFileException, BacktrackException
{
List designatorList = new ArrayList();
// designated initializers for C
if( LT(1) == IToken.tDOT || LT(1) == IToken.tLBRACKET )
{
while( LT(1) == IToken.tDOT || LT(1) == IToken.tLBRACKET )
{
IToken id = null;
IASTExpression constantExpression = null;
IASTDesignator.DesignatorKind kind = null;
if( LT(1) == IToken.tDOT )
{
consume( IToken.tDOT );
id = identifier();
kind = IASTDesignator.DesignatorKind.FIELD;
}
else if( LT(1) == IToken.tLBRACKET )
{
consume( IToken.tLBRACKET );
constantExpression = expression( scope );
consume( IToken.tRBRACKET );
kind = IASTDesignator.DesignatorKind.SUBSCRIPT;
}
IASTDesignator d =
astFactory.createDesignator( kind, constantExpression, id );
designatorList.add( d );
}
}
return designatorList;
}
/**
* Parse a declarator, as according to the ANSI C++ specification.
*
* declarator
* : (ptrOperator)* directDeclarator
*
* directDeclarator
* : declaratorId
* | directDeclarator "(" parameterDeclarationClause ")" (cvQualifier)*
* (exceptionSpecification)*
* | directDeclarator "[" (constantExpression)? "]"
* | "(" declarator")"
* | directDeclarator "(" parameterDeclarationClause ")" (oldKRParameterDeclaration)*
*
* declaratorId
* : name
*
* @param container IParserCallback object that represents the owner declaration.
* @return declarator that this parsing produced.
* @throws BacktrackException request a backtrack
*/
protected Declarator declarator(
IDeclaratorOwner owner, IASTScope scope, SimpleDeclarationStrategy strategy )
throws EndOfFileException, BacktrackException
{
Declarator d = null;
DeclarationWrapper sdw = owner.getDeclarationWrapper();
overallLoop : do
{
d = new Declarator(owner);
consumePointerOperators(d);
if (LT(1) == IToken.tLPAREN)
{
consume();
declarator(d, scope, strategy );
consume(IToken.tRPAREN);
}
else
consumeTemplatedOperatorName(d);
for (;;)
{
switch (LT(1))
{
case IToken.tLPAREN :
// temporary fix for initializer/function declaration ambiguity
if (!LA(2).looksLikeExpression() && strategy != SimpleDeclarationStrategy.TRY_VARIABLE )
{
boolean failed = false;
if( LT(2) == IToken.tIDENTIFIER )
{
IToken newMark = mark();
consume( IToken.tLPAREN );
try
{
try
{
if( ! astFactory.queryIsTypeName( scope, name() ) )
failed = true;
}
catch (Exception e)
{
throw backtrack;
}
} catch( BacktrackException b )
{
failed = true;
}
backup( newMark );
}
if( !failed )
{
// parameterDeclarationClause
d.setIsFunction(true);
// TODO need to create a temporary scope object here
consume(IToken.tLPAREN);
boolean seenParameter = false;
parameterDeclarationLoop : for (;;)
{
switch (LT(1))
{
case IToken.tRPAREN :
consume();
break parameterDeclarationLoop;
case IToken.tELLIPSIS :
consume();
d.setIsVarArgs( true );
break;
case IToken.tCOMMA :
consume();
seenParameter = false;
break;
default :
if (seenParameter)
throw backtrack;
parameterDeclaration(d, scope);
seenParameter = true;
}
}
}
if (LT(1) == IToken.tCOLON || LT(1) == IToken.t_try )
break overallLoop;
IToken beforeCVModifier = mark();
IToken cvModifier = null;
IToken afterCVModifier = beforeCVModifier;
// const-volatile
// 2 options: either this is a marker for the method,
// or it might be the beginning of old K&R style parameter declaration, see
// void getenv(name) const char * name; {}
// This will be determined further below
if (LT(1) == IToken.t_const
|| LT(1) == IToken.t_volatile)
{
cvModifier = consume();
afterCVModifier = mark();
}
//check for throws clause here
List exceptionSpecIds = null;
if (LT(1) == IToken.t_throw)
{
exceptionSpecIds = new ArrayList();
consume(); // throw
consume(IToken.tLPAREN); // (
boolean done = false;
IASTTypeId duple = null;
while (!done)
{
switch (LT(1))
{
case IToken.tRPAREN :
consume();
done = true;
break;
case IToken.tCOMMA :
consume();
break;
default :
String image = LA(1).getImage();
try
{
duple = typeId(scope, false);
exceptionSpecIds.add(duple);
}
catch (BacktrackException e)
{
failParse();
log.traceLog(
"Unexpected Token ="
+ image );
consume();
// eat this token anyway
continue;
}
break;
}
}
if (exceptionSpecIds != null)
try
{
d.setExceptionSpecification(
astFactory
.createExceptionSpecification(
d.getDeclarationWrapper().getScope(), exceptionSpecIds));
}
catch (ASTSemanticException e)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
// check for optional pure virtual
if (LT(1) == IToken.tASSIGN
&& LT(2) == IToken.tINTEGER
&& LA(2).getImage().equals("0"))
{
consume(IToken.tASSIGN);
consume(IToken.tINTEGER);
d.setPureVirtual(true);
}
if (afterCVModifier != LA(1)
|| LT(1) == IToken.tSEMI)
{
// There were C++-specific clauses after const/volatile modifier
// Then it is a marker for the method
if (cvModifier != null)
{
if (cvModifier.getType() == IToken.t_const)
d.setConst(true);
if (cvModifier.getType()
== IToken.t_volatile)
d.setVolatile(true);
}
afterCVModifier = mark();
// In this case (method) we can't expect K&R parameter declarations,
// but we'll check anyway, for errorhandling
}
}
break;
case IToken.tLBRACKET :
consumeArrayModifiers(d, sdw.getScope());
continue;
case IToken.tCOLON :
consume(IToken.tCOLON);
IASTExpression exp = null;
exp = constantExpression(scope);
d.setBitFieldExpression(exp);
default :
break;
}
break;
}
if (LA(1).getType() != IToken.tIDENTIFIER)
break;
}
while (true);
if (d.getOwner() instanceof IDeclarator)
((Declarator)d.getOwner()).setOwnedDeclarator(d);
return d;
}
protected void consumeTemplatedOperatorName(Declarator d)
throws EndOfFileException, BacktrackException
{
if (LT(1) == IToken.t_operator)
operatorId(d, null);
else
{
try
{
ITokenDuple duple = name();
d.setName(duple);
}
catch (BacktrackException bt)
{
Declarator d1 = d;
Declarator d11 = d1;
IToken start = null;
IToken mark = mark();
if (LT(1) == IToken.tCOLONCOLON
|| LT(1) == IToken.tIDENTIFIER)
{
start = consume();
IToken end = null;
if (start.getType() == IToken.tIDENTIFIER)
end = consumeTemplateParameters(end);
while (LT(1) == IToken.tCOLONCOLON
|| LT(1) == IToken.tIDENTIFIER)
{
end = consume();
if (end.getType() == IToken.tIDENTIFIER)
end = consumeTemplateParameters(end);
}
if (LT(1) == IToken.t_operator)
operatorId(d11, start);
else
{
backup(mark);
throw backtrack;
}
}
}
}
}
protected void consumeArrayModifiers( IDeclarator d, IASTScope scope )
throws EndOfFileException, BacktrackException
{
while (LT(1) == IToken.tLBRACKET)
{
consume( IToken.tLBRACKET ); // eat the '['
IASTExpression exp = null;
if (LT(1) != IToken.tRBRACKET)
{
exp = constantExpression(scope);
}
consume(IToken.tRBRACKET);
IASTArrayModifier arrayMod;
try
{
arrayMod = astFactory.createArrayModifier(exp);
}
catch (Exception e)
{
throw backtrack;
}
d.addArrayModifier(arrayMod);
}
}
protected void operatorId(
Declarator d,
IToken originalToken)
throws BacktrackException, EndOfFileException
{
// we know this is an operator
IToken operatorToken = consume(IToken.t_operator);
IToken toSend = null;
if (LA(1).isOperator()
|| LT(1) == IToken.tLPAREN
|| LT(1) == IToken.tLBRACKET)
{
if ((LT(1) == IToken.t_new || LT(1) == IToken.t_delete)
&& LT(2) == IToken.tLBRACKET
&& LT(3) == IToken.tRBRACKET)
{
consume();
consume(IToken.tLBRACKET);
toSend = consume(IToken.tRBRACKET);
// vector new and delete operators
}
else if (LT(1) == IToken.tLPAREN && LT(2) == IToken.tRPAREN)
{
// operator ()
consume(IToken.tLPAREN);
toSend = consume(IToken.tRPAREN);
}
else if (LT(1) == IToken.tLBRACKET && LT(2) == IToken.tRBRACKET)
{
consume(IToken.tLBRACKET);
toSend = consume(IToken.tRBRACKET);
}
else if (LA(1).isOperator())
toSend = consume();
else
throw backtrack;
}
else
{
// must be a conversion function
typeId(d.getDeclarationWrapper().getScope(), true );
toSend = lastToken;
}
ITokenDuple duple =
new TokenDuple(
originalToken == null ? operatorToken : originalToken,
toSend);
d.setName(duple);
}
/**
* Parse a Pointer Operator.
*
* ptrOperator
* : "*" (cvQualifier)*
* | "&"
* | ::? nestedNameSpecifier "*" (cvQualifier)*
*
* @param owner Declarator that this pointer operator corresponds to.
* @throws BacktrackException request a backtrack
*/
protected IToken consumePointerOperators(IDeclarator d) throws EndOfFileException, BacktrackException
{
IToken result = null;
for( ; ; )
{
if (LT(1) == IToken.tAMPER)
{
result = consume( IToken.tAMPER );
d.addPointerOperator(ASTPointerOperator.REFERENCE);
return result;
}
IToken mark = mark();
ITokenDuple nameDuple = null;
if (LT(1) == IToken.tIDENTIFIER || LT(1) == IToken.tCOLONCOLON)
{
try
{
nameDuple = name();
}
catch( BacktrackException bt )
{
backup( mark );
return null;
}
}
if ( LT(1) == IToken.tSTAR)
{
result = consume(Token.tSTAR); // tokenType = "*"
d.setPointerOperatorName(nameDuple);
IToken successful = null;
for (;;)
{
IToken newSuccess = cvQualifier(d);
if( newSuccess != null ) successful = newSuccess;
else break;
}
if( successful == null )
{
d.addPointerOperator( ASTPointerOperator.POINTER );
}
continue;
}
backup(mark);
return result;
}
}
/**
* Parse an enumeration specifier, as according to the ANSI specs in C & C++.
*
* enumSpecifier:
* "enum" (name)? "{" (enumerator-list) "}"
* enumerator-list:
* enumerator-definition
* enumerator-list , enumerator-definition
* enumerator-definition:
* enumerator
* enumerator = constant-expression
* enumerator: identifier
*
* @param owner IParserCallback object that represents the declaration that owns this type specifier.
* @throws BacktrackException request a backtrack
*/
protected void enumSpecifier(DeclarationWrapper sdw)
throws BacktrackException, EndOfFileException
{
IToken mark = mark();
IToken identifier = null;
consume( IToken.t_enum );
if (LT(1) == IToken.tIDENTIFIER)
{
identifier = identifier();
}
if (LT(1) == IToken.tLBRACE)
{
IASTEnumerationSpecifier enumeration = null;
try
{
enumeration = astFactory.createEnumerationSpecifier(
sdw.getScope(),
((identifier == null) ? "" : identifier.getImage()),
mark.getOffset(),
((identifier == null)
? mark.getOffset()
: identifier.getOffset()),
((identifier == null)? mark.getEndOffset()
: identifier.getEndOffset()));
}
catch (ASTSemanticException e)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
consume(IToken.tLBRACE);
while (LT(1) != IToken.tRBRACE)
{
IToken enumeratorIdentifier = null;
if (LT(1) == IToken.tIDENTIFIER)
{
enumeratorIdentifier = identifier();
}
else
{
throw backtrack;
}
IASTExpression initialValue = null;
if (LT(1) == IToken.tASSIGN)
{
consume(IToken.tASSIGN);
initialValue = constantExpression(sdw.getScope());
}
if (LT(1) == IToken.tRBRACE)
{
try
{
astFactory.addEnumerator(
enumeration,
enumeratorIdentifier.getImage(),
enumeratorIdentifier.getOffset(),
enumeratorIdentifier.getOffset(),
enumeratorIdentifier.getEndOffset(), enumeratorIdentifier.getEndOffset(), initialValue);
}
catch (ASTSemanticException e1)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
}
if (LT(1) != IToken.tCOMMA)
{
throw backtrack;
}
try
{
astFactory.addEnumerator(
enumeration,
enumeratorIdentifier.getImage(),
enumeratorIdentifier.getOffset(),
enumeratorIdentifier.getOffset(),
enumeratorIdentifier.getEndOffset(), enumeratorIdentifier.getEndOffset(), initialValue);
}
catch (ASTSemanticException e1)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
consume(IToken.tCOMMA);
}
IToken t = consume(IToken.tRBRACE);
enumeration.setEndingOffset(t.getEndOffset());
enumeration.acceptElement( requestor );
sdw.setTypeSpecifier(enumeration);
}
else
{
// enumSpecifierAbort
backup(mark);
throw backtrack;
}
}
/**
* Parse a class/struct/union definition.
*
* classSpecifier
* : classKey name (baseClause)? "{" (memberSpecification)* "}"
*
* @param owner IParserCallback object that represents the declaration that owns this classSpecifier
* @throws BacktrackException request a backtrack
*/
protected void classSpecifier(DeclarationWrapper sdw)
throws BacktrackException, EndOfFileException
{
ClassNameType nameType = ClassNameType.IDENTIFIER;
ASTClassKind classKind = null;
ASTAccessVisibility access = ASTAccessVisibility.PUBLIC;
IToken classKey = null;
IToken mark = mark();
// class key
switch (LT(1))
{
case IToken.t_class :
classKey = consume();
classKind = ASTClassKind.CLASS;
access = ASTAccessVisibility.PRIVATE;
break;
case IToken.t_struct :
classKey = consume();
classKind = ASTClassKind.STRUCT;
break;
case IToken.t_union :
classKey = consume();
classKind = ASTClassKind.UNION;
break;
default :
throw backtrack;
}
ITokenDuple duple = null;
setCompletionKind( CompletionKind.USER_SPECIFIED_NAME );
setCompletionKeywords( Key.EMPTY );
// class name
if (LT(1) == IToken.tIDENTIFIER)
duple = className();
if (duple != null && !duple.isIdentifier())
nameType = ClassNameType.TEMPLATE;
if (LT(1) != IToken.tCOLON && LT(1) != IToken.tLBRACE)
{
backup(mark);
throw backtrack;
}
IASTClassSpecifier astClassSpecifier = null;
try
{
astClassSpecifier =
astFactory
.createClassSpecifier(
sdw.getScope(),
duple,
classKind,
nameType,
access,
classKey.getOffset(),
duple == null ? classKey.getOffset() : duple.getFirstToken().getOffset(),
duple == null ? classKey.getEndOffset() : duple.getFirstToken().getEndOffset() );
}
catch (ASTSemanticException e)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
sdw.setTypeSpecifier(astClassSpecifier);
// base clause
if (LT(1) == IToken.tCOLON)
{
baseSpecifier(astClassSpecifier);
}
if (LT(1) == IToken.tLBRACE)
{
consume(IToken.tLBRACE);
astClassSpecifier.enterScope( requestor );
memberDeclarationLoop : while (LT(1) != IToken.tRBRACE)
{
IToken checkToken = LA(1);
switch (LT(1))
{
case IToken.t_public :
consume();
consume(IToken.tCOLON);
astClassSpecifier.setCurrentVisibility( ASTAccessVisibility.PUBLIC );
break;
case IToken.t_protected :
consume();
consume(IToken.tCOLON);
astClassSpecifier.setCurrentVisibility( ASTAccessVisibility.PROTECTED);
break;
case IToken.t_private :
consume();
consume(IToken.tCOLON);
astClassSpecifier.setCurrentVisibility( ASTAccessVisibility.PRIVATE);
break;
case IToken.tRBRACE :
consume(IToken.tRBRACE);
break memberDeclarationLoop;
default :
try
{
declaration(astClassSpecifier, null);
}
catch (BacktrackException bt)
{
failParse();
if (checkToken == LA(1))
errorHandling();
}
}
if (checkToken == LA(1))
errorHandling();
}
// consume the }
IToken lt = consume(IToken.tRBRACE);
astClassSpecifier.setEndingOffset(lt.getEndOffset());
try
{
astFactory.signalEndOfClassSpecifier( astClassSpecifier );
}
catch (Exception e1)
{
throw backtrack;
}
astClassSpecifier.exitScope( requestor );
}
}
/**
* Parse the subclass-baseclauses for a class specification.
*
* baseclause: : basespecifierlist
* basespecifierlist: basespecifier
* basespecifierlist, basespecifier
* basespecifier: ::? nestednamespecifier? classname
* virtual accessspecifier? ::? nestednamespecifier? classname
* accessspecifier virtual? ::? nestednamespecifier? classname
* accessspecifier: private | protected | public
* @param classSpecOwner
* @throws BacktrackException
*/
protected void baseSpecifier(
IASTClassSpecifier astClassSpec)
throws EndOfFileException, BacktrackException
{
consume(IToken.tCOLON);
boolean isVirtual = false;
ASTAccessVisibility visibility = ASTAccessVisibility.PUBLIC;
ITokenDuple nameDuple = null;
baseSpecifierLoop : for (;;)
{
switch (LT(1))
{
case IToken.t_virtual :
consume(IToken.t_virtual);
isVirtual = true;
break;
case IToken.t_public :
consume();
break;
case IToken.t_protected :
consume();
visibility = ASTAccessVisibility.PROTECTED;
break;
case IToken.t_private :
visibility = ASTAccessVisibility.PRIVATE;
consume();
break;
case IToken.tCOLONCOLON :
case IToken.tIDENTIFIER :
nameDuple = name();
break;
case IToken.tCOMMA :
try
{
astFactory.addBaseSpecifier(
astClassSpec,
isVirtual,
visibility,
nameDuple );
}
catch (ASTSemanticException e)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
isVirtual = false;
visibility = ASTAccessVisibility.PUBLIC;
nameDuple = null;
consume();
continue baseSpecifierLoop;
default :
break baseSpecifierLoop;
}
}
try
{
astFactory.addBaseSpecifier(
astClassSpec,
isVirtual,
visibility,
nameDuple );
}
catch (ASTSemanticException e)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
/**
* Parses a function body.
*
* @throws BacktrackException request a backtrack
*/
protected void functionBody( IASTScope scope ) throws EndOfFileException, BacktrackException
{
compoundStatement( scope, false );
}
/**
* Parses a statement.
*
* @throws BacktrackException request a backtrack
*/
protected void statement(IASTScope scope) throws EndOfFileException, BacktrackException
{
setCurrentScope(scope);
setCompletionKind( CompletionKind.STATEMENT_START );
setCompletionKeywords( Key.STATEMENT );
switch (LT(1))
{
case IToken.t_case :
consume(IToken.t_case);
IASTExpression constant_expression = constantExpression(scope);
constant_expression.acceptElement(requestor);
consume(IToken.tCOLON);
statement(scope);
return;
case IToken.t_default :
consume(IToken.t_default);
consume(IToken.tCOLON);
statement(scope);
return;
case IToken.tLBRACE :
compoundStatement(scope, true);
return;
case IToken.t_if :
consume( IToken.t_if );
consume(IToken.tLPAREN);
condition( scope );
consume(IToken.tRPAREN);
if( LT(1) != IToken.tLBRACE )
singleStatementScope(scope);
else
statement( scope );
if (LT(1) == IToken.t_else)
{
consume( IToken.t_else );
if( LT(1) != IToken.tLBRACE )
singleStatementScope(scope);
else
statement( scope );
}
return;
case IToken.t_switch :
consume();
consume(IToken.tLPAREN);
condition(scope);
consume(IToken.tRPAREN);
statement(scope);
return;
case IToken.t_while :
consume(IToken.t_while);
consume(IToken.tLPAREN);
condition(scope);
consume(IToken.tRPAREN);
if( LT(1) != IToken.tLBRACE )
singleStatementScope(scope);
else
statement(scope);
return;
case IToken.t_do :
consume(IToken.t_do);
if( LT(1) != IToken.tLBRACE )
singleStatementScope(scope);
else
statement(scope);
consume(IToken.t_while);
consume(IToken.tLPAREN);
condition(scope);
consume(IToken.tRPAREN);
return;
case IToken.t_for :
consume();
consume(IToken.tLPAREN);
forInitStatement(scope);
if (LT(1) != IToken.tSEMI)
condition(scope);
consume(IToken.tSEMI);
if (LT(1) != IToken.tRPAREN)
{
IASTExpression finalExpression = expression(scope);
finalExpression.acceptElement(requestor);
}
consume(IToken.tRPAREN);
statement(scope);
return;
case IToken.t_break :
consume();
consume(IToken.tSEMI);
return;
case IToken.t_continue :
consume();
consume(IToken.tSEMI);
return;
case IToken.t_return :
consume();
if (LT(1) != IToken.tSEMI)
{
IASTExpression retVal = expression(scope);
retVal.acceptElement(requestor);
}
consume(IToken.tSEMI);
return;
case IToken.t_goto :
consume();
consume(IToken.tIDENTIFIER);
consume(IToken.tSEMI);
return;
case IToken.t_try :
consume();
compoundStatement(scope,true);
catchHandlerSequence(scope);
return;
case IToken.tSEMI :
consume();
return;
default :
// can be many things:
// label
try
{
if (LT(1) == IToken.tIDENTIFIER && LT(2) == IToken.tCOLON)
{
consume(IToken.tIDENTIFIER);
consume(IToken.tCOLON);
statement(scope);
return;
}
}catch( OffsetLimitReachedException olre )
{
// ok
}
// expressionStatement
// Note: the function style cast ambiguity is handled in expression
// Since it only happens when we are in a statement
IToken mark = mark();
try
{
IASTExpression thisExpression = expression(scope);
if( queryLookaheadCapability() )
consume(IToken.tSEMI);
else
throw new EndOfFileException();
thisExpression.acceptElement( requestor );
return;
}
catch (BacktrackException b)
{
backup( mark );
}
catch( OffsetLimitReachedException olre )
{
backup(mark);
}
// declarationStatement
declaration(scope, null);
}
}
protected void catchHandlerSequence(IASTScope scope)
throws EndOfFileException, BacktrackException
{
if( LT(1) != IToken.t_catch )
throw backtrack; // error, need at least one of these
while (LT(1) == IToken.t_catch)
{
consume(IToken.t_catch);
consume(IToken.tLPAREN);
if( LT(1) == IToken.tELLIPSIS )
consume( IToken.tELLIPSIS );
else
declaration(scope, null); // was exceptionDeclaration
consume(IToken.tRPAREN);
catchBlockCompoundStatement(scope);
}
}
protected abstract void catchBlockCompoundStatement(IASTScope scope) throws BacktrackException, EndOfFileException;
protected void singleStatementScope(IASTScope scope) throws EndOfFileException, BacktrackException
{
IASTCodeScope newScope;
try
{
newScope = astFactory.createNewCodeBlock(scope);
}
catch (Exception e)
{
throw backtrack;
}
newScope.enterScope( requestor );
try
{
statement( newScope );
}
finally
{
newScope.exitScope( requestor );
}
}
/**
* @throws BacktrackException
*/
protected void condition( IASTScope scope ) throws BacktrackException, EndOfFileException
{
IASTExpression someExpression = expression( scope );
someExpression.acceptElement(requestor);
//TODO type-specifier-seq declarator = assignment expression
}
/**
* @throws BacktrackException
*/
protected void forInitStatement( IASTScope scope ) throws BacktrackException, EndOfFileException
{
try
{
simpleDeclarationStrategyUnion(scope,null);
}
catch( BacktrackException bt )
{
try
{
IASTExpression e = expression( scope );
e.acceptElement(requestor);
}
catch( BacktrackException b )
{
failParse();
throw b;
}
}
}
/**
* @throws BacktrackException
*/
protected void compoundStatement( IASTScope scope, boolean createNewScope ) throws EndOfFileException, BacktrackException
{
consume(IToken.tLBRACE);
IASTCodeScope newScope = null;
if( createNewScope )
{
try
{
newScope = astFactory.createNewCodeBlock(scope);
}
catch (Exception e)
{
throw backtrack;
}
newScope.enterScope( requestor );
}
IToken checkToken = null;
setCurrentScope(createNewScope ? newScope : scope);
setCompletionKind( CompletionKind.STATEMENT_START );
while (queryLookaheadCapability() && LT(1) != IToken.tRBRACE)
{
checkToken = LA(1);
setCurrentScope(createNewScope ? newScope : scope);
try
{
statement(createNewScope ? newScope : scope );
}
catch( BacktrackException b )
{
failParse();
if( LA(1) == checkToken )
errorHandling();
}
setCurrentScope(createNewScope ? newScope : scope);
setCompletionKind( CompletionKind.STATEMENT_START );
setCompletionKeywords( Key.STATEMENT );
}
if( queryLookaheadCapability() ) consume(IToken.tRBRACE);
else throw new EndOfFileException();
if( createNewScope )
newScope.exitScope( requestor );
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression constantExpression( IASTScope scope )
throws BacktrackException, EndOfFileException
{
return conditionalExpression(scope);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.parser.IParser#expression(java.lang.Object)
*/
public IASTExpression expression(IASTScope scope) throws BacktrackException, EndOfFileException
{
IASTExpression assignmentExpression = assignmentExpression(scope);
if( !queryLookaheadCapability() ) return assignmentExpression;
while (LT(1) == IToken.tCOMMA)
{
consume();
IASTExpression secondExpression = assignmentExpression(scope);
try
{
assignmentExpression =
astFactory.createExpression(
scope,
IASTExpression.Kind.EXPRESSIONLIST,
assignmentExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
return assignmentExpression;
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression assignmentExpression(IASTScope scope)
throws EndOfFileException, BacktrackException {
if (LT(1) == IToken.t_throw) {
return throwExpression(scope);
}
IASTExpression conditionalExpression = conditionalExpression(scope);
// if the condition not taken, try assignment operators
if (conditionalExpression != null
&& conditionalExpression.getExpressionKind()
== IASTExpression.Kind.CONDITIONALEXPRESSION)
return conditionalExpression;
if( !queryLookaheadCapability() ) return conditionalExpression;
switch (LT(1)) {
case IToken.tASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_NORMAL,
conditionalExpression);
case IToken.tSTARASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_MULT,
conditionalExpression);
case IToken.tDIVASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_DIV,
conditionalExpression);
case IToken.tMODASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_MOD,
conditionalExpression);
case IToken.tPLUSASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_PLUS,
conditionalExpression);
case IToken.tMINUSASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_MINUS,
conditionalExpression);
case IToken.tSHIFTRASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_RSHIFT,
conditionalExpression);
case IToken.tSHIFTLASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_LSHIFT,
conditionalExpression);
case IToken.tAMPERASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_AND,
conditionalExpression);
case IToken.tXORASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_XOR,
conditionalExpression);
case IToken.tBITORASSIGN :
return assignmentOperatorExpression(
scope,
IASTExpression.Kind.ASSIGNMENTEXPRESSION_OR,
conditionalExpression);
}
return conditionalExpression;
}
protected IASTExpression assignmentOperatorExpression(
IASTScope scope,
IASTExpression.Kind kind, IASTExpression lhs )
throws EndOfFileException, BacktrackException
{
consume();
IASTExpression assignmentExpression = assignmentExpression(scope);
try
{
return astFactory.createExpression(
scope,
kind,
lhs,
assignmentExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression throwExpression( IASTScope scope )
throws EndOfFileException, BacktrackException
{
consume(IToken.t_throw);
IASTExpression throwExpression = null;
try
{
throwExpression = expression(scope);
}
catch (BacktrackException b)
{
}
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.THROWEXPRESSION,
throwExpression,
null,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
/**
* @param expression
* @return
* @throws BacktrackException
*/
protected IASTExpression conditionalExpression( IASTScope scope )
throws BacktrackException, EndOfFileException
{
IASTExpression firstExpression = logicalOrExpression(scope);
if( !queryLookaheadCapability() ) return firstExpression;
if (LT(1) == IToken.tQUESTION)
{
consume();
IASTExpression secondExpression = expression(scope);
consume(IToken.tCOLON);
IASTExpression thirdExpression = assignmentExpression(scope);
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.CONDITIONALEXPRESSION,
firstExpression,
secondExpression,
thirdExpression,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
else
return firstExpression;
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression logicalOrExpression(IASTScope scope)
throws BacktrackException, EndOfFileException
{
IASTExpression firstExpression = logicalAndExpression(scope);
if( !queryLookaheadCapability() ) return firstExpression;
while (LT(1) == IToken.tOR)
{
consume();
IASTExpression secondExpression = logicalAndExpression(scope);
try
{
firstExpression =
astFactory.createExpression(
scope,
IASTExpression.Kind.LOGICALOREXPRESSION,
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
return firstExpression;
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression logicalAndExpression( IASTScope scope )
throws BacktrackException, EndOfFileException
{
IASTExpression firstExpression = inclusiveOrExpression( scope );
if( !queryLookaheadCapability() ) return firstExpression;
while (LT(1) == IToken.tAND)
{
consume();
IASTExpression secondExpression = inclusiveOrExpression( scope );
try
{
firstExpression =
astFactory.createExpression(
scope,
IASTExpression.Kind.LOGICALANDEXPRESSION,
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
return firstExpression;
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression inclusiveOrExpression( IASTScope scope )
throws BacktrackException, EndOfFileException
{
IASTExpression firstExpression = exclusiveOrExpression(scope);
if( !queryLookaheadCapability() ) return firstExpression;
while (LT(1) == IToken.tBITOR)
{
consume();
IASTExpression secondExpression = exclusiveOrExpression(scope);
try
{
firstExpression =
astFactory.createExpression(
scope,
IASTExpression.Kind.INCLUSIVEOREXPRESSION,
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
return firstExpression;
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression exclusiveOrExpression( IASTScope scope )
throws BacktrackException, EndOfFileException
{
IASTExpression firstExpression = andExpression( scope );
if( !queryLookaheadCapability() ) return firstExpression;
while (LT(1) == IToken.tXOR)
{
consume();
IASTExpression secondExpression = andExpression( scope );
try
{
firstExpression =
astFactory.createExpression(
scope,
IASTExpression.Kind.EXCLUSIVEOREXPRESSION,
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
return firstExpression;
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression andExpression(IASTScope scope) throws EndOfFileException, BacktrackException
{
IASTExpression firstExpression = equalityExpression(scope);
if( !queryLookaheadCapability() ) return firstExpression;
while (LT(1) == IToken.tAMPER)
{
consume();
IASTExpression secondExpression = equalityExpression(scope);
try
{
firstExpression =
astFactory.createExpression(
scope,
IASTExpression.Kind.ANDEXPRESSION,
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
return firstExpression;
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression equalityExpression( IASTScope scope )
throws EndOfFileException, BacktrackException
{
IASTExpression firstExpression = relationalExpression(scope);
for (;;)
{
if( !queryLookaheadCapability() ) return firstExpression;
switch (LT(1))
{
case IToken.tEQUAL :
case IToken.tNOTEQUAL :
IToken t = consume();
IASTExpression secondExpression =
relationalExpression(scope);
try
{
firstExpression =
astFactory.createExpression(
scope,
(t.getType() == IToken.tEQUAL)
? IASTExpression.Kind.EQUALITY_EQUALS
: IASTExpression.Kind.EQUALITY_NOTEQUALS,
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
default :
return firstExpression;
}
}
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression relationalExpression(IASTScope scope)
throws BacktrackException, EndOfFileException
{
IASTExpression firstExpression = shiftExpression(scope);
for (;;)
{
if( !queryLookaheadCapability() ) return firstExpression;
switch (LT(1))
{
case IToken.tGT :
case IToken.tLT :
case IToken.tLTEQUAL :
case IToken.tGTEQUAL :
IToken mark = mark();
IToken t = consume();
IToken next = LA(1);
IASTExpression secondExpression =
shiftExpression(scope);
if (next == LA(1))
{
// we did not consume anything
// this is most likely an error
backup(mark);
return firstExpression;
}
else
{
IASTExpression.Kind kind = null;
switch (t.getType())
{
case IToken.tGT :
kind =
IASTExpression.Kind.RELATIONAL_GREATERTHAN;
break;
case IToken.tLT :
kind = IASTExpression.Kind.RELATIONAL_LESSTHAN;
break;
case IToken.tLTEQUAL :
kind =
IASTExpression
.Kind
.RELATIONAL_LESSTHANEQUALTO;
break;
case IToken.tGTEQUAL :
kind =
IASTExpression
.Kind
.RELATIONAL_GREATERTHANEQUALTO;
break;
}
try
{
firstExpression =
astFactory.createExpression(
scope,
kind,
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
break;
default :
return firstExpression;
}
}
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression shiftExpression(IASTScope scope)
throws BacktrackException, EndOfFileException
{
IASTExpression firstExpression = additiveExpression(scope);
for (;;)
{
if( !queryLookaheadCapability() ) return firstExpression;
switch (LT(1))
{
case IToken.tSHIFTL :
case IToken.tSHIFTR :
IToken t = consume();
IASTExpression secondExpression =
additiveExpression(scope);
try
{
firstExpression =
astFactory.createExpression(
scope,
((t.getType() == IToken.tSHIFTL)
? IASTExpression.Kind.SHIFT_LEFT
: IASTExpression.Kind.SHIFT_RIGHT),
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
default :
return firstExpression;
}
}
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression additiveExpression( IASTScope scope )
throws BacktrackException, EndOfFileException
{
IASTExpression firstExpression = multiplicativeExpression( scope );
for (;;)
{
if( !queryLookaheadCapability() ) return firstExpression;
switch (LT(1))
{
case IToken.tPLUS :
case IToken.tMINUS :
IToken t = consume();
IASTExpression secondExpression =
multiplicativeExpression(scope);
try
{
firstExpression =
astFactory.createExpression(
scope,
((t.getType() == IToken.tPLUS)
? IASTExpression.Kind.ADDITIVE_PLUS
: IASTExpression.Kind.ADDITIVE_MINUS),
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
default :
return firstExpression;
}
}
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression multiplicativeExpression( IASTScope scope )
throws BacktrackException, EndOfFileException
{
IASTExpression firstExpression = pmExpression(scope);
for (;;)
{
if( !queryLookaheadCapability() ) return firstExpression;
switch (LT(1))
{
case IToken.tSTAR :
case IToken.tDIV :
case IToken.tMOD :
IToken t = consume();
IASTExpression secondExpression = pmExpression(scope);
IASTExpression.Kind kind = null;
switch (t.getType())
{
case IToken.tSTAR :
kind = IASTExpression.Kind.MULTIPLICATIVE_MULTIPLY;
break;
case IToken.tDIV :
kind = IASTExpression.Kind.MULTIPLICATIVE_DIVIDE;
break;
case IToken.tMOD :
kind = IASTExpression.Kind.MULTIPLICATIVE_MODULUS;
break;
}
try
{
firstExpression =
astFactory.createExpression(
scope,
kind,
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
default :
return firstExpression;
}
}
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression pmExpression( IASTScope scope ) throws EndOfFileException, BacktrackException
{
IASTExpression firstExpression = castExpression(scope);
for (;;)
{
if( ! queryLookaheadCapability() ) return firstExpression;
switch (LT(1))
{
case IToken.tDOTSTAR :
case IToken.tARROWSTAR :
IToken t = consume();
IASTExpression secondExpression =
castExpression(scope);
try
{
firstExpression =
astFactory.createExpression(
scope,
((t.getType() == IToken.tDOTSTAR)
? IASTExpression.Kind.PM_DOTSTAR
: IASTExpression.Kind.PM_ARROWSTAR),
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
default :
return firstExpression;
}
}
}
/**
* castExpression
* : unaryExpression
* | "(" typeId ")" castExpression
*/
protected IASTExpression castExpression( IASTScope scope ) throws EndOfFileException, BacktrackException
{
// TO DO: we need proper symbol checkint to ensure type name
if( ! queryLookaheadCapability() ) return unaryExpression(scope);
if (LT(1) == IToken.tLPAREN)
{
IToken mark = mark();
consume();
IASTTypeId typeId = null;
// If this isn't a type name, then we shouldn't be here
try
{
typeId = typeId(scope, false);
consume(IToken.tRPAREN);
IASTExpression castExpression = castExpression(scope);
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.CASTEXPRESSION,
castExpression,
null,
null,
typeId,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
catch (BacktrackException b)
{
backup(mark);
}
}
return unaryExpression(scope);
}
/**
* @throws BacktrackException
*/
protected IASTTypeId typeId(IASTScope scope, boolean skipArrayModifiers ) throws EndOfFileException, BacktrackException
{
IToken mark = mark();
ITokenDuple name = null;
boolean isConst = false, isVolatile = false;
boolean isSigned = false, isUnsigned = false;
boolean isShort = false, isLong = false;
boolean isTypename = false;
IASTSimpleTypeSpecifier.Type kind = null;
do
{
try
{
name = name();
kind = IASTSimpleTypeSpecifier.Type.CLASS_OR_TYPENAME;
break;
}
catch (BacktrackException b)
{
// do nothing
}
boolean encounteredType = false;
simpleMods : for (;;)
{
switch (LT(1))
{
case IToken.t_signed :
consume();
isSigned = true;
break;
case IToken.t_unsigned :
consume();
isUnsigned = true;
break;
case IToken.t_short :
consume();
isShort = true;
break;
case IToken.t_long :
consume();
isLong = true;
break;
case IToken.t_const :
consume();
isConst = true;
break;
case IToken.t_volatile :
consume();
isVolatile = true;
break;
case IToken.tIDENTIFIER :
if( encounteredType ) break simpleMods;
encounteredType = true;
name = name();
kind = IASTSimpleTypeSpecifier.Type.CLASS_OR_TYPENAME;
break;
case IToken.t_int :
if( encounteredType ) break simpleMods;
encounteredType = true;
kind = IASTSimpleTypeSpecifier.Type.INT;
consume();
break;
case IToken.t_char :
if( encounteredType ) break simpleMods;
encounteredType = true;
kind = IASTSimpleTypeSpecifier.Type.CHAR;
consume();
break;
case IToken.t_bool :
if( encounteredType ) break simpleMods;
encounteredType = true;
kind = IASTSimpleTypeSpecifier.Type.BOOL;
consume();
break;
case IToken.t_double :
if( encounteredType ) break simpleMods;
encounteredType = true;
kind = IASTSimpleTypeSpecifier.Type.DOUBLE;
consume();
break;
case IToken.t_float :
if( encounteredType ) break simpleMods;
encounteredType = true;
kind = IASTSimpleTypeSpecifier.Type.FLOAT;
consume();
break;
case IToken.t_wchar_t :
if( encounteredType ) break simpleMods;
encounteredType = true;
kind = IASTSimpleTypeSpecifier.Type.WCHAR_T;
consume();
break;
case IToken.t_void :
if( encounteredType ) break simpleMods;
encounteredType = true;
kind = IASTSimpleTypeSpecifier.Type.VOID;
consume();
break;
default :
break simpleMods;
}
}
if( kind != null ) break;
if( isShort || isLong || isUnsigned || isSigned )
{
kind = IASTSimpleTypeSpecifier.Type.INT;
break;
}
if (
LT(1) == IToken.t_typename
|| LT(1) == IToken.t_struct
|| LT(1) == IToken.t_class
|| LT(1) == IToken.t_enum
|| LT(1) == IToken.t_union)
{
consume();
try
{
name = name();
kind = IASTSimpleTypeSpecifier.Type.CLASS_OR_TYPENAME;
} catch( BacktrackException b )
{
backup( mark );
throw backtrack;
}
}
} while( false );
if( kind == null )
throw backtrack;
TypeId id = new TypeId();
IToken last = lastToken;
lastToken = consumeTemplateParameters( last );
if( lastToken == null ) lastToken = last;
consumePointerOperators( id );
if( lastToken == null ) lastToken = last;
if( ! skipArrayModifiers )
{
last = lastToken;
consumeArrayModifiers( id, scope );
if( lastToken == null ) lastToken = last;
}
try
{
return astFactory.createTypeId( scope, kind, isConst, isVolatile, isShort, isLong, isSigned, isUnsigned, isTypename, name, id.getPointerOperators(), id.getArrayModifiers());
}
catch (ASTSemanticException e)
{
backup( mark );
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression deleteExpression( IASTScope scope )
throws EndOfFileException, BacktrackException
{
if (LT(1) == IToken.tCOLONCOLON)
{
// global scope
consume();
}
consume(IToken.t_delete);
boolean vectored = false;
if (LT(1) == IToken.tLBRACKET)
{
// array delete
consume();
consume(IToken.tRBRACKET);
vectored = true;
}
IASTExpression castExpression = castExpression(scope);
try
{
return astFactory.createExpression(
scope,
(vectored
? IASTExpression.Kind.DELETE_VECTORCASTEXPRESSION
: IASTExpression.Kind.DELETE_CASTEXPRESSION),
castExpression,
null,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
/**
* Pazse a new-expression.
*
* @param expression
* @throws BacktrackException
*
*
* newexpression: ::? new newplacement? newtypeid newinitializer?
* ::? new newplacement? ( typeid ) newinitializer?
* newplacement: ( expressionlist )
* newtypeid: typespecifierseq newdeclarator?
* newdeclarator: ptroperator newdeclarator? | directnewdeclarator
* directnewdeclarator: [ expression ]
* directnewdeclarator [ constantexpression ]
* newinitializer: ( expressionlist? )
*/
protected IASTExpression newExpression( IASTScope scope ) throws BacktrackException, EndOfFileException
{
if (LT(1) == IToken.tCOLONCOLON)
{
// global scope
consume();
}
consume(IToken.t_new);
boolean typeIdInParen = false;
boolean placementParseFailure = true;
IToken beforeSecondParen = null;
IToken backtrackMarker = null;
IASTTypeId typeId = null;
ArrayList newPlacementExpressions = new ArrayList();
ArrayList newTypeIdExpressions = new ArrayList();
ArrayList newInitializerExpressions = new ArrayList();
if (LT(1) == IToken.tLPAREN)
{
consume(IToken.tLPAREN);
try
{
// Try to consume placement list
// Note: since expressionList and expression are the same...
backtrackMarker = mark();
newPlacementExpressions.add(expression(scope));
consume(IToken.tRPAREN);
placementParseFailure = false;
if (LT(1) == IToken.tLPAREN)
{
beforeSecondParen = mark();
consume(IToken.tLPAREN);
typeIdInParen = true;
}
}
catch (BacktrackException e)
{
backup(backtrackMarker);
}
if (placementParseFailure)
{
// CASE: new (typeid-not-looking-as-placement) ...
// the first expression in () is not a placement
// - then it has to be typeId
typeId = typeId(scope, true );
consume(IToken.tRPAREN);
}
else
{
if (!typeIdInParen)
{
if (LT(1) == IToken.tLBRACKET)
{
// CASE: new (typeid-looking-as-placement) [expr]...
// the first expression in () has been parsed as a placement;
// however, we assume that it was in fact typeId, and this
// new statement creates an array.
// Do nothing, fallback to array/initializer processing
}
else
{
// CASE: new (placement) typeid ...
// the first expression in () is parsed as a placement,
// and the next expression doesn't start with '(' or '['
// - then it has to be typeId
try
{
backtrackMarker = mark();
typeId = typeId(scope, true);
}
catch (BacktrackException e)
{
// Hmmm, so it wasn't typeId after all... Then it is
// CASE: new (typeid-looking-as-placement)
backup(backtrackMarker);
// TODO fix this
return null;
}
}
}
else
{
// Tricky cases: first expression in () is parsed as a placement,
// and the next expression starts with '('.
// The problem is, the first expression might as well be a typeid
try
{
typeId = typeId(scope, true);
consume(IToken.tRPAREN);
if (LT(1) == IToken.tLPAREN
|| LT(1) == IToken.tLBRACKET)
{
// CASE: new (placement)(typeid)(initializer)
// CASE: new (placement)(typeid)[] ...
// Great, so far all our assumptions have been correct
// Do nothing, fallback to array/initializer processing
}
else
{
// CASE: new (placement)(typeid)
// CASE: new (typeid-looking-as-placement)(initializer-looking-as-typeid)
// Worst-case scenario - this cannot be resolved w/o more semantic information.
// Luckily, we don't need to know what was that - we only know that
// new-expression ends here.
try
{
return astFactory.createExpression(
scope, IASTExpression.Kind.NEW_TYPEID,
null, null, null, typeId, null,
"", astFactory.createNewDescriptor(newPlacementExpressions, newTypeIdExpressions, newInitializerExpressions));
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
}
catch (BacktrackException e)
{
// CASE: new (typeid-looking-as-placement)(initializer-not-looking-as-typeid)
// Fallback to initializer processing
backup(beforeSecondParen);
}
}
}
}
else
{
// CASE: new typeid ...
// new parameters do not start with '('
// i.e it has to be a plain typeId
typeId = typeId(scope, true);
}
while (LT(1) == IToken.tLBRACKET)
{
// array new
consume();
newTypeIdExpressions.add(assignmentExpression(scope));
consume(IToken.tRBRACKET);
}
// newinitializer
if (LT(1) == IToken.tLPAREN)
{
consume(IToken.tLPAREN);
if (LT(1) != IToken.tRPAREN)
newInitializerExpressions.add(expression(scope));
consume(IToken.tRPAREN);
}
try
{
return astFactory.createExpression(
scope, IASTExpression.Kind.NEW_TYPEID,
null, null, null, typeId, null,
"", astFactory.createNewDescriptor(newPlacementExpressions, newTypeIdExpressions, newInitializerExpressions));
}
catch (ASTSemanticException e)
{
return null;
} catch (Exception e)
{
throw backtrack;
}
}
protected IASTExpression unaryOperatorCastExpression( IASTScope scope,
IASTExpression.Kind kind)
throws EndOfFileException, BacktrackException
{
IASTExpression castExpression = castExpression(scope);
try
{
return astFactory.createExpression(
scope,
kind,
castExpression,
null,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression unaryExpression( IASTScope scope )
throws EndOfFileException, BacktrackException
{
if( ! queryLookaheadCapability() ) return postfixExpression( scope );
switch (LT(1))
{
case IToken.tSTAR :
consume();
return unaryOperatorCastExpression(scope,
IASTExpression.Kind.UNARY_STAR_CASTEXPRESSION);
case IToken.tAMPER :
consume();
return unaryOperatorCastExpression(scope,
IASTExpression.Kind.UNARY_AMPSND_CASTEXPRESSION);
case IToken.tPLUS :
consume();
return unaryOperatorCastExpression(scope,
IASTExpression.Kind.UNARY_PLUS_CASTEXPRESSION);
case IToken.tMINUS :
consume();
return unaryOperatorCastExpression(scope,
IASTExpression.Kind.UNARY_MINUS_CASTEXPRESSION);
case IToken.tNOT :
consume();
return unaryOperatorCastExpression(scope,
IASTExpression.Kind.UNARY_NOT_CASTEXPRESSION);
case IToken.tCOMPL :
consume();
return unaryOperatorCastExpression(scope,
IASTExpression.Kind.UNARY_TILDE_CASTEXPRESSION);
case IToken.tINCR :
consume();
return unaryOperatorCastExpression(scope,
IASTExpression.Kind.UNARY_INCREMENT);
case IToken.tDECR :
consume();
return unaryOperatorCastExpression(scope,
IASTExpression.Kind.UNARY_DECREMENT);
case IToken.t_sizeof :
consume(IToken.t_sizeof);
IToken mark = LA(1);
IASTTypeId d = null;
IASTExpression unaryExpression = null;
if (LT(1) == IToken.tLPAREN)
{
try
{
consume(IToken.tLPAREN);
d = typeId(scope, false);
consume(IToken.tRPAREN);
}
catch (BacktrackException bt)
{
backup(mark);
unaryExpression = unaryExpression(scope);
}
}
else
{
unaryExpression = unaryExpression(scope);
}
if (d != null & unaryExpression == null)
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.UNARY_SIZEOF_TYPEID,
null,
null,
null,
d,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
else if (unaryExpression != null && d == null)
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.UNARY_SIZEOF_UNARYEXPRESSION,
unaryExpression,
null,
null,
null,
null, "", null);
}
catch (ASTSemanticException e1)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
else
throw backtrack;
case IToken.t_new :
return newExpression(scope);
case IToken.t_delete :
return deleteExpression(scope);
case IToken.tCOLONCOLON :
switch (LT(2))
{
case IToken.t_new :
return newExpression(scope);
case IToken.t_delete :
return deleteExpression(scope);
default :
return postfixExpression(scope);
}
default :
return postfixExpression(scope);
}
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression postfixExpression( IASTScope scope )
throws EndOfFileException, BacktrackException
{
IASTExpression firstExpression = null;
boolean isTemplate = false;
if( ! queryLookaheadCapability() ) return primaryExpression(scope);
switch (LT(1))
{
case IToken.t_typename :
consume(IToken.t_typename);
ITokenDuple nestedName = name();
boolean templateTokenConsumed = false;
if( LT(1) == IToken.t_template )
{
consume( IToken.t_template );
templateTokenConsumed = true;
}
IToken current = mark();
ITokenDuple templateId = null;
try
{
templateId = new TokenDuple( current, templateId() );
}
catch( BacktrackException bt )
{
if( templateTokenConsumed )
throw bt;
backup( current );
}
consume( IToken.tLPAREN );
IASTExpression expressionList = expression( scope );
consume( IToken.tRPAREN );
try {
firstExpression =
astFactory.createExpression( scope,
(( templateId != null )? IASTExpression.Kind.POSTFIX_TYPENAME_TEMPLATEID : IASTExpression.Kind.POSTFIX_TYPENAME_IDENTIFIER ),
expressionList,
null,
null,
null,
nestedName,
"",
null );
} catch (ASTSemanticException ase ) {
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
// simple-type-specifier ( assignment-expression , .. )
case IToken.t_char :
firstExpression =
simpleTypeConstructorExpression(scope,
IASTExpression.Kind.POSTFIX_SIMPLETYPE_CHAR);
break;
case IToken.t_wchar_t :
firstExpression =
simpleTypeConstructorExpression(scope,
IASTExpression.Kind.POSTFIX_SIMPLETYPE_WCHART);
break;
case IToken.t_bool :
firstExpression =
simpleTypeConstructorExpression(scope,
IASTExpression.Kind.POSTFIX_SIMPLETYPE_BOOL);
break;
case IToken.t_short :
firstExpression =
simpleTypeConstructorExpression(scope,
IASTExpression.Kind.POSTFIX_SIMPLETYPE_SHORT);
break;
case IToken.t_int :
firstExpression =
simpleTypeConstructorExpression(scope,
IASTExpression.Kind.POSTFIX_SIMPLETYPE_INT);
break;
case IToken.t_long :
firstExpression =
simpleTypeConstructorExpression(scope,
IASTExpression.Kind.POSTFIX_SIMPLETYPE_LONG);
break;
case IToken.t_signed :
firstExpression =
simpleTypeConstructorExpression(scope,
IASTExpression.Kind.POSTFIX_SIMPLETYPE_SIGNED);
break;
case IToken.t_unsigned :
firstExpression =
simpleTypeConstructorExpression(scope,
IASTExpression.Kind.POSTFIX_SIMPLETYPE_UNSIGNED);
break;
case IToken.t_float :
firstExpression =
simpleTypeConstructorExpression(scope,
IASTExpression.Kind.POSTFIX_SIMPLETYPE_FLOAT);
break;
case IToken.t_double :
firstExpression =
simpleTypeConstructorExpression( scope,
IASTExpression.Kind.POSTFIX_SIMPLETYPE_DOUBLE);
break;
case IToken.t_dynamic_cast :
firstExpression =
specialCastExpression(scope,
IASTExpression.Kind.POSTFIX_DYNAMIC_CAST);
break;
case IToken.t_static_cast :
firstExpression =
specialCastExpression(scope,
IASTExpression.Kind.POSTFIX_STATIC_CAST);
break;
case IToken.t_reinterpret_cast :
firstExpression =
specialCastExpression(scope,
IASTExpression.Kind.POSTFIX_REINTERPRET_CAST);
break;
case IToken.t_const_cast :
firstExpression =
specialCastExpression(scope,
IASTExpression.Kind.POSTFIX_CONST_CAST);
break;
case IToken.t_typeid :
consume();
consume(IToken.tLPAREN);
boolean isTypeId = true;
IASTExpression lhs = null;
IASTTypeId typeId = null;
try
{
typeId = typeId(scope, false);
}
catch (BacktrackException b)
{
isTypeId = false;
lhs = expression(scope);
}
consume(IToken.tRPAREN);
try
{
firstExpression =
astFactory.createExpression(
scope,
(isTypeId
? IASTExpression.Kind.POSTFIX_TYPEID_TYPEID
: IASTExpression.Kind.POSTFIX_TYPEID_EXPRESSION),
lhs,
null,
null,
typeId,
null, "", null);
}
catch (ASTSemanticException e6)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
default :
firstExpression = primaryExpression(scope);
}
IASTExpression secondExpression = null;
for (;;)
{
if( ! queryLookaheadCapability() )return firstExpression;
switch (LT(1))
{
case IToken.tLBRACKET :
// array access
consume();
secondExpression = expression(scope);
consume(IToken.tRBRACKET);
try
{
firstExpression =
astFactory.createExpression(
scope,
IASTExpression.Kind.POSTFIX_SUBSCRIPT,
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e2)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
case IToken.tLPAREN :
// function call
consume(IToken.tLPAREN);
secondExpression = expression(scope);
consume(IToken.tRPAREN);
try
{
firstExpression =
astFactory.createExpression(
scope,
IASTExpression.Kind.POSTFIX_FUNCTIONCALL,
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e3)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
case IToken.tINCR :
consume();
try
{
firstExpression =
astFactory.createExpression(
scope,
IASTExpression.Kind.POSTFIX_INCREMENT,
firstExpression,
null,
null,
null,
null, "", null);
}
catch (ASTSemanticException e1)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
case IToken.tDECR :
consume();
try
{
firstExpression =
astFactory.createExpression(
scope,
IASTExpression.Kind.POSTFIX_DECREMENT,
firstExpression,
null,
null,
null,
null, "", null);
}
catch (ASTSemanticException e4)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
break;
case IToken.tDOT :
// member access
consume(IToken.tDOT);
try
{
if (LT(1) == IToken.t_template)
{
consume(IToken.t_template);
isTemplate = true;
}
} catch( OffsetLimitReachedException olre )
{
setCompletionToken( null );
}
IASTNode context = astFactory.getCompletionContext( (isTemplate
? IASTExpression.Kind.POSTFIX_DOT_TEMPL_IDEXPRESS
: IASTExpression.Kind.POSTFIX_DOT_IDEXPRESSION),
firstExpression );
setCompletionContext( context );
setCompletionKind( IASTCompletionNode.CompletionKind.MEMBER_REFERENCE );
secondExpression = primaryExpression(scope);
try
{
firstExpression =
astFactory.createExpression(
scope,
(isTemplate
? IASTExpression.Kind.POSTFIX_DOT_TEMPL_IDEXPRESS
: IASTExpression.Kind.POSTFIX_DOT_IDEXPRESSION),
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e5)
{
failParse();
setCompletionContext( null );
throw backtrack;
} catch (Exception e)
{
setCompletionContext( null );
throw backtrack;
}
break;
case IToken.tARROW :
// member access
consume(IToken.tARROW);
try
{
if (LT(1) == IToken.t_template)
{
consume(IToken.t_template);
isTemplate = true;
}
} catch( OffsetLimitReachedException olre )
{
setCompletionToken( null );
}
context = astFactory.getCompletionContext( (isTemplate
? IASTExpression.Kind.POSTFIX_ARROW_TEMPL_IDEXP
: IASTExpression.Kind.POSTFIX_ARROW_IDEXPRESSION),
firstExpression );
setCompletionContext( context );
setCompletionKind( IASTCompletionNode.CompletionKind.MEMBER_REFERENCE );
secondExpression = primaryExpression(scope);
try
{
firstExpression =
astFactory.createExpression(
scope,
(isTemplate
? IASTExpression.Kind.POSTFIX_ARROW_TEMPL_IDEXP
: IASTExpression.Kind.POSTFIX_ARROW_IDEXPRESSION),
firstExpression,
secondExpression,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
failParse();
setCompletionContext( null );
throw backtrack;
} catch (Exception e)
{
setCompletionContext( null );
throw backtrack;
}
break;
default :
return firstExpression;
}
}
}
/**
* @return
* @throws EndOfFileException
*/
protected boolean queryLookaheadCapability() throws EndOfFileException {
//make sure we can look ahead one before doing this
boolean result = true;
try
{
LA(1);
}
catch( OffsetLimitReachedException olre )
{
result = false;
}
return result;
}
protected IASTExpression specialCastExpression( IASTScope scope,
IASTExpression.Kind kind)
throws EndOfFileException, BacktrackException
{
consume();
consume(IToken.tLT);
IASTTypeId duple = typeId(scope, false);
consume(IToken.tGT);
consume(IToken.tLPAREN);
IASTExpression lhs = expression(scope);
consume(IToken.tRPAREN);
try
{
return astFactory.createExpression(
scope,
kind,
lhs,
null,
null,
duple,
null, "", null);
}
catch (ASTSemanticException e)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
protected IASTExpression simpleTypeConstructorExpression( IASTScope scope,
Kind type)
throws EndOfFileException, BacktrackException
{
consume();
consume(IToken.tLPAREN);
IASTExpression inside = expression(scope);
consume(IToken.tRPAREN);
try
{
return astFactory.createExpression(
scope,
type,
inside,
null,
null,
null,
null, "", null);
}
catch (ASTSemanticException e)
{
failParse();
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
}
/**
* @param expression
* @throws BacktrackException
*/
protected IASTExpression primaryExpression( IASTScope scope )
throws EndOfFileException, BacktrackException
{
IToken t = null;
IASTExpression emptyExpression = null;
try {
emptyExpression = astFactory.createExpression(
scope,
IASTExpression.Kind.PRIMARY_EMPTY,
null,
null,
null,
null,
null, "", null);
} catch (ASTSemanticException e9) {
// TODO Auto-generated catch block
e9.printStackTrace();
}
if( !queryLookaheadCapability() ) return emptyExpression;
switch (LT(1))
{
// TO DO: we need more literals...
case IToken.tINTEGER :
t = consume();
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.PRIMARY_INTEGER_LITERAL,
null,
null,
null,
null,
null, t.getImage(), null);
}
catch (ASTSemanticException e1)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
case IToken.tFLOATINGPT :
t = consume();
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.PRIMARY_FLOAT_LITERAL,
null,
null,
null,
null,
null, t.getImage(), null);
}
catch (ASTSemanticException e2)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
case IToken.tSTRING :
case IToken.tLSTRING :
t = consume();
try
{
return astFactory.createExpression( scope, IASTExpression.Kind.PRIMARY_STRING_LITERAL, null, null, null, null, null, t.getImage(), null );
}
catch (ASTSemanticException e5)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
case IToken.t_false :
case IToken.t_true :
t = consume();
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.PRIMARY_BOOLEAN_LITERAL,
null,
null,
null,
null,
null, t.getImage(), null);
}
catch (ASTSemanticException e3)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
case IToken.tCHAR :
case IToken.tLCHAR :
t = consume();
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.PRIMARY_CHAR_LITERAL,
null,
null,
null,
null,
null, t.getImage(), null);
}
catch (ASTSemanticException e4)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
case IToken.t_this :
consume(IToken.t_this);
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.PRIMARY_THIS,
null,
null,
null,
null,
null, "", null);
}
catch (ASTSemanticException e7)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
case IToken.tLPAREN :
consume();
IASTExpression lhs = expression(scope);
consume(IToken.tRPAREN);
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.PRIMARY_BRACKETED_EXPRESSION,
lhs,
null,
null,
null,
null, "", null);
}
catch (ASTSemanticException e6)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
case IToken.tIDENTIFIER :
case IToken.tCOLONCOLON :
case IToken.t_operator :
ITokenDuple duple = null;
IToken mark = mark();
try
{
duple = name();
}
catch( BacktrackException bt )
{
Declarator d = new Declarator( new DeclarationWrapper(scope, 0, null) );
if (LT(1) == IToken.tCOLONCOLON || LT(1) == IToken.tIDENTIFIER)
{
IToken start = consume();
IToken end = null;
if (start.getType() == IToken.tIDENTIFIER)
end = consumeTemplateParameters(end);
while (LT(1) == IToken.tCOLONCOLON || LT(1) == IToken.tIDENTIFIER)
{
end = consume();
if (end.getType() == IToken.tIDENTIFIER)
end = consumeTemplateParameters(end);
}
if (LT(1) == IToken.t_operator)
operatorId(d, start);
else
{
backup(mark);
throw backtrack;
}
}
else if( LT(1) == IToken.t_operator )
operatorId( d, null);
duple = d.getNameDuple();
}
catch(OffsetLimitReachedException olre )
{
backup(mark);
throw backtrack;
}
try
{
return astFactory.createExpression(
scope,
IASTExpression.Kind.ID_EXPRESSION,
null,
null,
null,
null,
duple, "", null);
}
catch (ASTSemanticException e8)
{
throw backtrack;
} catch (Exception e)
{
throw backtrack;
}
default :
return emptyExpression;
}
}
/**
* @throws Exception
*/
protected void varName() throws Exception
{
if (LT(1) == IToken.tCOLONCOLON)
consume();
for (;;)
{
switch (LT(1))
{
case IToken.tIDENTIFIER :
consume();
//if (isTemplateArgs()) {
// rTemplateArgs();
//}
if (LT(1) == IToken.tCOLONCOLON)
{
switch (LT(2))
{
case IToken.tIDENTIFIER :
case IToken.tCOMPL :
case IToken.t_operator :
consume();
break;
default :
return;
}
}
else
return;
break;
case IToken.tCOMPL :
consume();
consume(IToken.tIDENTIFIER);
return;
case IToken.t_operator :
consume();
//rOperatorName();
return;
default :
throw backtrack;
}
}
}
// the static instance we always use
private static BacktrackException backtrack = new BacktrackException();
// Token management
protected IScanner scanner;
protected IToken currToken, // current token we plan to consume next
lastToken; // last token we consumed
private boolean limitReached = false;
protected void setCurrentScope( IASTScope scope )
{
}
/**
* Fetches a token from the scanner.
*
* @return the next token from the scanner
* @throws EndOfFileException thrown when the scanner.nextToken() yields no tokens
*/
protected IToken fetchToken() throws EndOfFileException
{
if(limitReached) throw new OffsetLimitReachedException(getCompletionToken());
try
{
return scanner.nextToken();
}
catch( OffsetLimitReachedException olre )
{
limitReached = true;
handleOffsetLimitException(olre);
return null;
}
catch (ScannerException e)
{
log.traceLog( "ScannerException thrown : " + e.getProblem().getMessage() );
log.errorLog( "Scanner Exception: " + e.getProblem().getMessage()); //$NON-NLS-1$h
failParse();
return fetchToken();
}
}
protected void handleOffsetLimitException(OffsetLimitReachedException exception) throws EndOfFileException {
// unexpected, throw EOF instead (equivalent)
throw new EndOfFileException();
}
/**
* Look Ahead in the token list to see what is coming.
*
* @param i How far ahead do you wish to peek?
* @return the token you wish to observe
* @throws EndOfFileException if looking ahead encounters EOF, throw EndOfFile
*/
protected IToken LA(int i) throws EndOfFileException
{
if (i < 1) // can't go backwards
return null;
if (currToken == null)
currToken = fetchToken();
IToken retToken = currToken;
for (; i > 1; --i)
{
retToken = retToken.getNext();
if (retToken == null)
retToken = fetchToken();
}
return retToken;
}
/**
* Look ahead in the token list and return the token type.
*
* @param i How far ahead do you wish to peek?
* @return The type of that token
* @throws EndOfFileException if looking ahead encounters EOF, throw EndOfFile
*/
protected int LT(int i) throws EndOfFileException
{
return LA(i).getType();
}
/**
* Consume the next token available, regardless of the type.
*
* @return The token that was consumed and removed from our buffer.
* @throws EndOfFileException If there is no token to consume.
*/
protected IToken consume() throws EndOfFileException
{
if (currToken == null)
currToken = fetchToken();
if (currToken != null)
lastToken = currToken;
currToken = currToken.getNext();
return lastToken;
}
/**
* Consume the next token available only if the type is as specified.
*
* @param type The type of token that you are expecting.
* @return the token that was consumed and removed from our buffer.
* @throws BacktrackException If LT(1) != type
*/
protected IToken consume(int type) throws EndOfFileException, BacktrackException
{
if (LT(1) == type)
return consume();
else
throw backtrack;
}
/**
* Mark our place in the buffer so that we could return to it should we have to.
*
* @return The current token.
* @throws EndOfFileException If there are no more tokens.
*/
protected IToken mark() throws EndOfFileException
{
if (currToken == null)
currToken = fetchToken();
return currToken;
}
/**
* Rollback to a previous point, reseting the queue of tokens.
*
* @param mark The point that we wish to restore to.
*
*/
protected void backup(IToken mark)
{
currToken = (Token)mark;
lastToken = null; // this is not entirely right ...
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.parser.IParser#getLanguage()
*/
public ParserLanguage getLanguage()
{
return language;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.parser.IParser#setLanguage(Language)
*/
public void setLanguage( ParserLanguage l )
{
language = l;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.parser.IParser#getLastErrorOffset()
*/
public int getLastErrorOffset()
{
return firstErrorOffset;
}
protected void setCompletionContext( IASTNode node )
{
}
protected void setCompletionKind( IASTCompletionNode.CompletionKind kind )
{
}
protected void setCompletionKeywords(KeywordSets.Key key )
{
}
protected void setCompletionToken( IToken token )
{
}
protected IToken getCompletionToken()
{
return null;
}
}