All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.cxx.parser.CxxGrammarImpl Maven / Gradle / Ivy

The newest version!
/*
 * Sonar C++ Plugin (Community)
 * Copyright (C) 2011 Waleri Enns and CONTACT Software GmbH
 * [email protected]
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */
package org.sonar.cxx.parser;

import com.sonar.sslr.impl.matcher.GrammarFunctions;
import org.sonar.cxx.api.CxxGrammar;
import org.sonar.cxx.api.CxxKeyword;

import static com.sonar.sslr.api.GenericTokenType.EOF;
import static com.sonar.sslr.api.GenericTokenType.IDENTIFIER;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Predicate.next;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Predicate.not;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Standard.and;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Standard.o2n;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Standard.one2n;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Standard.opt;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Standard.or;
import static org.sonar.cxx.api.CxxTokenType.CHARACTER;
import static org.sonar.cxx.api.CxxTokenType.NUMBER;
import static org.sonar.cxx.api.CxxTokenType.STRING;

/**
 * Based on the C++ Standard, Appendix A
 */
public class CxxGrammarImpl extends CxxGrammar {
  public CxxGrammarImpl() {
    toplevel();
    expressions();
    statements();
    declarations();
    declarators();
    classes();
    derivedClasses();
    specialMemberFunctions();
    overloading();
    templates();
    exceptionHandling();

    misc();

    test.is("debugging asset");

    GrammarFunctions.enableMemoizationOfMatchesForAllRules(this);
  }

  private void misc() {
    // C++ Standard, Section 2.14.6 "Boolean literals"
    bool.is(
        or(
            CxxKeyword.TRUE,
            CxxKeyword.FALSE
        )
        );

    literal.is(
        or(
            CHARACTER,
            STRING,
            NUMBER,
            bool
        )
        );
  }

  private void toplevel() {
    translationUnit.is(o2n(declaration), EOF);
  }

