blob: 5c5df98496579754119c91194e98aed5036a64a2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.dom.lrparser.action;
import static org.eclipse.cdt.core.dom.lrparser.action.ParserUtil.endOffset;
import static org.eclipse.cdt.core.dom.lrparser.action.ParserUtil.length;
import static org.eclipse.cdt.core.dom.lrparser.action.ParserUtil.offset;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.IASTASMDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
import org.eclipse.cdt.core.dom.ast.IASTContinueStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTDefaultStatement;
import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpressionList;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTFieldDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTInitializerList;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNullStatement;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTProblemHolder;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.INodeFactory;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
import org.eclipse.cdt.core.dom.lrparser.ISecondaryParser;
import org.eclipse.cdt.core.dom.lrparser.LRParserProperties;
import org.eclipse.cdt.core.dom.parser.IBuiltinBindingsProvider;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.IScanner;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousExpression;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousStatement;
import lpg.lpgjavaruntime.IToken;
/**
* Parser semantic actions that are common to both C and C++.
*
* @author Mike Kucera
*/
@SuppressWarnings("restriction")
public abstract class BuildASTParserAction extends AbstractParserAction {
/** Abstract factory for creating AST node objects */
private final INodeFactory nodeFactory;
/** Abstract factory for creating secondary parsers */
private final ISecondaryParserFactory parserFactory;
/**
* Returns true if the token is an identifier.
*/
protected abstract boolean isIdentifierToken(IToken token);
protected IASTTranslationUnit tu = null;
/**
* Create a new parser action.
* @param tu Root node of the AST, its list of declarations should be empty.
* @throws NullPointerException if any of the parameters are null
*/
public BuildASTParserAction(ITokenStream parser, ScopedStack<Object> astStack, INodeFactory nodeFactory,
ISecondaryParserFactory parserFactory) {
super(parser, astStack);
if (nodeFactory == null)
throw new NullPointerException("nodeFactory is null"); //$NON-NLS-1$
if (parserFactory == null)
throw new NullPointerException("parserFactory is null"); //$NON-NLS-1$
this.nodeFactory = nodeFactory;
this.parserFactory = parserFactory;
}
public void initializeTranslationUnit(IScanner scanner, IBuiltinBindingsProvider builtinBindingsProvider,
IIndex index) {
tu = nodeFactory.newTranslationUnit(scanner);
tu.setIndex(index);
// add built-in names to the scope
if (builtinBindingsProvider != null) {
IScope tuScope = tu.getScope();
IBinding[] bindings = builtinBindingsProvider.getBuiltinBindings(tuScope);
for (IBinding binding : bindings) {
ASTInternal.addBinding(tuScope, binding);
}
}
if (tu instanceof ASTTranslationUnit) {
((ASTTranslationUnit) tu).setLocationResolver(scanner.getLocationResolver());
}
}
public void consumeTranslationUnit() {
if (tu == null)
tu = nodeFactory.newTranslationUnit(null);
// can't close the outermost scope
for (Object o : astStack.topScope()) {
tu.addDeclaration((IASTDeclaration) o);
}
while (!astStack.isEmpty()) {
astStack.pop();
}
// this is the same way that the DOM parser computes the length
IASTDeclaration[] declarations = tu.getDeclarations();
if (declarations.length != 0) {
IASTNode d = declarations[declarations.length - 1];
ParserUtil.setOffsetAndLength(tu, 0, offset(d) + length(d));
}
resolveAmbiguityNodes(tu);
tu.freeze();
astStack.push(tu);
}
@Override
public ASTCompletionNode newCompletionNode(String prefix) {
return new ASTCompletionNode(prefix, tu);
}
/**
* Removes ambiguity nodes from the AST by resolving them.
*
* @see AbstractGNUSourceCodeParser#resolveAmbiguities()
*/
private static void resolveAmbiguityNodes(IASTTranslationUnit tu) {
if (tu instanceof ASTTranslationUnit) {
((ASTTranslationUnit) tu).resolveAmbiguities();
}
}
/**
* Consumes a single identifier token.
*/
public void consumeIdentifierName() {
astStack.push(createName(stream.getRightIToken()));
}
/**
* block_item ::= declaration | statement
*
* TODO, be careful where exactly in the grammar this is called, it may be called unnecessarily
*/
public void consumeStatementDeclarationWithDisambiguation() {
IASTDeclaration decl = (IASTDeclaration) astStack.pop();
IASTDeclarationStatement declarationStatement = nodeFactory.newDeclarationStatement(decl);
setOffsetAndLength(declarationStatement);
// attempt to also parse the tokens as an expression
IASTExpressionStatement expressionStatement = null;
if (decl instanceof IASTSimpleDeclaration) {
List<IToken> expressionTokens = stream.getRuleTokens();
expressionTokens = expressionTokens.subList(0, expressionTokens.size() - 1); // remove the semicolon at the end
ISecondaryParser<IASTExpression> expressionParser = parserFactory.getExpressionParser(stream, properties);
IASTExpression expr = runSecondaryParser(expressionParser, expressionTokens);
if (expr != null) { // the parse may fail
expressionStatement = nodeFactory.newExpressionStatement(expr);
setOffsetAndLength(expressionStatement);
}
}
List<IToken> tokens = stream.getRuleTokens();
IASTNode result;
if (expressionStatement == null)
result = declarationStatement;
else if (expressionStatement.getExpression() instanceof IASTFunctionCallExpression)
result = expressionStatement;
else if (tokens.size() == 2 && (isCompletionToken(tokens.get(0)) || isIdentifierToken(tokens.get(0)))) // identifier followed by semicolon
result = expressionStatement;
else if (isImplicitInt(decl))
result = expressionStatement;
else {
result = createAmbiguousStatement(declarationStatement, expressionStatement);
setOffsetAndLength(result);
}
astStack.push(result);
}
protected abstract IASTAmbiguousStatement createAmbiguousStatement(IASTStatement... statements);
/**
* Wrap a declaration in a DeclarationStatement.
*/
public void consumeStatementDeclaration() {
IASTDeclaration decl = (IASTDeclaration) astStack.pop();
IASTDeclarationStatement declarationStatement = nodeFactory.newDeclarationStatement(decl);
setOffsetAndLength(declarationStatement);
astStack.push(declarationStatement);
}
/**
* Returns true if the given declaration has unspecified type,
* in this case the type defaults to int and is know as "implicit int".
*
* With implicit int a lot of language constructs can be accidentally parsed
* as declarations:
*
* eg) x = 1;
* Should be an assignment statement but can also be parsed as a declaration
* of a variable x, of unspecified type, initialized to 1.
*
* These cases are easy to detect (using this method) and the wrong interpretation
* as a declaration is discarded.
*/
protected static boolean isImplicitInt(IASTDeclaration declaration) {
if (declaration instanceof IASTSimpleDeclaration) {
IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) declaration).getDeclSpecifier();
if (declSpec instanceof IASTSimpleDeclSpecifier
&& ((IASTSimpleDeclSpecifier) declSpec).getType() == IASTSimpleDeclSpecifier.t_unspecified) {
return true;
}
}
return false;
}
/**
* @param kind One of the kind flags from IASTLiteralExpression or ICPPASTLiteralExpression
* @see IASTLiteralExpression
* @see ICPPASTLiteralExpression
*/
public void consumeExpressionLiteral(int kind) {
IToken token = stream.getRightIToken();
String rep = token.toString();
// Strip the quotes from string literals, this is just to be consistent
// with the dom parser (i.e. to make a test pass)
// if(kind == IASTLiteralExpression.lk_string_literal &&
// rep.startsWith("\"") && rep.endsWith("\"")) {
// rep = rep.substring(1, rep.length()-1);
// }
IASTLiteralExpression expr = nodeFactory.newLiteralExpression(kind, rep);
ParserUtil.setOffsetAndLength(expr, token);
astStack.push(expr);
}
public void consumeExpressionBracketed() {
IASTExpression operand = (IASTExpression) astStack.pop();
IASTUnaryExpression expr = nodeFactory.newUnaryExpression(IASTUnaryExpression.op_bracketedPrimary, operand);
setOffsetAndLength(expr);
astStack.push(expr);
}
public void consumeExpressionID() {
IASTName name = createName(stream.getLeftIToken());
IASTIdExpression expr = nodeFactory.newIdExpression(name);
setOffsetAndLength(expr);
astStack.push(expr);
}
public void consumeExpressionName() {
IASTName name = (IASTName) astStack.pop();
IASTIdExpression expr = nodeFactory.newIdExpression(name);
setOffsetAndLength(expr);
astStack.push(expr);
}
/**
* expression ::= <openscope-ast> expression_list_actual
*/
public void consumeExpressionList() {
List<Object> expressions = astStack.closeScope();
if (expressions.size() == 1) {
astStack.push(expressions.get(0));
} else {
IASTExpressionList exprList = nodeFactory.newExpressionList();
for (Object o : expressions) {
exprList.addExpression((IASTExpression) o);
}
setOffsetAndLength(exprList);
astStack.push(exprList);
}
}
/**
* postfix_expression ::= postfix_expression '[' expression ']'
*/
public void consumeExpressionArraySubscript() {
IASTExpression subscript = (IASTExpression) astStack.pop();
IASTExpression arrayExpr = (IASTExpression) astStack.pop();
IASTArraySubscriptExpression expr = nodeFactory.newArraySubscriptExpression(arrayExpr, subscript);
setOffsetAndLength(expr);
astStack.push(expr);
}
/**
* postfix_expression ::= postfix_expression '(' expression_list_opt ')'
*/
public void consumeExpressionFunctionCall() {
IASTExpression argList = (IASTExpression) astStack.pop(); // may be null
IASTExpression idExpr = (IASTExpression) astStack.pop();
IASTFunctionCallExpression expr = nodeFactory.newFunctionCallExpression(idExpr, argList);
setOffsetAndLength(expr);
astStack.push(expr);
}
/**
* @param operator constant for {@link ICPPASTCastExpression}
*/
public void consumeExpressionCast(int operator) {
IASTExpression operand = (IASTExpression) astStack.pop();
IASTTypeId typeId = (IASTTypeId) astStack.pop();
IASTCastExpression expr = nodeFactory.newCastExpression(operator, typeId, operand);
setOffsetAndLength(expr);
IASTExpression alternateExpr = null;
if (operator == IASTCastExpression.op_cast) { // don't reparse for dynamic_cast etc as those are not ambiguous
// try parsing as non-cast to resolve ambiguities
ISecondaryParser<IASTExpression> secondaryParser = parserFactory.getNoCastExpressionParser(stream,
properties);
alternateExpr = runSecondaryParser(secondaryParser);
}
if (alternateExpr == null)
astStack.push(expr);
else {
IASTNode ambiguityNode = createAmbiguousExpression(expr, alternateExpr);
setOffsetAndLength(ambiguityNode);
astStack.push(ambiguityNode);
}
}
protected abstract IASTAmbiguousExpression createAmbiguousExpression(IASTExpression... expressions);
/**
* Lots of rules, no need to list them.
* @param operator From IASTUnaryExpression
*/
public void consumeExpressionUnaryOperator(int operator) {
IASTExpression operand = (IASTExpression) astStack.pop();
IASTUnaryExpression expr = nodeFactory.newUnaryExpression(operator, operand);
setOffsetAndLength(expr);
astStack.push(expr);
}
/**
* unary_operation ::= 'sizeof' '(' type_name ')'
* @see consumeExpressionUnaryOperator For the other use of sizeof
*/
public void consumeExpressionTypeId(int operator) {
IASTTypeId typeId = (IASTTypeId) astStack.pop();
IASTTypeIdExpression expr = nodeFactory.newTypeIdExpression(operator, typeId);
setOffsetAndLength(expr);
// try parsing as an expression to resolve ambiguities
ISecondaryParser<IASTExpression> secondaryParser = parserFactory.getSizeofExpressionParser(stream, properties);
IASTExpression alternateExpr = runSecondaryParser(secondaryParser);
if (alternateExpr == null)
astStack.push(expr);
else if (isFunctionType(expr)) // bug 252243
astStack.push(alternateExpr);
else {
IASTNode ambiguityNode = createAmbiguousExpression(expr, alternateExpr);
setOffsetAndLength(ambiguityNode);
astStack.push(ambiguityNode);
}
}
private static boolean isFunctionType(IASTExpression expr) {
if (expr instanceof IASTTypeIdExpression) {
IASTTypeId typeId = ((IASTTypeIdExpression) expr).getTypeId();
return typeId.getAbstractDeclarator() instanceof IASTFunctionDeclarator;
}
return false;
}
/**
* Lots of rules, no need to list them all.
* @param op Field from IASTBinaryExpression
*/
public void consumeExpressionBinaryOperator(int op) {
IASTExpression expr2 = (IASTExpression) astStack.pop();
IASTExpression expr1 = (IASTExpression) astStack.pop();
IASTBinaryExpression binExpr = nodeFactory.newBinaryExpression(op, expr1, expr2);
setOffsetAndLength(binExpr);
astStack.push(binExpr);
}
/**
* conditional_expression ::= logical_OR_expression '?' expression ':' conditional_expression
*/
public void consumeExpressionConditional() {
IASTExpression expr3 = (IASTExpression) astStack.pop();
IASTExpression expr2 = (IASTExpression) astStack.pop();
IASTExpression expr1 = (IASTExpression) astStack.pop();
IASTConditionalExpression condExpr = nodeFactory.newConditionalExpession(expr1, expr2, expr3);
setOffsetAndLength(condExpr);
astStack.push(condExpr);
}
/**
* labeled_statement ::= label_identifier ':' statement
* label_identifier ::= identifier
*/
public void consumeStatementLabeled() {
IASTStatement body = (IASTStatement) astStack.pop();
IASTName label = createName(stream.getLeftIToken());
IASTLabelStatement stat = nodeFactory.newLabelStatement(label, body);
setOffsetAndLength(stat);
astStack.push(stat);
}
/**
* labeled_statement ::= 'case' constant_expression ':' statement
*/
public void consumeStatementCase() {
IASTStatement body = (IASTStatement) astStack.pop();
IASTExpression expr = (IASTExpression) astStack.pop();
IASTCaseStatement caseStatement = nodeFactory.newCaseStatement(expr);
setOffsetAndLength(caseStatement); // TODO this is wrong, need to adjust length to end of colon
// this is a hackey fix because case statements are not modeled correctly in the AST
IASTCompoundStatement compound = nodeFactory.newCompoundStatement();
setOffsetAndLength(compound);
compound.addStatement(caseStatement);
compound.addStatement(body);
astStack.push(compound);
}
/**
* labeled_statement ::= 'default' ':' <openscope-ast> statement
*/
public void consumeStatementDefault() {
IASTStatement body = (IASTStatement) astStack.pop();
IASTDefaultStatement stat = nodeFactory.newDefaultStatement();
List<IToken> tokens = stream.getRuleTokens();
IToken defaultToken = tokens.get(0);
IToken colonToken = tokens.get(1);
ParserUtil.setOffsetAndLength(stat, offset(defaultToken), offset(colonToken) - offset(defaultToken) + 1);
IASTCompoundStatement compound = nodeFactory.newCompoundStatement();
setOffsetAndLength(compound);
compound.addStatement(stat);
compound.addStatement(body);
astStack.push(compound);
}
/**
* expression_statement ::= ';'
*/
public void consumeStatementNull() {
IASTNullStatement stat = nodeFactory.newNullStatement();
setOffsetAndLength(stat);
astStack.push(stat);
}
/**
* expression_statement ::= expression ';'
*/
public void consumeStatementExpression() {
IASTExpression expr = (IASTExpression) astStack.pop();
IASTExpressionStatement stat = nodeFactory.newExpressionStatement(expr);
setOffsetAndLength(stat);
astStack.push(stat);
}
/**
* compound_statement ::= <openscope> '{' block_item_list '}'
*
* block_item_list ::= block_item | block_item_list block_item
*/
public void consumeStatementCompoundStatement(boolean hasStatementsInBody) {
IASTCompoundStatement block = nodeFactory.newCompoundStatement();
if (hasStatementsInBody) {
for (Object o : astStack.closeScope()) {
block.addStatement((IASTStatement) o);
}
}
setOffsetAndLength(block);
astStack.push(block);
}
/**
* iteration_statement_matched
* ::= 'do' statement 'while' '(' expression ')' ';'
* | 'do' statement
*/
public void consumeStatementDoLoop(boolean hasWhileBlock) {
IASTExpression condition = hasWhileBlock ? (IASTExpression) astStack.pop() : null;
IASTStatement body = (IASTStatement) astStack.pop();
IASTDoStatement stat = nodeFactory.newDoStatement(body, condition);
setOffsetAndLength(stat);
astStack.push(stat);
}
/**
* jump_statement ::= goto goto_identifier ';'
*/
public void consumeStatementGoto() {
IASTName name = createName(stream.getRuleTokens().get(1));
IASTGotoStatement gotoStat = nodeFactory.newGotoStatement(name);
setOffsetAndLength(gotoStat);
astStack.push(gotoStat);
}
/**
* jump_statement ::= continue ';'
*/
public void consumeStatementContinue() {
IASTContinueStatement stat = nodeFactory.newContinueStatement();
setOffsetAndLength(stat);
astStack.push(stat);
}
/**
* jump_statement ::= break ';'
*/
public void consumeStatementBreak() {
IASTBreakStatement stat = nodeFactory.newBreakStatement();
setOffsetAndLength(stat);
astStack.push(stat);
}
/**
* jump_statement ::= return ';'
* jump_statement ::= return expression ';'
*/
public void consumeStatementReturn(boolean hasExpr) {
IASTExpression expr = hasExpr ? (IASTExpression) astStack.pop() : null;
IASTReturnStatement returnStat = nodeFactory.newReturnStatement(expr);
setOffsetAndLength(returnStat);
astStack.push(returnStat);
}
/**
* type_name ::= specifier_qualifier_list
* | specifier_qualifier_list abstract_declarator
*/
public void consumeTypeId(boolean hasDeclarator) {
IASTDeclarator declarator;
if (hasDeclarator)
declarator = (IASTDeclarator) astStack.pop();
else {
declarator = nodeFactory.newDeclarator(nodeFactory.newName());
ParserUtil.setOffsetAndLength(declarator, stream.getRightIToken().getEndOffset(), 0);
}
IASTDeclSpecifier declSpecifier = (IASTDeclSpecifier) astStack.pop();
IASTTypeId typeId = nodeFactory.newTypeId(declSpecifier, declarator);
setOffsetAndLength(typeId);
astStack.push(typeId);
}
/**
* declarator
* ::= <openscope-ast> ptr_operator_seq direct_declarator
*
* abstract_declarator
* ::= <openscope-ast> ptr_operator_seq
* | <openscope-ast> ptr_operator_seq direct_declarator
*/
public void consumeDeclaratorWithPointer(boolean hasDeclarator) {
IASTDeclarator decl;
if (hasDeclarator)
decl = (IASTDeclarator) astStack.pop();
else
decl = nodeFactory.newDeclarator(nodeFactory.newName());
for (Object pointer : astStack.closeScope())
decl.addPointerOperator((IASTPointerOperator) pointer);
setOffsetAndLength(decl);
astStack.push(decl);
}
/**
* init_declarator
* ::= declarator initializer
*
* @param hasDeclarator in C++ its possible for a parameter declaration to specifiy
* a default value without also specifying a named declarator
*/
public void consumeDeclaratorWithInitializer(boolean hasDeclarator) {
IASTInitializer initializer = (IASTInitializer) astStack.pop();
IASTDeclarator declarator;
if (hasDeclarator) {
declarator = (IASTDeclarator) astStack.peek();
} else {
IASTName emptyName = nodeFactory.newName();
declarator = nodeFactory.newDeclarator(emptyName);
setOffsetAndLength(emptyName);
astStack.push(declarator);
}
declarator.setInitializer(initializer);
setOffsetAndLength(declarator); // adjust the length to include the initializer
}
/**
* asm_definition
* ::= 'asm' '(' 'stringlit' ')' ';'
*/
public void consumeDeclarationASM() {
String s = stream.getRuleTokens().get(2).toString();
IASTASMDeclaration asm = nodeFactory.newASMDeclaration(s);
setOffsetAndLength(asm);
astStack.push(asm);
}
/**
* parameter_declaration ::= declaration_specifiers declarator
* | declaration_specifiers abstract_declarator
*/
public void consumeParameterDeclaration() {
IASTDeclarator declarator = (IASTDeclarator) astStack.pop();
IASTDeclSpecifier declSpec = (IASTDeclSpecifier) astStack.pop();
IASTParameterDeclaration declaration = nodeFactory.newParameterDeclaration(declSpec, declarator);
setOffsetAndLength(declaration);
astStack.push(declaration);
}
/**
* parameter_declaration ::= declaration_specifiers
*/
public void consumeParameterDeclarationWithoutDeclarator() {
// offsets need to be calculated differently in this case
final int endOffset = stream.getRightIToken().getEndOffset();
IASTName name = nodeFactory.newName();
ParserUtil.setOffsetAndLength(name, endOffset, 0);
// it appears that a declarator is always required in the AST here
IASTDeclarator declarator = nodeFactory.newDeclarator(name);
ParserUtil.setOffsetAndLength(declarator, endOffset, 0);
IASTDeclSpecifier declSpec = (IASTDeclSpecifier) astStack.pop();
IASTParameterDeclaration declaration = nodeFactory.newParameterDeclaration(declSpec, declarator);
setOffsetAndLength(declaration);
astStack.push(declaration);
}
/**
* TODO: do I really want to share declaration rules between the two parsers.
* Even if there is potential for reuse it still may be cleaner to leave the
* common stuff to just simple expressions and statements.
*
* For C99:
*
* declaration ::= declaration_specifiers <openscope> init_declarator_list ';'
* declaration ::= declaration_specifiers ';'
*
*
* For C++:
*
* simple_declaration
* ::= declaration_specifiers_opt <openscope-ast> init_declarator_list_opt ';'
*
*
* TODO Make both grammars the same here.
*/
// public void consumeDeclarationSimple(boolean hasDeclaratorList) {
// if(TRACE_ACTIONS) DebugUtil.printMethodTrace();
//
// List<Object> declarators = (hasDeclaratorList) ? astStack.closeScope() : Collections.emptyList();
// IASTDeclSpecifier declSpecifier = (IASTDeclSpecifier) astStack.pop(); // may be null
//
// // do not generate nodes for extra EOC tokens
// if(matchTokens(parser.getRuleTokens(), CPPParsersym.TK_EndOfCompletion))
// return;
//
// if(declSpecifier == null) { // can happen if implicit int is used
// declSpecifier = nodeFactory.newSimpleDeclSpecifier();
// setOffsetAndLength(declSpecifier, parser.getLeftIToken().getStartOffset(), 0);
// }
//
// IASTSimpleDeclaration declaration = nodeFactory.newSimpleDeclaration(declSpecifier);
//
// for(Object declarator : declarators)
// declaration.addDeclarator((IASTDeclarator)declarator);
//
// setOffsetAndLength(declaration);
// astStack.push(declaration);
//
// if(TRACE_AST_STACK) System.out.println(astStack);
// }
/**
* direct_declarator ::= '(' declarator ')'
*/
public void consumeDirectDeclaratorBracketed() {
IASTDeclarator nested = (IASTDeclarator) astStack.pop();
IASTDeclarator declarator = nodeFactory.newDeclarator(nodeFactory.newName());
declarator.setNestedDeclarator(nested);
setOffsetAndLength(declarator);
astStack.push(declarator);
}
/**
* direct_declarator ::= declarator_id_name
*/
public void consumeDirectDeclaratorIdentifier() {
IASTName name = (IASTName) astStack.pop();
IASTDeclarator declarator = nodeFactory.newDeclarator(name);
setOffsetAndLength(declarator);
astStack.push(declarator);
}
/**
* array_modifier
* ::= '[' ']'
* | '[' assignment_expression ']'
*/
public void consumeDirectDeclaratorArrayModifier(boolean hasAssignmentExpr) {
IASTExpression expr = hasAssignmentExpr ? (IASTExpression) astStack.pop() : null;
IASTArrayModifier arrayModifier = nodeFactory.newArrayModifier(expr);
setOffsetAndLength(arrayModifier);
astStack.push(arrayModifier);
}
/**
* When the identifier part of a declarator is parsed it will put a plain IASTDeclarator on the stack.
* When the array modifier part is parsed we will need to throw away the plain
* declarator and replace it with an array declarator. If its a multidimensional array then
* the additional array modifiers will need to be added to the array declarator.
* Special care is taken for nested declarators.
*/
protected void addArrayModifier(IASTArrayModifier arrayModifier) {
IASTDeclarator node = (IASTDeclarator) astStack.pop();
// Its a nested declarator so create an new ArrayDeclarator
if (node.getNestedDeclarator() != null) { //node.getPropertyInParent() == IASTDeclarator.NESTED_DECLARATOR) {
IASTArrayDeclarator declarator = nodeFactory.newArrayDeclarator(nodeFactory.newName());
IASTDeclarator nested = node;
declarator.setNestedDeclarator(nested);
int offset = offset(nested);
int length = endOffset(arrayModifier) - offset;
ParserUtil.setOffsetAndLength(declarator, offset, length);
declarator.addArrayModifier(arrayModifier);
astStack.push(declarator);
}
// There is already an array declarator so just add the modifier to it
else if (node instanceof IASTArrayDeclarator) {
IASTArrayDeclarator decl = (IASTArrayDeclarator) node;
((ASTNode) decl).setLength(endOffset(arrayModifier) - offset(decl));
decl.addArrayModifier(arrayModifier);
astStack.push(decl);
}
// The declarator is an identifier so create a new array declarator
else {
IASTName name = node.getName();
IASTArrayDeclarator decl = nodeFactory.newArrayDeclarator(name);
int offset = offset(name);
int length = endOffset(arrayModifier) - offset;
ParserUtil.setOffsetAndLength(decl, offset, length);
decl.addArrayModifier(arrayModifier);
astStack.push(decl);
}
}
/**
* Pops a simple declarator from the stack, converts it into
* a FunctionDeclator, then pushes it.
* TODO: is this the best way of doing this?
* TODO, rename this method, its an accidental overload
*/
protected void addFunctionModifier(IASTFunctionDeclarator declarator, int endOffset) {
IASTDeclarator decl = (IASTDeclarator) astStack.pop();
if (decl.getNestedDeclarator() != null) {
decl = decl.getNestedDeclarator(); // need to remove one level of nesting for function pointers
declarator.setNestedDeclarator(decl);
declarator.setName(nodeFactory.newName());
int offset = offset(decl);
ParserUtil.setOffsetAndLength(declarator, offset, endOffset - offset);
astStack.push(declarator);
} else {
IASTName name = decl.getName();
if (name == null) {
name = nodeFactory.newName();
}
declarator.setName(name);
IASTPointerOperator[] pointers = decl.getPointerOperators();
for (IASTPointerOperator pointer : pointers) {
declarator.addPointerOperator(pointer);
}
int offset = offset(name); // TODO
ParserUtil.setOffsetAndLength(declarator, offset, endOffset - offset);
astStack.push(declarator);
}
}
// TODO why is this here
// /**
// * direct_declarator ::= direct_declarator array_modifier
// * consume the direct_declarator part and add the array modifier
// */
// public void consumeDirectDeclaratorArrayDeclarator() {
// if(TRACE_ACTIONS) DebugUtil.printMethodTrace();
//
// IASTArrayModifier arrayModifier = (IASTArrayModifier) astStack.pop();
// addArrayModifier(arrayModifier);
// }
/**
* direct_abstract_declarator
* ::= array_modifier
* | direct_abstract_declarator array_modifier
*/
public void consumeDirectDeclaratorArrayDeclarator(boolean hasDeclarator) {
IASTArrayModifier arrayModifier = (IASTArrayModifier) astStack.pop();
if (hasDeclarator) {
addArrayModifier(arrayModifier);
} else {
IASTArrayDeclarator decl = nodeFactory.newArrayDeclarator(nodeFactory.newName());
decl.addArrayModifier(arrayModifier);
setOffsetAndLength(decl);
astStack.push(decl);
}
}
/**
* enum_specifier ::= 'enum' '{' <openscope> enumerator_list_opt '}'
* | 'enum' enum_identifier '{' <openscope> enumerator_list_opt '}'
*/
public void consumeTypeSpecifierEnumeration(boolean hasIdent) {
IASTName name = (hasIdent) ? createName(stream.getRuleTokens().get(1)) : nodeFactory.newName();
IASTEnumerationSpecifier enumSpec = nodeFactory.newEnumerationSpecifier(name);
for (Object o : astStack.closeScope())
enumSpec.addEnumerator((IASTEnumerator) o);
setOffsetAndLength(enumSpec);
astStack.push(enumSpec);
}
/**
* enumerator ::= enum_identifier
* | enum_identifier '=' constant_expression
*/
public void consumeEnumerator(boolean hasInitializer) {
IASTName name = createName(stream.getLeftIToken());
IASTExpression value = null;
if (hasInitializer)
value = (IASTExpression) astStack.pop();
IASTEnumerator enumerator = nodeFactory.newEnumerator(name, value);
setOffsetAndLength(enumerator);
astStack.push(enumerator);
}
private int initializerListNestingLevel = 0;
public void initializerListStart() {
initializerListNestingLevel++;
}
public void initializerListEnd() {
initializerListNestingLevel--;
}
/**
* initializer ::= assignment_expression
*/
public void consumeInitializer() {
//CDT_70_FIX_FROM_50-#4
IASTInitializerClause initClause = (IASTInitializerClause) astStack.pop();
if (initClause instanceof IASTExpression) {
if (discardInitializer((IASTExpression) initClause)) {
astStack.push(null);
return;
}
}
//CDT_70_FIX_FROM_50-#2
//IASTInitializerExpression initializer = nodeFactory.newInitializerExpression(expr);
IASTEqualsInitializer initializer = nodeFactory.newEqualsInitializer(initClause);
setOffsetAndLength(initializer);
astStack.push(initializer);
}
private boolean discardInitializer(IASTExpression expression) {
return initializerListNestingLevel > 0
&& Boolean.parseBoolean(
properties.get(LRParserProperties.SKIP_TRIVIAL_EXPRESSIONS_IN_AGGREGATE_INITIALIZERS))
&& !ASTQueries.canContainName(expression);
}
/**
* initializer ::= '{' <openscope> initializer_list '}'
* | '{' <openscope> initializer_list ',' '}'
*/
public void consumeInitializerList() {
IASTInitializerList list = nodeFactory.newInitializerList();
for (Object o : astStack.closeScope())
list.addInitializer((IASTInitializer) o);
setOffsetAndLength(list);
astStack.push(list);
}
/**
* struct_declarator
* ::= ':' constant_expression
* | declarator ':' constant_expression
*/
public void consumeBitField(boolean hasDeclarator) {
IASTExpression expr = (IASTExpression) astStack.pop();
IASTName name;
if (hasDeclarator) // it should have been parsed into a regular declarator
name = ((IASTDeclarator) astStack.pop()).getName();
else
name = nodeFactory.newName();
IASTFieldDeclarator fieldDecl = nodeFactory.newFieldDeclarator(name, expr);
setOffsetAndLength(fieldDecl);
astStack.push(fieldDecl);
}
/**
* statement ::= ERROR_TOKEN
*/
public void consumeStatementProblem() {
consumeProblem(nodeFactory.newProblemStatement(null));
}
/**
* assignment_expression ::= ERROR_TOKEN
* constant_expression ::= ERROR_TOKEN
*/
public void consumeExpressionProblem() {
consumeProblem(nodeFactory.newProblemExpression(null));
}
/**
* external_declaration ::= ERROR_TOKEN
*/
public void consumeDeclarationProblem() {
consumeProblem(nodeFactory.newProblemDeclaration(null));
}
private void consumeProblem(IASTProblemHolder problemHolder) {
IASTProblem problem = nodeFactory.newProblem(IProblem.SYNTAX_ERROR, new char[0], true);
problemHolder.setProblem(problem);
setOffsetAndLength(problem);
setOffsetAndLength((ASTNode) problemHolder);
astStack.push(problemHolder);
}
}