| /******************************************************************************* |
| * Copyright (c) 2006, 2012 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.c99; |
| |
| 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.matchTokens; |
| import static org.eclipse.cdt.core.dom.lrparser.action.ParserUtil.offset; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_Completion; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_EndOfCompletion; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_LeftParen; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_SemiColon; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK__Bool; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK__Complex; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_auto; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_char; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_const; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_double; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_extern; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_float; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_for; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_identifier; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_inline; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_int; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_long; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_register; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_restrict; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_short; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_signed; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_static; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_struct; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_typedef; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_union; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_unsigned; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_void; |
| import static org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym.TK_volatile; |
| |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; |
| 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.IASTElaboratedTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTFieldReference; |
| import org.eclipse.cdt.core.dom.ast.IASTForStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; |
| import org.eclipse.cdt.core.dom.ast.IASTIdExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTIfStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTInitializer; |
| import org.eclipse.cdt.core.dom.ast.IASTInitializerList; |
| import org.eclipse.cdt.core.dom.ast.IASTName; |
| import org.eclipse.cdt.core.dom.ast.IASTNode; |
| import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTPointer; |
| import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTTypeId; |
| import org.eclipse.cdt.core.dom.ast.IASTWhileStatement; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTArrayDesignator; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTArrayModifier; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTCompositeTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTDesignatedInitializer; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTDesignator; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTFieldDesignator; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTPointer; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTSimpleDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTTypeIdInitializerExpression; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTTypedefNameSpecifier; |
| import org.eclipse.cdt.core.dom.ast.c.ICNodeFactory; |
| import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.lrparser.ISecondaryParser; |
| import org.eclipse.cdt.core.dom.lrparser.action.BuildASTParserAction; |
| import org.eclipse.cdt.core.dom.lrparser.action.ISecondaryParserFactory; |
| import org.eclipse.cdt.core.dom.lrparser.action.ITokenMap; |
| import org.eclipse.cdt.core.dom.lrparser.action.ITokenStream; |
| import org.eclipse.cdt.core.dom.lrparser.action.ParserUtil; |
| import org.eclipse.cdt.core.dom.lrparser.action.ScopedStack; |
| import org.eclipse.cdt.core.dom.lrparser.action.TokenMap; |
| import org.eclipse.cdt.core.parser.util.CollectionUtils; |
| import org.eclipse.cdt.internal.core.dom.lrparser.c99.C99Parsersym; |
| import org.eclipse.cdt.internal.core.dom.parser.ASTNode; |
| import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousExpression; |
| import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousStatement; |
| import org.eclipse.cdt.internal.core.dom.parser.c.CASTAmbiguousExpression; |
| import org.eclipse.cdt.internal.core.dom.parser.c.CASTAmbiguousStatement; |
| |
| import lpg.lpgjavaruntime.IToken; |
| |
| /** |
| * Semantic actions called by the C99 parser to build an AST. |
| * |
| * @author Mike Kucera |
| */ |
| @SuppressWarnings("restriction") |
| public class C99BuildASTParserAction extends BuildASTParserAction { |
| |
| private final ITokenMap tokenMap; |
| |
| /** Used to create the AST node objects */ |
| protected final ICNodeFactory nodeFactory; |
| |
| private final ISecondaryParserFactory parserFactory; |
| |
| /** |
| * @param parser |
| * @param orderedTerminalSymbols When an instance of this class is created for a parser |
| * that parsers token kinds will be mapped back to the base C99 parser's token kinds. |
| */ |
| public C99BuildASTParserAction(ITokenStream parser, ScopedStack<Object> astStack, ICNodeFactory nodeFactory, |
| ISecondaryParserFactory parserFactory) { |
| super(parser, astStack, nodeFactory, parserFactory); |
| |
| this.nodeFactory = nodeFactory; |
| this.parserFactory = parserFactory; |
| this.tokenMap = new TokenMap(C99Parsersym.orderedTerminalSymbols, parser.getOrderedTerminalSymbols()); |
| } |
| |
| private int baseKind(IToken token) { |
| return tokenMap.mapKind(token.getKind()); |
| } |
| |
| @Override |
| protected boolean isCompletionToken(IToken token) { |
| return baseKind(token) == TK_Completion; |
| } |
| |
| @Override |
| protected boolean isIdentifierToken(IToken token) { |
| return baseKind(token) == TK_identifier; |
| } |
| |
| @Override |
| protected IASTName createName(char[] image) { |
| return nodeFactory.newName(image); |
| } |
| |
| /******************************************************************** |
| * Start of semantic actions. |
| ********************************************************************/ |
| |
| /** |
| * postfix_expression ::= postfix_expression '.' ident |
| * postfix_expression ::= postfix_expression '->' ident |
| */ |
| public void consumeExpressionFieldReference(boolean isPointerDereference) { |
| IASTName name = createName(stream.getRightIToken()); |
| IASTExpression owner = (IASTExpression) astStack.pop(); |
| IASTFieldReference expr = nodeFactory.newFieldReference(name, owner); |
| expr.setIsPointerDereference(isPointerDereference); |
| setOffsetAndLength(expr); |
| astStack.push(expr); |
| } |
| |
| /** |
| * postfix_expression ::= '(' type_id ')' initializer_list |
| */ |
| public void consumeExpressionTypeIdInitializer() { |
| IASTInitializerList list = (IASTInitializerList) astStack.pop(); |
| IASTTypeId typeId = (IASTTypeId) astStack.pop(); |
| ICASTTypeIdInitializerExpression expr = nodeFactory.newTypeIdInitializerExpression(typeId, list); |
| setOffsetAndLength(expr); |
| astStack.push(expr); |
| } |
| |
| /** |
| * Applies a specifier to a decl spec node. |
| * |
| * In plain C99 specifiers are always just single tokens, but in language |
| * extensions specifiers may be more complex. Thats why this method takes |
| * Object as the type of the specifier, so that it may be overridden in subclasses |
| * and used with arbitrary objects as the specifier. |
| */ |
| public void setSpecifier(ICASTDeclSpecifier node, Object specifier) { |
| if (!(specifier instanceof IToken)) |
| return; |
| IToken token = (IToken) specifier; |
| |
| int kind = baseKind(token); |
| switch (kind) { |
| case TK_typedef: |
| node.setStorageClass(IASTDeclSpecifier.sc_typedef); |
| return; |
| case TK_extern: |
| node.setStorageClass(IASTDeclSpecifier.sc_extern); |
| return; |
| case TK_static: |
| node.setStorageClass(IASTDeclSpecifier.sc_static); |
| return; |
| case TK_auto: |
| node.setStorageClass(IASTDeclSpecifier.sc_auto); |
| return; |
| case TK_register: |
| node.setStorageClass(IASTDeclSpecifier.sc_register); |
| return; |
| case TK_inline: |
| node.setInline(true); |
| return; |
| case TK_const: |
| node.setConst(true); |
| return; |
| case TK_restrict: |
| node.setRestrict(true); |
| return; |
| case TK_volatile: |
| node.setVolatile(true); |
| return; |
| } |
| |
| if (node instanceof ICASTSimpleDeclSpecifier) { |
| ICASTSimpleDeclSpecifier n = (ICASTSimpleDeclSpecifier) node; |
| switch (kind) { |
| case TK_void: |
| n.setType(IASTSimpleDeclSpecifier.t_void); |
| break; |
| case TK_char: |
| n.setType(IASTSimpleDeclSpecifier.t_char); |
| break; |
| case TK__Bool: |
| n.setType(ICASTSimpleDeclSpecifier.t_Bool); |
| break; |
| case TK_int: |
| n.setType(IASTSimpleDeclSpecifier.t_int); |
| break; |
| case TK_float: |
| n.setType(IASTSimpleDeclSpecifier.t_float); |
| break; |
| case TK_double: |
| n.setType(IASTSimpleDeclSpecifier.t_double); |
| break; |
| case TK_signed: |
| n.setSigned(true); |
| break; |
| case TK_unsigned: |
| n.setUnsigned(true); |
| break; |
| case TK_short: |
| n.setShort(true); |
| break; |
| case TK__Complex: |
| n.setComplex(true); |
| break; |
| case TK_long: |
| boolean isLong = n.isLong(); |
| n.setLongLong(isLong); |
| n.setLong(!isLong); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * type_qualifier ::= const | restrict | volatile |
| */ |
| private void collectArrayModifierTypeQualifiers(ICASTArrayModifier arrayModifier) { |
| for (Object o : astStack.closeScope()) { |
| switch (baseKind((IToken) o)) { |
| case TK_const: |
| arrayModifier.setConst(true); |
| break; |
| case TK_restrict: |
| arrayModifier.setRestrict(true); |
| break; |
| case TK_volatile: |
| arrayModifier.setVolatile(true); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * array_modifier |
| * ::= '[' <openscope> type_qualifier_list ']' |
| * | '[' <openscope> type_qualifier_list assignment_expression ']' |
| * | '[' 'static' assignment_expression ']' |
| * | '[' 'static' <openscope> type_qualifier_list assignment_expression ']' |
| * | '[' <openscope> type_qualifier_list 'static' assignment_expression ']' |
| * | '[' '*' ']' |
| * | '[' <openscope> type_qualifier_list '*' ']' |
| * |
| * The main reason to separate array_modifier into its own rule is to |
| * make calculating the offset and length much easier. |
| */ |
| public void consumeDirectDeclaratorModifiedArrayModifier(boolean isStatic, boolean isVarSized, |
| boolean hasTypeQualifierList, boolean hasAssignmentExpr) { |
| assert isStatic || isVarSized || hasTypeQualifierList; |
| |
| ICASTArrayModifier arrayModifier = nodeFactory.newArrayModifier(null); |
| |
| // consume all the stuff between the square brackets into an array modifier |
| arrayModifier.setStatic(isStatic); |
| arrayModifier.setVariableSized(isVarSized); |
| |
| if (hasAssignmentExpr) |
| arrayModifier.setConstantExpression((IASTExpression) astStack.pop()); |
| |
| if (hasTypeQualifierList) |
| collectArrayModifierTypeQualifiers(arrayModifier); |
| |
| setOffsetAndLength(arrayModifier); |
| astStack.push(arrayModifier); |
| } |
| |
| /** |
| * direct_declarator ::= direct_declarator '(' <openscope> identifier_list ')' |
| */ |
| public void consumeDirectDeclaratorFunctionDeclaratorKnR() { |
| ICASTKnRFunctionDeclarator declarator = nodeFactory.newKnRFunctionDeclarator(null, null); |
| IASTName[] names = astStack.topScope().toArray(new IASTName[0]); |
| declarator.setParameterNames(names); |
| astStack.closeScope(); |
| int endOffset = endOffset(stream.getRightIToken()); |
| addFunctionModifier(declarator, endOffset); |
| } |
| |
| /** |
| * identifier_list |
| * ::= 'identifier' |
| * | identifier_list ',' 'identifier' |
| */ |
| public void consumeIdentifierKnR() { |
| IASTName name = createName(stream.getRightIToken()); |
| astStack.push(name); |
| } |
| |
| /** |
| * pointer ::= '*' |
| * | pointer '*' |
| */ |
| public void consumePointer() { |
| IASTPointer pointer = nodeFactory.newPointer(); |
| IToken star = stream.getRightIToken(); |
| ParserUtil.setOffsetAndLength(pointer, star); |
| astStack.push(pointer); |
| } |
| |
| /** |
| * pointer ::= '*' <openscope> type_qualifier_list |
| * | pointer '*' <openscope> type_qualifier_list |
| */ |
| public void consumePointerTypeQualifierList() { |
| ICASTPointer pointer = nodeFactory.newPointer(); |
| |
| for (Object o : astStack.closeScope()) { |
| IToken token = (IToken) o; |
| switch (baseKind(token)) { |
| default: |
| assert false; |
| case TK_const: |
| pointer.setConst(true); |
| break; |
| case TK_volatile: |
| pointer.setVolatile(true); |
| break; |
| case TK_restrict: |
| pointer.setRestrict(true); |
| break; |
| } |
| } |
| |
| setOffsetAndLength(pointer); |
| astStack.push(pointer); |
| } |
| |
| /** |
| * direct_abstract_declarator |
| * ::= '(' ')' |
| * | direct_abstract_declarator '(' ')' |
| * | '(' <openscope> parameter_type_list ')' |
| * | direct_abstract_declarator '(' <openscope> parameter_type_list ')' |
| */ |
| public void consumeDirectDeclaratorFunctionDeclarator(boolean hasDeclarator, boolean hasParameters) { |
| IASTName name = nodeFactory.newName(); |
| IASTStandardFunctionDeclarator declarator = nodeFactory.newFunctionDeclarator(name); |
| |
| if (hasParameters) { |
| boolean isVarArgs = astStack.pop() == PLACE_HOLDER; |
| declarator.setVarArgs(isVarArgs); |
| |
| for (Object param : astStack.closeScope()) |
| declarator.addParameterDeclaration((IASTParameterDeclaration) param); |
| } |
| |
| if (hasDeclarator) { |
| addFunctionModifier(declarator, endOffset(stream.getRightIToken())); |
| } else { |
| setOffsetAndLength(declarator); |
| astStack.push(declarator); |
| } |
| } |
| |
| /** |
| * designated_initializer ::= <openscope> designation initializer |
| */ |
| public void consumeInitializerDesignated() { |
| IASTInitializer initializer = (IASTInitializer) astStack.pop(); |
| ICASTDesignatedInitializer result = nodeFactory.newDesignatedInitializer(initializer); |
| |
| for (Object o : astStack.closeScope()) |
| result.addDesignator((ICASTDesignator) o); |
| |
| setOffsetAndLength(result); |
| astStack.push(result); |
| } |
| |
| /** |
| * designator ::= '[' constant_expression ']' |
| */ |
| public void consumeDesignatorArray() { |
| IASTExpression expr = (IASTExpression) astStack.pop(); |
| ICASTArrayDesignator designator = nodeFactory.newArrayDesignator(expr); |
| setOffsetAndLength(designator); |
| astStack.push(designator); |
| } |
| |
| /** |
| * designator ::= '.' 'identifier' |
| */ |
| public void consumeDesignatorField() { |
| IASTName name = createName(stream.getRightIToken()); |
| ICASTFieldDesignator designator = nodeFactory.newFieldDesignator(name); |
| setOffsetAndLength(designator); |
| astStack.push(designator); |
| } |
| |
| /** |
| * declaration_specifiers ::= <openscope> simple_declaration_specifiers |
| */ |
| public void consumeDeclarationSpecifiersSimple() { |
| ICASTSimpleDeclSpecifier declSpec = nodeFactory.newSimpleDeclSpecifier(); |
| |
| for (Object specifier : astStack.closeScope()) |
| setSpecifier(declSpec, specifier); |
| |
| setOffsetAndLength(declSpec); |
| astStack.push(declSpec); |
| } |
| |
| /** |
| * declaration_specifiers ::= <openscope> struct_or_union_declaration_specifiers |
| * declaration_specifiers ::= <openscope> enum_declaration_specifiers |
| */ |
| public void consumeDeclarationSpecifiersStructUnionEnum() { |
| List<Object> topScope = astStack.closeScope(); |
| ICASTDeclSpecifier declSpec = CollectionUtils.findFirstAndRemove(topScope, ICASTDeclSpecifier.class); |
| |
| // now apply the rest of the specifiers |
| for (Object specifier : topScope) |
| setSpecifier(declSpec, specifier); |
| |
| setOffsetAndLength(declSpec); |
| astStack.push(declSpec); |
| } |
| |
| /** |
| * declaration_specifiers ::= <openscope> typdef_name_declaration_specifiers |
| */ |
| public void consumeDeclarationSpecifiersTypedefName() { |
| ICASTTypedefNameSpecifier declSpec = nodeFactory.newTypedefNameSpecifier(null); |
| |
| for (Object o : astStack.topScope()) { |
| if (o instanceof IToken) { |
| IToken token = (IToken) o; |
| // There is one identifier token on the stack |
| int kind = baseKind(token); |
| if (kind == TK_identifier || kind == TK_Completion) { |
| IASTName name = createName(token); |
| declSpec.setName(name); |
| } else { |
| setSpecifier(declSpec, token); |
| } |
| } |
| } |
| |
| astStack.closeScope(); |
| setOffsetAndLength(declSpec); |
| astStack.push(declSpec); |
| } |
| |
| /** |
| * declaration ::= declaration_specifiers <openscope> init_declarator_list ';' |
| * declaration ::= declaration_specifiers ';' |
| */ |
| public void consumeDeclarationSimple(boolean hasDeclaratorList) { |
| List<Object> declarators = (hasDeclaratorList) ? astStack.closeScope() : Collections.emptyList(); |
| IASTDeclSpecifier declSpecifier = (IASTDeclSpecifier) astStack.pop(); |
| |
| List<IToken> ruleTokens = stream.getRuleTokens(); |
| if (ruleTokens.size() == 1 && baseKind(ruleTokens.get(0)) == TK_EndOfCompletion) |
| return; // do not generate nodes for extra EOC tokens |
| |
| IASTSimpleDeclaration declaration = nodeFactory.newSimpleDeclaration(declSpecifier); |
| |
| for (Object declarator : declarators) |
| declaration.addDeclarator((IASTDeclarator) declarator); |
| |
| setOffsetAndLength(declaration); |
| astStack.push(declaration); |
| } |
| |
| /** |
| * external_declaration ::= ';' |
| * |
| * TODO: doesn't the declaration need a name? |
| */ |
| public void consumeDeclarationEmpty() { |
| // Don't generate declaration nodes for extra EOC tokens |
| if (baseKind(stream.getLeftIToken()) == C99Parsersym.TK_EndOfCompletion) |
| return; |
| |
| IASTDeclSpecifier declSpecifier = nodeFactory.newSimpleDeclSpecifier(); |
| IASTSimpleDeclaration declaration = nodeFactory.newSimpleDeclaration(declSpecifier); |
| setOffsetAndLength(declSpecifier); |
| setOffsetAndLength(declaration); |
| astStack.push(declaration); |
| } |
| |
| /** |
| * a declaration inside of a struct |
| * |
| * struct_declaration ::= specifier_qualifier_list <openscope> struct_declarator_list ';' |
| * |
| * specifier_qualifier_list is a subset of declaration_specifiers, |
| * struct_declarators are declarators that are allowed inside a struct, |
| * a struct declarator is a regular declarator plus bit fields |
| */ |
| public void consumeStructDeclaration(boolean hasDeclaration) { |
| consumeDeclarationSimple(hasDeclaration); // TODO this is ok as long as bit fields implement IASTDeclarator (see consumeDeclaration()) |
| } |
| |
| /** |
| * struct_or_union_specifier |
| * ::= 'struct' '{' <openscope> struct_declaration_list_opt '}' |
| * | 'union' '{' <openscope> struct_declaration_list_opt '}' |
| * | 'struct' struct_or_union_identifier '{' <openscope> struct_declaration_list_opt '}' |
| * | 'union' struct_or_union_identifier '{' <openscope> struct_declaration_list_opt '}' |
| * |
| * @param key either k_struct or k_union from IASTCompositeTypeSpecifier |
| */ |
| public void consumeTypeSpecifierComposite(boolean hasName) { |
| |
| int key = 0; |
| switch (baseKind(stream.getLeftIToken())) { |
| case TK_struct: |
| key = IASTCompositeTypeSpecifier.k_struct; |
| case TK_union: |
| key = IASTCompositeTypeSpecifier.k_union; |
| } |
| |
| IASTName name = (hasName) ? createName(stream.getRuleTokens().get(1)) : nodeFactory.newName(); |
| |
| ICASTCompositeTypeSpecifier typeSpec = nodeFactory.newCompositeTypeSpecifier(key, name); |
| |
| for (Object o : astStack.closeScope()) |
| typeSpec.addMemberDeclaration((IASTDeclaration) o); |
| |
| setOffsetAndLength(typeSpec); |
| astStack.push(typeSpec); |
| } |
| |
| /** |
| * struct_or_union_specifier |
| * ::= 'struct' struct_or_union_identifier |
| * | 'union' struct_or_union_identifier |
| * |
| * enum_specifier ::= 'enum' enum_identifier |
| */ |
| public void consumeTypeSpecifierElaborated(int kind) { |
| IASTName name = createName(stream.getRuleTokens().get(1)); |
| IASTElaboratedTypeSpecifier typeSpec = nodeFactory.newElaboratedTypeSpecifier(kind, name); |
| setOffsetAndLength(typeSpec); |
| astStack.push(typeSpec); |
| } |
| |
| /** |
| * iteration_statement ::= 'while' '(' expression ')' statement |
| */ |
| public void consumeStatementWhileLoop() { |
| IASTStatement body = (IASTStatement) astStack.pop(); |
| IASTExpression condition = (IASTExpression) astStack.pop(); |
| IASTWhileStatement whileStatement = nodeFactory.newWhileStatement(condition, body); |
| setOffsetAndLength(whileStatement); |
| astStack.push(whileStatement); |
| } |
| |
| /** |
| * iteration_statement_matched |
| * ::= 'for' '(' expression_opt ';' expression_opt ';' expression_opt ')' statement |
| */ |
| public void consumeStatementForLoop() { |
| IASTStatement body = (IASTStatement) astStack.pop(); |
| // these two expressions may be null, see consumeExpressionOptional() |
| IASTExpression expr3 = (IASTExpression) astStack.pop(); |
| IASTExpression expr2 = (IASTExpression) astStack.pop(); |
| IASTNode node = (IASTNode) astStack.pop(); // may be an expression or a declaration |
| |
| IASTStatement initializer; |
| if (node instanceof IASTExpression) |
| initializer = nodeFactory.newExpressionStatement((IASTExpression) node); |
| else if (node instanceof IASTDeclaration) |
| initializer = nodeFactory.newDeclarationStatement((IASTDeclaration) node); |
| else // its null |
| initializer = nodeFactory.newNullStatement(); |
| |
| // bug 234463, fix for content assist to work in this case |
| int TK_EOC = TK_EndOfCompletion; // TODO: change this in the grammar file |
| List<IToken> tokens = stream.getRuleTokens(); |
| if (matchTokens(tokens, tokenMap, TK_for, TK_LeftParen, TK_Completion, TK_EOC, TK_EOC, TK_EOC, TK_EOC)) { |
| IASTName name = createName(tokens.get(2)); |
| IASTIdExpression idExpression = nodeFactory.newIdExpression(name); |
| ParserUtil.setOffsetAndLength(idExpression, offset(name), length(name)); |
| initializer = nodeFactory.newExpressionStatement(idExpression); |
| ParserUtil.setOffsetAndLength(initializer, offset(name), length(name)); |
| } |
| |
| //initializer could be an expression or a declaration |
| int TK_SC = TK_SemiColon; |
| IASTExpressionStatement expressionStatement = null; |
| if (initializer instanceof IASTDeclarationStatement) { |
| IASTDeclarationStatement declarationStatement = (IASTDeclarationStatement) initializer; |
| List<IToken> expressionTokens = stream.getRuleTokens(); |
| |
| //find the first semicolon |
| int end_pos = -1; |
| for (int i = 0, n = expressionTokens.size(); i < n; i++) { |
| if (tokenMap.mapKind(expressionTokens.get(i).getKind()) == TK_SC) { |
| end_pos = i; |
| break; |
| } |
| } |
| |
| if (end_pos != -1) { |
| expressionTokens = expressionTokens.subList(2, end_pos); |
| |
| ISecondaryParser<IASTExpression> expressionParser = parserFactory.getExpressionParser(stream, |
| properties); |
| IASTExpression expr1 = runSecondaryParser(expressionParser, expressionTokens); |
| |
| if (expr1 != null) { // the parse may fail |
| expressionStatement = nodeFactory.newExpressionStatement(expr1); |
| setOffsetAndLength(expressionStatement); |
| } |
| } |
| |
| if (expressionStatement == null) |
| initializer = declarationStatement; |
| else { |
| initializer = createAmbiguousStatement(expressionStatement, declarationStatement); |
| setOffsetAndLength(initializer); |
| } |
| } |
| |
| if (node != null) |
| ParserUtil.setOffsetAndLength(initializer, offset(node), length(node)); |
| |
| IASTForStatement forStat = nodeFactory.newForStatement(initializer, expr2, expr3, body); |
| setOffsetAndLength(forStat); |
| astStack.push(forStat); |
| } |
| |
| /** |
| * selection_statement ::= switch '(' expression ')' statement |
| */ |
| public void consumeStatementSwitch() { |
| IASTStatement body = (IASTStatement) astStack.pop(); |
| IASTExpression expr = (IASTExpression) astStack.pop(); |
| IASTSwitchStatement stat = nodeFactory.newSwitchStatement(expr, body); |
| setOffsetAndLength(stat); |
| astStack.push(stat); |
| } |
| |
| public void consumeStatementIf(boolean hasElse) { |
| IASTStatement elseClause = null; |
| if (hasElse) |
| elseClause = (IASTStatement) astStack.pop(); |
| |
| IASTStatement thenClause = (IASTStatement) astStack.pop(); |
| IASTExpression condition = (IASTExpression) astStack.pop(); |
| |
| IASTIfStatement ifStatement = nodeFactory.newIfStatement(condition, thenClause, elseClause); |
| setOffsetAndLength(ifStatement); |
| astStack.push(ifStatement); |
| } |
| |
| /** |
| * function_definition |
| * ::= declaration_specifiers <openscope> declarator compound_statement |
| * | function_declarator compound_statement |
| * |
| * The seemingly pointless <openscope> is just there to |
| * prevent a shift/reduce conflict in the grammar. |
| */ |
| public void consumeFunctionDefinition(boolean hasDeclSpecifiers) { |
| IASTCompoundStatement body = (IASTCompoundStatement) astStack.pop(); |
| IASTFunctionDeclarator decl = (IASTFunctionDeclarator) astStack.pop(); |
| astStack.closeScope(); |
| |
| IASTDeclSpecifier declSpecifier; |
| if (hasDeclSpecifiers) { |
| declSpecifier = (IASTDeclSpecifier) astStack.pop(); |
| } else { // there are no decl specifiers, implicit int |
| declSpecifier = nodeFactory.newSimpleDeclSpecifier(); |
| } |
| |
| IASTFunctionDefinition def = nodeFactory.newFunctionDefinition(declSpecifier, decl, body); |
| setOffsetAndLength(def); |
| astStack.push(def); |
| } |
| |
| /** |
| * function_definition |
| * ::= declaration_specifiers <openscope-ast> knr_function_declarator |
| * <openscope-ast> declaration_list compound_statement |
| */ |
| public void consumeFunctionDefinitionKnR() { |
| IASTCompoundStatement body = (IASTCompoundStatement) astStack.pop(); |
| |
| IASTDeclaration[] declarations = astStack.topScope().toArray(new IASTDeclaration[0]); |
| astStack.closeScope(); |
| |
| ICASTKnRFunctionDeclarator decl = (ICASTKnRFunctionDeclarator) astStack.pop(); |
| astStack.closeScope(); |
| |
| ICASTDeclSpecifier declSpecifier = (ICASTDeclSpecifier) astStack.pop(); |
| decl.setParameterDeclarations(declarations); |
| |
| // re-compute the length of the declaration to take the parameter declarations into account |
| ASTNode lastDeclaration = (ASTNode) declarations[declarations.length - 1]; |
| int endOffset = lastDeclaration.getOffset() + lastDeclaration.getLength(); |
| ((ASTNode) decl).setLength(endOffset - offset(decl)); |
| |
| IASTFunctionDefinition def = nodeFactory.newFunctionDefinition(declSpecifier, decl, body); |
| setOffsetAndLength(def); |
| astStack.push(def); |
| } |
| |
| @Override |
| protected IASTAmbiguousExpression createAmbiguousExpression(IASTExpression... expressions) { |
| return new CASTAmbiguousExpression(expressions); |
| } |
| |
| @Override |
| protected IASTAmbiguousStatement createAmbiguousStatement(IASTStatement... statements) { |
| return new CASTAmbiguousStatement(statements); |
| } |
| } |