  private void expressions() {
    primaryExpression.is(
        or(
            literal,
            CxxKeyword.THIS,
            and("(", expression, ")"),
            idExpression,
            lambdaExpression
        )
        ).skipIfOneChild();

    idExpression.is(
        or(
            qualifiedId,
            unqualifiedId
        )
        );

    unqualifiedId.is(
        or(
            templateId,
            operatorFunctionId,
            conversionFunctionId,
            literalOperatorId,
            and("~", className),
            and("~", decltypeSpecifier),
            IDENTIFIER
        )
        );

    qualifiedId.is(
        or(
            and(nestedNameSpecifier, opt(CxxKeyword.TEMPLATE), unqualifiedId),
            and("::", IDENTIFIER),
            and("::", operatorFunctionId),
            and("::", literalOperatorId),
            and("::", templateId)
        )
        );

    nestedNameSpecifier.is(
        or(
            and(opt("::"), typeName, "::"),
            and(opt("::"), namespaceName, "::"),
            and(decltypeSpecifier, "::")
        ),
        o2n(
        or(
            and(IDENTIFIER, "::"),
            and(opt(CxxKeyword.TEMPLATE), simpleTemplateId, "::")
        )
        )
        );

    lambdaExpression.is(lambdaIntroducer, opt(lambdaDeclarator), compoundStatement);

    lambdaIntroducer.is("[", opt(lambdaCapture), "]");

    lambdaCapture.is(
        or(
            and(captureDefault, ",", captureList),
            captureList,
            captureDefault
        ));

    captureDefault.is(
        or(
            "&",
            "="
        ));

    captureList.is(and(capture, opt("...")), o2n(",", and(capture, opt("..."))));

    capture.is(
        or(
            IDENTIFIER,
            and("&", IDENTIFIER),
            CxxKeyword.THIS
        ));

    lambdaDeclarator.is(
        "(", parameterDeclarationClause, ")", opt(CxxKeyword.MUTABLE),
        opt(exceptionSpecification), opt(attributeSpecifierSeq), opt(trailingReturnType)
        );

    postfixExpression.is(
        or(
            and(simpleTypeSpecifier, "(", opt(expressionList), ")"),
            and(simpleTypeSpecifier, bracedInitList),
            and(typenameSpecifier, "(", opt(expressionList), ")"),
            and(typenameSpecifier, bracedInitList),

            primaryExpression,

            and(CxxKeyword.DYNAMIC_CAST, "<", typeId, ">", "(", expression, ")"),
            and(CxxKeyword.STATIC_CAST, "<", typeId, ">", "(", expression, ")"),
            and(CxxKeyword.REINTERPRET_CAST, "<", typeId, ">", "(", expression, ")"),
            and(CxxKeyword.CONST_CAST, "<", typeId, ">", "(", expression, ")"),
            and(CxxKeyword.TYPEID, "(", expression, ")"),
            and(CxxKeyword.TYPEID, "(", typeId, ")")
        ),

        // postfixExpression [ expression ]
        // postfixExpression [ bracedInitList ]
        // postfixExpression ( expressionListopt )
        // postfixExpression . templateopt idExpression
        // postfixExpression -> templateopt idExpression
        // postfixExpression . pseudoDestructorName
        // postfixExpression -> pseudoDestructorName
        // postfixExpression ++
        // postfixExpression --

        // should replace the left recursive stuff above

        o2n(
        or(
            and("[", expression, "]"),
            and("(", opt(expressionList), ")"),
            and(or(".", "->"),
                or(and(opt(CxxKeyword.TEMPLATE), idExpression),
                    pseudoDestructorName)),
            "++",
            "--"
        )
        )
        ).skipIfOneChild();

    expressionList.is(initializerList);

    pseudoDestructorName.is(
        or(
            and(opt(nestedNameSpecifier), typeName, "::", "~", typeName),
            and(nestedNameSpecifier, CxxKeyword.TEMPLATE, simpleTemplateId, "::", "~", typeName),
            and(opt(nestedNameSpecifier), "~", typeName),
            and("~", decltypeSpecifier)
        )
        );

    unaryExpression.is(
        or(
            and(unaryOperator, castExpression),
            postfixExpression,
            and("++", castExpression),
            and("--", castExpression),
            and(CxxKeyword.SIZEOF, unaryExpression),
            and(CxxKeyword.SIZEOF, "(", typeId, ")"),
            and(CxxKeyword.SIZEOF, "...", "(", IDENTIFIER, ")"),
            and(CxxKeyword.ALIGNOF, "(", typeId, ")"),
            noexceptExpression,
            newExpression,
            deleteExpression
        )
        ).skipIfOneChild();

    unaryOperator.is(
        or("*", "&", "+", "-", "!", "~")
        );

    newExpression.is(
        or(
            and(opt("::"), CxxKeyword.NEW, opt(newPlacement), newTypeId, opt(newInitializer)),
            and(opt("::"), CxxKeyword.NEW, newPlacement, "(", typeId, ")", opt(newInitializer)),
            and(opt("::"), CxxKeyword.NEW, "(", typeId, ")", opt(newInitializer))
        )
        );

    newPlacement.is("(", expressionList, ")");

    newTypeId.is(typeSpecifierSeq, opt(newDeclarator));

    newDeclarator.is(
        or(
            noptrNewDeclarator,
            and(ptrOperator, opt(newDeclarator))
        )
        );

    noptrNewDeclarator.is("[", expression, "]", opt(attributeSpecifierSeq), o2n("[", constantExpression, "]", opt(attributeSpecifierSeq)));

    newInitializer.is(
        or(
            and("(", opt(expressionList), ")"),
            bracedInitList
        )
        );

    deleteExpression.is(opt("::"), CxxKeyword.DELETE, opt("[", "]"), castExpression);

    noexceptExpression.is(CxxKeyword.NOEXCEPT, "(", expression, ")");

    castExpression.is(
        or(
            and(next("(", typeId, ")"), "(", typeId, ")", castExpression),
            unaryExpression
        )
        ).skipIfOneChild();

    pmExpression.is(castExpression, o2n(or(".*", "->*"), castExpression)).skipIfOneChild();

    multiplicativeExpression.is(pmExpression, o2n(or("*", "/", "%"), pmExpression)).skipIfOneChild();

    additiveExpression.is(multiplicativeExpression, o2n(or("+", "-"), multiplicativeExpression)).skipIfOneChild();

    shiftExpression.is(additiveExpression, o2n(or("<<", ">>"), additiveExpression)).skipIfOneChild();

    relationalExpression.is(shiftExpression, o2n(or("<", ">", "<=", ">="), shiftExpression)).skipIfOneChild();

    equalityExpression.is(relationalExpression, o2n(or("==", "!="), relationalExpression)).skipIfOneChild();

    andExpression.is(equalityExpression, o2n("&", equalityExpression)).skipIfOneChild();

    exclusiveOrExpression.is(andExpression, o2n("^", andExpression)).skipIfOneChild();

    inclusiveOrExpression.is(exclusiveOrExpression, o2n("|", exclusiveOrExpression)).skipIfOneChild();

    logicalAndExpression.is(inclusiveOrExpression, o2n("&&", inclusiveOrExpression)).skipIfOneChild();

    logicalOrExpression.is(logicalAndExpression, o2n("||", logicalAndExpression)).skipIfOneChild();

    conditionalExpression.is(
        or(
            and(logicalOrExpression, "?", expression, ":", assignmentExpression),
            logicalOrExpression
        )
        ).skipIfOneChild();

    assignmentExpression.is(
        or(
            and(logicalOrExpression, assignmentOperator, initializerClause),
            conditionalExpression,
            throwExpression
        )
        ).skipIfOneChild();

    assignmentOperator.is(or("=", "*=", "/=", "%=", "+=", "-=", ">>=", "<<=", "&=", "^=", "|="));

    expression.is(assignmentExpression, o2n(",", assignmentExpression));

    constantExpression.is(conditionalExpression);
  }

  private void statements() {
    statement.is(
        or(
            labeledStatement,
            and(opt(attributeSpecifierSeq), expressionStatement),
            and(opt(attributeSpecifierSeq), compoundStatement),
            and(opt(attributeSpecifierSeq), selectionStatement),
            and(opt(attributeSpecifierSeq), iterationStatement),
            and(opt(attributeSpecifierSeq), jumpStatement),
            declarationStatement,
            and(opt(attributeSpecifierSeq), tryBlock)
        )
        );

    labeledStatement.is(opt(attributeSpecifierSeq), or(IDENTIFIER, and(CxxKeyword.CASE, constantExpression), CxxKeyword.DEFAULT), ":", statement);

    expressionStatement.is(opt(expression), ";");

    compoundStatement.is("{", opt(statementSeq), "}");

    statementSeq.is(one2n(statement));

    selectionStatement.is(
        or(
            and(CxxKeyword.IF, "(", condition, ")", statement, opt(CxxKeyword.ELSE, statement)),
            and(CxxKeyword.SWITCH, "(", condition, ")", statement)
        )
        );

    condition.is(
        or(
            and(opt(attributeSpecifierSeq), conditionDeclSpecifierSeq, declarator, or(and("=", initializerClause), bracedInitList)),
            expression
        )
        );

    conditionDeclSpecifierSeq.is(
        one2n(
            not(and(declarator, or("=", "{"))),
            declSpecifier
        ),
        opt(attributeSpecifierSeq)
        );

    iterationStatement.is(
        or(
            and(CxxKeyword.WHILE, "(", condition, ")", statement),
            and(CxxKeyword.DO, statement, CxxKeyword.WHILE, "(", expression, ")", ";"),
            and(CxxKeyword.FOR, "(", forInitStatement, opt(condition), ";", opt(expression), ")", statement),
            and(CxxKeyword.FOR, "(", forRangeDeclaration, ":", forRangeInitializer, ")", statement)
        )
        );

    forInitStatement.is(
        or(
            expressionStatement,
            simpleDeclaration
        )
        );

    forRangeDeclaration.is(opt(attributeSpecifierSeq), forrangeDeclSpecifierSeq, declarator);

    forrangeDeclSpecifierSeq.is(
        one2n(
            not(declarator),
            declSpecifier
        ),
        opt(attributeSpecifierSeq)
        );

    forRangeInitializer.is(
        or(
            expression,
            bracedInitList
        )
        );

    jumpStatement.is(
        or(
            and(CxxKeyword.BREAK, ";"),
            and(CxxKeyword.CONTINUE, ";"),
            and(CxxKeyword.RETURN, opt(expression), ";"),
            and(CxxKeyword.RETURN, bracedInitList, ";"),
            and(CxxKeyword.GOTO, IDENTIFIER, ";")
        )
        );

    declarationStatement.is(blockDeclaration);
  }

  private void declarations() {
    declarationSeq.is(one2n(declaration));

    declaration.is(
        or(
            functionDefinition,
            blockDeclaration,
            templateDeclaration,
            explicitInstantiation,
            explicitSpecialization,
            linkageSpecification,
            namespaceDefinition,
            emptyDeclaration,
            attributeDeclaration
        )
        );

    blockDeclaration.is(
        or(
            simpleDeclaration,
            asmDefinition,
            namespaceAliasDefinition,
            usingDeclaration,
            usingDirective,
            staticAssertDeclaration,
            aliasDeclaration,
            opaqueEnumDeclaration
        )
        );

    aliasDeclaration.is(CxxKeyword.USING, IDENTIFIER, opt(attributeSpecifierSeq), "=", typeId);

    simpleDeclaration.is(
        or(
            and(opt(simpleDeclSpecifierSeq), opt(initDeclaratorList), ";"),
            and(attributeSpecifierSeq, opt(simpleDeclSpecifierSeq), initDeclaratorList, ";")
        )
        );

    simpleDeclSpecifierSeq.is(
        one2n(
            not(and(opt(initDeclaratorList), ";")),
            declSpecifier
        ),
        opt(attributeSpecifierSeq)
        );

    staticAssertDeclaration.is(CxxKeyword.STATIC_ASSERT, "(", constantExpression, ",", STRING, ")", ";");

    emptyDeclaration.is(";");

    attributeDeclaration.is(attributeSpecifierSeq, ";");

    declSpecifier.is(
        or(
            CxxKeyword.FRIEND, CxxKeyword.TYPEDEF, CxxKeyword.CONSTEXPR,
            storageClassSpecifier,
            functionSpecifier,
            typeSpecifier
        )
        );

    storageClassSpecifier.is(
        or(CxxKeyword.REGISTER, CxxKeyword.STATIC, CxxKeyword.THREAD_LOCAL, CxxKeyword.EXTERN, CxxKeyword.MUTABLE)
        );

    functionSpecifier.is(
        or(CxxKeyword.INLINE, CxxKeyword.VIRTUAL, CxxKeyword.EXPLICIT)
        );

    typedefName.is(IDENTIFIER);

    typeSpecifier.is(
        or(
            classSpecifier,
            enumSpecifier,
            trailingTypeSpecifier
        )
        );

    trailingTypeSpecifier.is(
        or(
            simpleTypeSpecifier,
            elaboratedTypeSpecifier,
            typenameSpecifier,
            cvQualifier)
        );

    typeSpecifierSeq.is(one2n(typeSpecifier), opt(attributeSpecifierSeq));

    trailingTypeSpecifierSeq.is(one2n(trailingTypeSpecifier), opt(attributeSpecifierSeq));

    simpleTypeSpecifier.is(
        or(
            "char", "char16_t", "char32_t", "wchar_t", "bool", "short", "int", "long", "signed", "unsigned", "float", "double", "void", "auto",
            decltypeSpecifier,
            and(nestedNameSpecifier, CxxKeyword.TEMPLATE, simpleTemplateId),

            // TODO: the "::"-Alternative to nested-name-specifier is because of need to parse
            // stuff like "void foo(::A a);". Figure out if there is another way
            and(opt(or(nestedNameSpecifier, "::")), typeName)
        )
        );

    typeName.is(
        or(
            simpleTemplateId,
            className,
            enumName,
            typedefName)
        );

    decltypeSpecifier.is(CxxKeyword.DECLTYPE, "(", expression, ")");

    elaboratedTypeSpecifier.is(
        or(
            and(classKey, opt(nestedNameSpecifier), opt(CxxKeyword.TEMPLATE), simpleTemplateId),

            // TODO: the "::"-Alternative to nested-name-specifier is because of need to parse
            // stuff like "friend class ::A". Figure out if there is another way
            and(classKey, opt(attributeSpecifierSeq), opt(or(nestedNameSpecifier, "::")), IDENTIFIER),

            and(CxxKeyword.ENUM, opt(nestedNameSpecifier), IDENTIFIER)
        )
        );

    enumName.is(IDENTIFIER);

    enumSpecifier.is(
        or(
            and(enumHead, "{", opt(enumeratorList), "}"),
            and(enumHead, "{", enumeratorList, ",", "}")
        )
        );

    enumHead.is(enumKey, opt(attributeSpecifierSeq), or(and(nestedNameSpecifier, IDENTIFIER), opt(IDENTIFIER)), opt(enumBase));

    opaqueEnumDeclaration.is(enumKey, opt(attributeSpecifierSeq), IDENTIFIER, opt(enumBase), ";");

    enumKey.is(CxxKeyword.ENUM, opt(CxxKeyword.CLASS, CxxKeyword.STRUCT));

    enumBase.is(":", typeSpecifierSeq);

    enumeratorList.is(enumeratorDefinition, o2n(",", enumeratorDefinition));

    enumeratorDefinition.is(enumerator, opt("=", constantExpression));

    enumerator.is(IDENTIFIER);

    namespaceName.is(
        or(
            originalNamespaceName,
            namespaceAlias
        )
        );

    originalNamespaceName.is(IDENTIFIER);

    namespaceDefinition.is(
        or(
            namedNamespaceDefinition,
            unnamedNamespaceDefinition
        )
        );

    namedNamespaceDefinition.is(
        or(
            originalNamespaceDefinition,
            extensionNamespaceDefinition
        )
        );

    originalNamespaceDefinition.is(opt(CxxKeyword.INLINE), CxxKeyword.NAMESPACE, IDENTIFIER, "{", namespaceBody, "}");

    extensionNamespaceDefinition.is(opt(CxxKeyword.INLINE), CxxKeyword.NAMESPACE, originalNamespaceName, "{", namespaceBody, "}");

    unnamedNamespaceDefinition.is(opt(CxxKeyword.INLINE), CxxKeyword.NAMESPACE, "{", namespaceBody, "}");

    namespaceBody.is(opt(declarationSeq));

    namespaceAlias.is(IDENTIFIER);

    namespaceAliasDefinition.is(CxxKeyword.NAMESPACE, IDENTIFIER, "=", qualifiedNamespaceSpecifier, ";");

    qualifiedNamespaceSpecifier.is(opt(nestedNameSpecifier), namespaceName);

    usingDeclaration.is(
        or(
            and(CxxKeyword.USING, opt(CxxKeyword.TYPENAME), nestedNameSpecifier, unqualifiedId, ";"),
            and(CxxKeyword.USING, "::", unqualifiedId, ";")
        )
        );

    usingDirective.is(opt(attributeSpecifier), CxxKeyword.USING, CxxKeyword.NAMESPACE, opt("::"), opt(nestedNameSpecifier), namespaceName, ";");

    asmDefinition.is(CxxKeyword.ASM, "(", STRING, ")", ";");

    linkageSpecification.is(CxxKeyword.EXTERN, STRING, or(and("{", opt(declarationSeq), "}"), declaration));

    attributeSpecifierSeq.is(one2n(attributeSpecifier));

    attributeSpecifier.is(
        or(
            and("[", "[", attributeList, "]", "]"),
            alignmentSpecifier
        ));

    alignmentSpecifier.is(
        or(
            and(CxxKeyword.ALIGNAS, "(", typeId, opt("..."), ")"),
            and(CxxKeyword.ALIGNAS, "(", assignmentExpression, opt("..."), ")")
        ));

    attributeList.is(
        or(
            and(attribute, "...", o2n(",", attribute, "...")),
            and(opt(attribute), o2n(",", opt(attribute)))
        ));

    attribute.is(attributeToken, opt(attributeArgumentClause));

    attributeToken.is(
        or(
            attributeScopedToken,
            IDENTIFIER
        ));

    attributeScopedToken.is(attributeNamespace, "::", IDENTIFIER);

    attributeNamespace.is(IDENTIFIER);

    attributeArgumentClause.is("(", balancedTokenSeq, ")");

    balancedTokenSeq.is(o2n(balancedToken));

    balancedToken.is(
        or(
            IDENTIFIER,
            and("(", balancedTokenSeq, ")"),
            and("{", balancedTokenSeq, "}"),
            and("[", balancedTokenSeq, "]")
        ));
  }

  private void declarators() {
    initDeclaratorList.is(initDeclarator, o2n(",", initDeclarator));

    initDeclarator.is(declarator, opt(initializer));

    declarator.is(
        or(
            ptrDeclarator,
            and(noptrDeclarator, parametersAndQualifiers, trailingReturnType)
        )
        );

    ptrDeclarator.is(
        or(
            and(ptrOperator, ptrDeclarator),
            noptrDeclarator
        )
        );

    noptrDeclarator.is(
        or(
            and(declaratorId, opt(attributeSpecifierSeq)),
            and("(", ptrDeclarator, ")")
        ),
        o2n(
        or(
            parametersAndQualifiers,
            and("[", opt(constantExpression), "]", opt(attributeSpecifierSeq))
        )
        )
        );

    parametersAndQualifiers.is("(", parameterDeclarationClause, ")", opt(attributeSpecifierSeq), opt(cvQualifierSeq), opt(refQualifier), opt(exceptionSpecification));

    trailingReturnType.is("->", trailingTypeSpecifierSeq, opt(abstractDeclarator));

    ptrOperator.is(
        or(
            and("*", opt(attributeSpecifierSeq), opt(cvQualifierSeq)),
            and("&", opt(attributeSpecifierSeq)),
            and("&&", opt(attributeSpecifierSeq)),
            and(nestedNameSpecifier, "*", opt(attributeSpecifierSeq), opt(cvQualifierSeq))
        )
        );

    cvQualifierSeq.is(one2n(cvQualifier));

    cvQualifier.is(
        or(CxxKeyword.CONST, CxxKeyword.VOLATILE)
        );

    refQualifier.is(
        or("&", "&&")
        );

    declaratorId.is(
        or(
            and(opt(nestedNameSpecifier), className),
            and(opt("..."), idExpression)
        )
        );

    typeId.is(typeSpecifierSeq, opt(abstractDeclarator));

    abstractDeclarator.is(
        or(
            ptrAbstractDeclarator,
            and(opt(noptrAbstractDeclarator), parametersAndQualifiers, trailingReturnType),
            abstractPackDeclarator
        )
        );

    ptrAbstractDeclarator.is(o2n(ptrOperator), opt(noptrAbstractDeclarator));

    noptrAbstractDeclarator.is(
        opt("(", ptrAbstractDeclarator, ")"),
        o2n(
        or(
            parametersAndQualifiers,
            and("[", opt(constantExpression), "]", opt(attributeSpecifierSeq))
        )
        )
        );

    abstractPackDeclarator.is(o2n(ptrOperator), noptrAbstractPackDeclarator);

    noptrAbstractPackDeclarator.is(
        "...",
        o2n(or(parametersAndQualifiers,
            and("[", opt(constantExpression), "]", opt(attributeSpecifierSeq))
        )
        )
        );

    parameterDeclarationClause.is(
        or(
            and(parameterDeclarationList, ",", "..."),
            and(opt(parameterDeclarationList), opt("...")),
            "..."
        )
        );

    parameterDeclarationList.is(parameterDeclaration, o2n(",", parameterDeclaration));

    parameterDeclaration.is(
        or(
            and(opt(attributeSpecifierSeq), parameterDeclSpecifierSeq, declarator, opt("=", initializerClause)),
            and(opt(attributeSpecifierSeq), parameterDeclSpecifierSeq, opt(abstractDeclarator), opt("=", initializerClause))
        )
        );

    parameterDeclSpecifierSeq.is(
        o2n(
            not(and(opt(declarator), or("=", ")", ","))),
            declSpecifier
        ),
        opt(attributeSpecifierSeq)
        );

    functionDefinition.is(opt(attributeSpecifierSeq), opt(functionDeclSpecifierSeq), declarator, opt(virtSpecifierSeq), functionBody);

    functionDeclSpecifierSeq.is(
        one2n(
            not(and(declarator, opt(virtSpecifierSeq), functionBody)),
            declSpecifier
        ),
        opt(attributeSpecifierSeq)
        );

    functionBody.is(
        or(
            and(opt(ctorInitializer), compoundStatement),
            functionTryBlock,
            and("=", CxxKeyword.DELETE, ";"),
            and("=", CxxKeyword.DEFAULT, ";")
        )
        );

    initializer.is(
        or(
            and("(", expressionList, ")"),
            braceOrEqualInitializer
        )
        );

    braceOrEqualInitializer.is(
        or(
            and("=", initializerClause),
            bracedInitList
        )
        );

    initializerClause.is(
        or(
            assignmentExpression,
            bracedInitList
        )
        );

    initializerList.is(initializerClause, opt("..."), o2n(",", initializerClause, opt("...")));

    bracedInitList.is("{", opt(initializerList), opt(","), "}");
  }

  private void classes() {
    className.is(
        or(
            simpleTemplateId,
            IDENTIFIER
        )
        );

    classSpecifier.is(classHead, "{", opt(memberSpecification), "}");

    classHead.is(
        or(
            and(classKey, opt(attributeSpecifierSeq), classHeadName, opt(classVirtSpecifier), opt(baseClause)),
            and(classKey, opt(attributeSpecifierSeq), opt(baseClause))
        )
        );

    classHeadName.is(opt(nestedNameSpecifier), className);

    classVirtSpecifier.is(CxxKeyword.FINAL);

    classKey.is(
        or(CxxKeyword.CLASS, CxxKeyword.STRUCT, CxxKeyword.UNION)
        );

    memberSpecification.is(
        one2n(
        or(
            memberDeclaration,
            and(accessSpecifier, ":")
        )
        )
        );

    memberDeclaration.is(
        or(
            and(opt(attributeSpecifierSeq), opt(memberDeclSpecifierSeq), opt(memberDeclaratorList), ";"),
            and(functionDefinition, opt(";")),
            and(opt("::"), nestedNameSpecifier, opt(CxxKeyword.TEMPLATE), unqualifiedId, ";"),
            usingDeclaration,
            staticAssertDeclaration,
            templateDeclaration,
            aliasDeclaration
        )
        );

    memberDeclSpecifierSeq.is(
        one2n(
            not(and(opt(memberDeclaratorList), ";")),
            declSpecifier
        ),
        opt(attributeSpecifierSeq)
        );

    memberDeclaratorList.is(memberDeclarator, o2n(",", memberDeclarator));

    memberDeclarator.is(
        or(
            and(declarator, braceOrEqualInitializer),
            and(declarator, virtSpecifierSeq, opt(pureSpecifier)),
            and(opt(IDENTIFIER), opt(attributeSpecifierSeq), ":", constantExpression),
            declarator
        )
        );

    virtSpecifierSeq.is(one2n(virtSpecifier));

    virtSpecifier.is(
        or(CxxKeyword.OVERRIDE, CxxKeyword.FINAL)
        );

    pureSpecifier.is("=", "0");
  }

  private void derivedClasses() {
    baseClause.is(":", baseSpecifierList);

    baseSpecifierList.is(baseSpecifier, opt("..."), o2n(",", baseSpecifier, opt("...")));

    baseSpecifier.is(
        or(
            and(opt(attributeSpecifierSeq), baseTypeSpecifier),
            and(opt(attributeSpecifierSeq), CxxKeyword.VIRTUAL, opt(accessSpecifier), baseTypeSpecifier),
            and(opt(attributeSpecifierSeq), accessSpecifier, opt(CxxKeyword.VIRTUAL), baseTypeSpecifier)
        )
        );

    classOrDecltype.is(
        or(
            and(opt(nestedNameSpecifier), className),
            decltypeSpecifier)
        );

    baseTypeSpecifier.is(classOrDecltype);

    accessSpecifier.is(
        or(CxxKeyword.PRIVATE, CxxKeyword.PROTECTED, CxxKeyword.PUBLIC)
        );
  }

  private void specialMemberFunctions() {
    conversionFunctionId.is(CxxKeyword.OPERATOR, conversionTypeId);

    conversionTypeId.is(typeSpecifierSeq, opt(conversionDeclarator));

    conversionDeclarator.is(one2n(ptrOperator));

    ctorInitializer.is(":", memInitializerList);

    memInitializerList.is(memInitializer, opt("..."), o2n(",", memInitializer, opt("...")));

    memInitializer.is(memInitializerId, or(and("(", opt(expressionList), ")"), bracedInitList));

    memInitializerId.is(
        or(
            classOrDecltype,
            IDENTIFIER
        )
        );
  }

  private void overloading() {
    operatorFunctionId.is(CxxKeyword.OPERATOR, operator);

    operator.is(
        or(
            and(CxxKeyword.NEW, "[", "]"),
            and(CxxKeyword.DELETE, "[", "]"),
            CxxKeyword.NEW, CxxKeyword.DELETE,
            "+", "-", "!", "=", "^=", "&=", "<=", ">=",
            and("(", ")"),
            and("[", "]"),
            "*", "<", "|=", "&&", "/",
            ">", "<<", "||", "%", "+=", ">>", "++", "^", "-=", ">>=", "--", "&", "*=", "<<=",
            ",", "|", "/=", "==", "->*", "~", "%=", "!=", "->"
        )
        );

    literalOperatorId.is(CxxKeyword.OPERATOR, "\"\"", IDENTIFIER);
  }

  private void templates() {
    templateDeclaration.is(CxxKeyword.TEMPLATE, "<", templateParameterList, ">", declaration);

    templateParameterList.is(templateParameter, o2n(",", templateParameter));

    templateParameter.is(
        or(
            typeParameter,
            parameterDeclaration
        )
        );

    typeParameter.is(
        or(
            and(CxxKeyword.CLASS, opt(IDENTIFIER), "=", typeId),
            and(CxxKeyword.CLASS, opt("..."), opt(IDENTIFIER)),
            and(CxxKeyword.TYPENAME, opt(IDENTIFIER), "=", typeId),
            and(CxxKeyword.TYPENAME, opt("..."), opt(IDENTIFIER)),
            and(CxxKeyword.TEMPLATE, "<", templateParameterList, ">", CxxKeyword.CLASS, opt(IDENTIFIER), "=", idExpression),
            and(CxxKeyword.TEMPLATE, "<", templateParameterList, ">", CxxKeyword.CLASS, opt("..."), opt(IDENTIFIER))
        )
        );

    simpleTemplateId.is(templateName, "<", opt(templateArgumentList), ">");

    templateId.is(
        or(
            simpleTemplateId,
            and(operatorFunctionId, "<", opt(templateArgumentList), ">"),
            and(literalOperatorId, "<", opt(templateArgumentList), ">")
        )
        );

    templateName.is(IDENTIFIER);

    templateArgumentList.is(templateArgument, opt("..."), o2n(",", templateArgument, opt("...")));

    templateArgument.is(
        or(
            typeId,

            // FIXME: workaround to parse stuff like "carray"
            // actually, it should be covered by the next rule (constantExpression)
            // but it doesnt work because of ambiguity template syntax <--> relationalExpression
            shiftExpression,
            constantExpression,

            idExpression
        )
        );

    typenameSpecifier.is(
        CxxKeyword.TYPENAME, nestedNameSpecifier,
        or(and(opt(CxxKeyword.TEMPLATE), simpleTemplateId), IDENTIFIER));

    explicitInstantiation.is(opt(CxxKeyword.EXTERN), CxxKeyword.TEMPLATE, declaration);

    explicitSpecialization.is(CxxKeyword.TEMPLATE, "<", ">", declaration);
  }

  private void exceptionHandling() {
    tryBlock.is(CxxKeyword.TRY, compoundStatement, handlerSeq);

    functionTryBlock.is(CxxKeyword.TRY, opt(ctorInitializer), compoundStatement, handlerSeq);

    handlerSeq.is(one2n(handler));

    handler.is(CxxKeyword.CATCH, "(", exceptionDeclaration, ")", compoundStatement);

    exceptionDeclaration.is(
        or(
            and(opt(attributeSpecifierSeq), typeSpecifierSeq, or(declarator, opt(abstractDeclarator))),
            "..."
        )
        );

    throwExpression.is(CxxKeyword.THROW, opt(assignmentExpression));

    exceptionSpecification.is(
        or(
            dynamicExceptionSpecification,
            noexceptSpecification
        )
        );

    dynamicExceptionSpecification.is(CxxKeyword.THROW, "(", opt(typeIdList), ")");

    typeIdList.is(typeId, opt("..."), o2n(",", typeId, opt("...")));

    noexceptSpecification.is(CxxKeyword.NOEXCEPT, opt("(", constantExpression, ")"));
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy