/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ /* * parser.yy - BISON grammar for IDLC 1.0 */ %{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "attributeexceptions.hxx" #include #include #include #include #define YYDEBUG 1 #define YYERROR_VERBOSE 1 using ::rtl::OUString; using ::rtl::OString; using ::rtl::OStringToOUString; using ::rtl::OStringBuffer; extern int yylex(void); void yyerror(char const *); void checkIdentifier(::rtl::OString const * id) { static short check = 0; if (check == 0) { if (idlc()->getOptions()->isValid("-cid")) check = 1; else check = 2; } if ( id->indexOf('_') >= 0 ) if ( (id->pData->buffer[0] >= 97 && id->pData->buffer[0] <= 122) || id->pData->buffer[0] == '_') { if (check == 1) { ::rtl::OStringBuffer msg(25 + id->getLength()); msg.append("mismatched identifier '"); msg.append(*id); msg.append("'"); ErrorHandler::syntaxError(idlc()->getParseState(), idlc()->getLineNumber(), msg.getStr()); } else ErrorHandler::warning0(WarningCode::WrongNamingConvention, id->getStr()); } } void reportDoubleMemberDeclarations( AstInterface::DoubleMemberDeclarations const & doubleMembers) { for (auto const& doubleMember : doubleMembers) { ErrorHandler::error2(ErrorCode::DoubleMember, doubleMember.first, doubleMember.second); } } void addInheritedInterface( AstInterface * ifc, rtl::OString const & name, bool optional, rtl::OUString const & documentation) { AstDeclaration * decl = ifc->lookupByName(name); AstDeclaration const * resolved = resolveTypedefs(decl); if (resolved != nullptr && resolved->getNodeType() == NT_interface) { if (ErrorHandler::checkPublished(decl)) { if (!static_cast< AstInterface const * >(resolved)->isDefined()) { ErrorHandler::inheritanceError( NT_interface, &ifc->getScopedName(), decl); } else { AstInterface::DoubleDeclarations doubleDecls( ifc->checkInheritedInterfaceClashes( static_cast< AstInterface const * >(resolved), optional)); if (doubleDecls.interfaces.empty() && doubleDecls.members.empty()) { ifc->addInheritedInterface( static_cast< AstType * >(decl), optional, documentation); } else { for (auto const& elem : doubleDecls.interfaces) { ErrorHandler::error1( ErrorCode::DoubleInheritance, elem); } reportDoubleMemberDeclarations(doubleDecls.members); } } } } else { ErrorHandler::lookupError( ErrorCode::InterfaceMemberLookup, name, scopeAsDecl(ifc)); } } AstDeclaration const * createNamedType( rtl::OString const * scopedName, DeclList const * typeArgs) { AstDeclaration * decl = idlc()->scopes()->topNonNull()->lookupByName( *scopedName); AstDeclaration const * resolved = resolveTypedefs(decl); if (decl == nullptr) { ErrorHandler::lookupError(*scopedName); } else if (!ErrorHandler::checkPublished(decl)) { decl = nullptr; } else if (resolved->getNodeType() == NT_struct) { if (static_cast< AstStruct const * >(resolved)->getTypeParameterCount() != (typeArgs == nullptr ? 0 : typeArgs->size())) { ErrorHandler::error0(ErrorCode::WrongNumberOfTypeArguments); decl = nullptr; } else if (typeArgs != nullptr) { AstScope * global = idlc()->scopes()->bottom(); AstDeclaration * inst = new AstStructInstance( static_cast< AstType * >(decl), typeArgs, global); decl = global->addDeclaration(inst); if (decl != inst) { delete inst; } } } else if (decl->isType()) { if (typeArgs != nullptr) { ErrorHandler::error0(ErrorCode::WrongNumberOfTypeArguments); decl = nullptr; } } else { ErrorHandler::noTypeError(decl); decl = nullptr; } delete scopedName; delete typeArgs; return decl; } bool includes(AstDeclaration const * type1, AstDeclaration const * type2) { OSL_ASSERT(type2 != nullptr); if (type1 != nullptr) { if (type1->getNodeType() == NT_instantiated_struct) { AstStructInstance const * inst = static_cast< AstStructInstance const * >(type1); if (inst->getTypeTemplate() == type2) { return true; } for (DeclList::const_iterator i(inst->getTypeArgumentsBegin()); i != inst->getTypeArgumentsEnd(); ++i) { if (includes(*i, type2)) { return true; } } } else if (type1 == type2) { return true; } } return false; } // Suppress any warnings from generated code: #if defined _MSC_VER #pragma warning(disable: 4702) // unreachable code #endif %} /* * Declare the type of values in the grammar */ %union { ExprType etval; /* Expression type */ AstDeclaration* dclval; /* Declaration */ AstDeclaration const * cdclval; DeclList * dclsval; AstExpression* exval; /* expression value */ FeDeclarator* fdval; /* declarator value */ FeDeclList* dlval; /* declarator list value */ FeInheritanceHeader* ihval; /* inheritance header value */ ::rtl::OString* sval; /* OString value */ std::vector< rtl::OString > * svals; sal_Char* strval; /* sal_Char* value */ bool bval; /* sal_Boolean* value */ sal_Int64 ival; /* sal_Int64 value */ sal_uInt64 uval; /* sal_uInt64 value */ sal_uInt32 ulval; /* sal_uInt32 value */ double dval; /* double value */ float fval; /* float value */ std::list< OString >* slval; /* StringList value */ AttributeExceptions::Part attexcpval; AttributeExceptions attexcval; } /* * Token types: These are returned by the lexer */ %token IDL_IDENTIFIER %token IDL_ATTRIBUTE %token IDL_BOUND %token IDL_CONST %token IDL_CONSTANTS %token IDL_CONSTRAINED %token IDL_ENUM %token IDL_EXCEPTION %token IDL_INTERFACE %token IDL_MAYBEAMBIGUOUS %token IDL_MAYBEDEFAULT %token IDL_MAYBEVOID %token IDL_MODULE %token IDL_NEEDS %token IDL_OBSERVES %token IDL_OPTIONAL %token IDL_PROPERTY %token IDL_RAISES %token IDL_READONLY %token IDL_REMOVABLE %token IDL_SERVICE %token IDL_SEQUENCE %token IDL_SINGLETON %token IDL_STRUCT %token IDL_TYPEDEF %token IDL_TRANSIENT %token IDL_ANY %token IDL_CHAR %token IDL_BOOLEAN %token IDL_BYTE %token IDL_DOUBLE %token IDL_FLOAT %token IDL_HYPER %token IDL_LONG %token IDL_SHORT %token IDL_VOID %token IDL_STRING %token IDL_TYPE %token IDL_UNSIGNED %token IDL_TRUE %token IDL_FALSE %token IDL_IN %token IDL_OUT %token IDL_INOUT %token IDL_GET %token IDL_SET %token IDL_PUBLISHED %token IDL_ELLIPSIS %token IDL_LEFTSHIFT %token IDL_RIGHTSHIFT %token IDL_SCOPESEPARATOR %token IDL_INTEGER_LITERAL %token IDL_INTEGER_ULITERAL %token IDL_FLOATING_PT_LITERAL /* * These are production names: */ %type type_dcl %type exception_name %type constructed_type_spec enum_type op_type_spec %type sequence_type_spec simple_type_spec struct_type %type type_spec %type fundamental_type type_arg type_or_parameter %type opt_raises raises exception_list %type opt_attribute_get_raises attribute_get_raises %type opt_attribute_set_raises attribute_set_raises %type opt_type_args type_args %type identifier %type interface_decl %type scoped_name inheritance_spec %type scoped_names at_least_one_scoped_name %type const_type integer_type char_type boolean_type %type floating_pt_type any_type signed_int string_type %type unsigned_int base_type_spec byte_type type_type %type expression const_expr or_expr xor_expr and_expr %type add_expr mult_expr unary_expr primary_expr shift_expr %type literal %type declarator %type declarators at_least_one_declarator %type exception_header structure_header interfaceheader %type flag_header opt_attrflags opt_attrflag %type direction service_interface_header service_service_header %type optional_inherited_interface opt_rest opt_service_body %type opt_attribute_block attribute_block_rest opt_attribute_raises %type opt_type_params type_params %% /* * Grammar start here */ start : definitions; definitions : definition definitions | /* EMPTY */ ; definition : opt_published publishable_definition | module_dcl { idlc()->setParseState(PS_ModuleDeclSeen); } ';' { idlc()->setParseState(PS_NoState); } | error ';' { yyerror("definitions"); yyerrok; } ; opt_published: IDL_PUBLISHED { idlc()->setPublished(true); } | /* empty */ { idlc()->setPublished(false); } ; publishable_definition: type_dcl { idlc()->setParseState(PS_TypeDeclSeen); } ';' { idlc()->setParseState(PS_NoState); } | exception_dcl { idlc()->setParseState(PS_ExceptionDeclSeen); } ';' { idlc()->setParseState(PS_NoState); } | interface { idlc()->setParseState(PS_InterfaceDeclSeen); } ';' { idlc()->setParseState(PS_NoState); } | service_dcl { idlc()->setParseState(PS_ServiceDeclSeen); } ';' { idlc()->setParseState(PS_NoState); } | singleton_dcl { idlc()->setParseState(PS_SingletonDeclSeen); } ';' { idlc()->setParseState(PS_NoState); } | constants_dcl { idlc()->setParseState(PS_ConstantsDeclSeen); } ';' { idlc()->setParseState(PS_NoState); } ; module_dcl : IDL_MODULE { idlc()->setParseState(PS_ModuleSeen); idlc()->setPublished(false); } identifier { idlc()->setParseState(PS_ModuleIDSeen); checkIdentifier($3); AstScope* pScope = idlc()->scopes()->topNonNull(); AstModule* pModule = nullptr; if ( pScope ) { pModule = new AstModule(*$3, pScope); if( AstDeclaration* pExists = pScope->lookupForAdd(pModule) ) { pExists->setInMainfile(idlc()->isInMainFile()); pExists->setFileName(pModule->getFileName()); if (pExists->isPredefined()) { pExists->setPredefined(false); if (pExists->getDocumentation().getLength() == 0 && pModule->getDocumentation().getLength() > 0) { pExists->setDocumentation(pModule->getDocumentation()); } } delete(pModule); pModule = static_cast(pExists); } else { pScope->addDeclaration(pModule); } idlc()->scopes()->push(pModule); } delete $3; } '{' { idlc()->setParseState(PS_ModuleSqSeen); } definitions { idlc()->setParseState(PS_ModuleBodySeen); } '}' { idlc()->setParseState(PS_ModuleQsSeen); /* * Finished with this module - pop it from the scope stack */ idlc()->scopes()->pop(); } ; interface : interface_dcl | forward_dcl ; interface_decl : IDL_INTERFACE { idlc()->setParseState(PS_InterfaceSeen); } identifier { idlc()->setParseState(PS_InterfaceIDSeen); checkIdentifier($3); $$ = $3; } ; forward_dcl : interface_decl { idlc()->setParseState(PS_ForwardDeclSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstInterface* pForward = nullptr; AstDeclaration* pDecl = nullptr; /* * Make a new forward interface node and add it to its enclosing scope */ if ( pScope && $1 ) { pForward = new AstInterface(*$1, nullptr, pScope); pDecl = pScope->lookupByName(pForward->getScopedName()); if ( pDecl ) { if ( (pDecl != pForward) && (pDecl->getNodeType() == NT_interface) ) { delete pForward; } else { ErrorHandler::error2(ErrorCode::RedefScope, scopeAsDecl(pScope), pDecl); } } else { /* * Add the interface to its definition scope */ pScope->addDeclaration(pForward); } } delete $1; } ; interface_dcl : interfaceheader { idlc()->setParseState(PS_InterfaceHeadSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstInterface* pInterface = nullptr; AstInterface* pForward = nullptr; /* * Make a new interface node and add it to its enclosing scope */ if ( pScope && $1 ) { pInterface = new AstInterface( *$1->getName(), static_cast< AstInterface const * >(resolveTypedefs($1->getInherits())), pScope); if ( AstDeclaration* pDecl = pScope->lookupByName(pInterface->getScopedName()) ) { /* * See if we're defining a forward declared interface. */ if (pDecl->getNodeType() == NT_interface) { pForward = static_cast(pDecl); if ( !pForward->isDefined() ) { /* * Check if redefining in same scope */ if ( pForward->getScope() != pScope ) { if ( pForward->getScopedName() != pInterface->getScopedName() ) { ErrorHandler::error3(ErrorCode::ScopeConflict, pInterface, pForward, scopeAsDecl(pScope)); } } else if ( !pInterface->isPublished() && pForward->isPublished() ) { ErrorHandler::error0(ErrorCode::PublishedForward); } /* * All OK, set full definition */ else { pForward->forwardDefined(*pInterface); delete pInterface; pInterface = pForward; } } else { // special handling for XInterface because it is predefined if ( pForward->isPredefined() && pForward->getScopedName() == "com::sun::star::uno::XInterface") { /* replace the predefined XInterface */ *pForward = *pInterface; delete pInterface; pInterface = pForward; } } } } else { /* * Add the interface to its definition scope */ pScope->addDeclaration(pInterface); } } /* * Push it on the scope stack */ idlc()->scopes()->push(pInterface); delete $1; } '{' { idlc()->setParseState(PS_InterfaceSqSeen); } exports { AstInterface * ifc = static_cast< AstInterface * >( idlc()->scopes()->topNonNull()); if (!ifc->hasMandatoryInheritedInterfaces() && ifc->getScopedName() != "com::sun::star::uno::XInterface") { addInheritedInterface( ifc, rtl::OString("::com::sun::star::uno::XInterface"), false, rtl::OUString()); } ifc->setDefined(); idlc()->setParseState(PS_InterfaceBodySeen); } '}' { idlc()->setParseState(PS_InterfaceQsSeen); /* * Done with this interface - pop it off the scopes stack */ idlc()->scopes()->pop(); } | error '}' { yyerror("interface definition"); yyerrok; } ; interfaceheader : interface_decl inheritance_spec { idlc()->setParseState(PS_InheritSpecSeen); $$ = new FeInheritanceHeader(NT_interface, $1, $2, nullptr); delete $2; } ; inheritance_spec : ':' { idlc()->setParseState(PS_InheritColonSeen); } scoped_name { $$ = $3; } | /* EMPTY */ { $$ = nullptr; } ; exports : exports export | /* EMPTY */ ; export : attribute { idlc()->setParseState(PS_AttributeDeclSeen); } ';' { idlc()->setParseState(PS_NoState); } | operation { idlc()->setParseState(PS_OperationDeclSeen); } ';' { idlc()->setParseState(PS_NoState); } | interface_inheritance_decl { idlc()->setParseState(PS_InterfaceInheritanceDeclSeen); } ';' { idlc()->setParseState(PS_NoState); } ; attribute : flag_header simple_type_spec { idlc()->setParseState(PS_AttrTypeSeen); } declarator { idlc()->setParseState(PS_AttrCompleted); if (($1 & ~(AF_BOUND | AF_READONLY)) != AF_ATTRIBUTE) { ErrorHandler::flagError(ErrorCode::BadAttributeFlags, $1); } AstInterface * scope = static_cast< AstInterface * >( idlc()->scopes()->top()); AstAttribute * attr = new AstAttribute( $1, FeDeclarator::compose($2), $4->getName(), scope); delete $4; AstInterface::DoubleMemberDeclarations doubleMembers( scope->checkMemberClashes(attr)); if (doubleMembers.empty()) { scope->addMember(attr); } else { reportDoubleMemberDeclarations(doubleMembers); } idlc()->scopes()->push(attr); } opt_attribute_block { static_cast< AstAttribute * >(idlc()->scopes()->top())->setExceptions( $6.get.documentation, $6.get.exceptions, $6.set.documentation, $6.set.exceptions); delete $6.get.documentation; delete $6.get.exceptions; delete $6.set.documentation; delete $6.set.exceptions; idlc()->scopes()->pop(); } ; flag_header : '[' opt_attrflags ']' { idlc()->setParseState(PS_FlagHeaderSeen); $$ = $2; } ; opt_attrflags : opt_attrflags ',' opt_attrflag { if ( ($1 & $3) == $3 ) ErrorHandler::flagError(ErrorCode::DefinedAttributeFlag, $3); $$ = $1 | $3; } | opt_attrflag { $$ = $1; } ; opt_attrflag : IDL_ATTRIBUTE { idlc()->setParseState(PS_AttrSeen); $$ = AF_ATTRIBUTE; } | IDL_PROPERTY { idlc()->setParseState(PS_PropertySeen); $$ = AF_PROPERTY; } | IDL_READONLY { idlc()->setParseState(PS_ReadOnlySeen); $$ = AF_READONLY; } | IDL_OPTIONAL { idlc()->setParseState(PS_OptionalSeen); $$ = AF_OPTIONAL; } | IDL_MAYBEVOID { idlc()->setParseState(PS_MayBeVoidSeen); $$ = AF_MAYBEVOID; } | IDL_BOUND { idlc()->setParseState(PS_BoundSeen); $$ = AF_BOUND; } | IDL_CONSTRAINED { idlc()->setParseState(PS_ConstrainedSeen); $$ = AF_CONSTRAINED; } | IDL_TRANSIENT { idlc()->setParseState(PS_TransientSeen); $$ = AF_TRANSIENT; } | IDL_MAYBEAMBIGUOUS { idlc()->setParseState(PS_MayBeAmbigiousSeen); $$ = AF_MAYBEAMBIGUOUS; } | IDL_MAYBEDEFAULT { idlc()->setParseState(PS_MayBeDefaultSeen); $$ = AF_MAYBEDEFAULT; } | IDL_REMOVABLE { idlc()->setParseState(PS_RemoveableSeen); $$ = AF_REMOVABLE; } | error ']' { yyerror("unknown property|attribute flag"); yyerrok; } ; opt_attribute_block: '{' attribute_block_rest { $$ = $2; } | /* empty */ { $$.get.documentation = nullptr; $$.get.exceptions = nullptr; $$.set.documentation = nullptr; $$.set.exceptions = nullptr; } ; attribute_block_rest: opt_attribute_raises '}' | error '}' { yyerror("bad attribute raises block"); yyerrok; $$.get.documentation = nullptr; $$.get.exceptions = nullptr; $$.set.documentation = nullptr; $$.set.exceptions = nullptr; } ; opt_attribute_raises: attribute_get_raises opt_attribute_set_raises { $$.get = $1; $$.set = $2; } | attribute_set_raises opt_attribute_get_raises { $$.get = $2; $$.set = $1; } | /* empty */ { $$.get.documentation = nullptr; $$.get.exceptions = nullptr; $$.set.documentation = nullptr; $$.set.exceptions = nullptr; } ; opt_attribute_get_raises: attribute_get_raises | /* empty */ { $$.documentation = nullptr; $$.exceptions = nullptr; } ; attribute_get_raises: IDL_GET raises ';' { $$.documentation = new rtl::OUString( rtl::OStringToOUString( idlc()->getDocumentation(), RTL_TEXTENCODING_UTF8)); $$.exceptions = $2; } ; opt_attribute_set_raises: attribute_set_raises | /* empty */ { $$.documentation = nullptr; $$.exceptions = nullptr; } ; attribute_set_raises: IDL_SET { if (static_cast< AstAttribute * >(idlc()->scopes()->top())-> isReadonly()) { ErrorHandler::error0(ErrorCode::ReadOnlyAttributeSetExceptions); } } raises ';' { $$.documentation = new rtl::OUString( rtl::OStringToOUString( idlc()->getDocumentation(), RTL_TEXTENCODING_UTF8)); $$.exceptions = $3; } ; operation : op_type_spec { idlc()->setParseState(PS_OpTypeSeen); } identifier { idlc()->setParseState(PS_OpIDSeen); checkIdentifier($3); AstInterface * pScope = static_cast< AstInterface * >( idlc()->scopes()->top()); AstOperation* pOp = nullptr; /* * Create a node representing an operation on an interface * and add it to its enclosing scope */ if ( pScope && $1 ) { AstType const *pType = static_cast($1); if ( !pType || (pType->getNodeType() == NT_exception) ) { // type ERROR } else { pOp = new AstOperation(pType, *$3, pScope); AstInterface::DoubleMemberDeclarations doubleMembers( pScope->checkMemberClashes(pOp)); if (doubleMembers.empty()) { pScope->addMember(pOp); } else { reportDoubleMemberDeclarations(doubleMembers); } } } delete $3; /* * Push the operation scope onto the scopes stack */ idlc()->scopes()->push(pOp); } '(' { idlc()->setParseState(PS_OpSqSeen); } parameters { idlc()->setParseState(PS_OpParsCompleted); } ')' { idlc()->setParseState(PS_OpQsSeen); } opt_raises { AstScope* pScope = idlc()->scopes()->topNonNull(); AstOperation* pOp = nullptr; /* * Add exceptions and context to the operation */ if ( pScope && pScope->getScopeNodeType() == NT_operation) { pOp = static_cast(pScope); if ( pOp ) pOp->setExceptions($11); } delete $11; /* * Done with this operation. Pop its scope from the scopes stack */ idlc()->scopes()->pop(); } ; op_type_spec : simple_type_spec | IDL_VOID { $$ = idlc()->scopes()->bottom()->lookupPrimitiveType(ET_void); } ; parameters : parameter | parameters ',' { idlc()->setParseState(PS_OpParCommaSeen); } parameter | /* EMPTY */ | error ',' { yyerror("parameter definition"); yyerrok; } ; parameter : '[' direction ']' { idlc()->setParseState(PS_OpParDirSeen); } simple_type_spec { idlc()->setParseState(PS_OpParTypeSeen); } opt_rest declarator { idlc()->setParseState(PS_OpParDeclSeen); AstOperation * pScope = static_cast< AstOperation * >( idlc()->scopes()->top()); AstParameter* pParam = nullptr; /* * Create a node representing an argument to an operation * Add it to the enclosing scope (the operation scope) */ if ( pScope && $5 && $8 ) { AstType const * pType = FeDeclarator::compose($5); if ( pType ) { if (pScope->isConstructor() && $2 != DIR_IN) { ErrorHandler::error0(ErrorCode::ConstructorParameterNotIn); } if (pScope->isVariadic()) { ErrorHandler::error0(ErrorCode::RestParameterNotLast); } if ($7) { AstDeclaration const * type = resolveTypedefs(pType); if (type->getNodeType() != NT_predefined || (static_cast< AstBaseType const * >(type)-> getExprType() != ET_any)) { ErrorHandler::error0(ErrorCode::RestParameterNotAny); } if (pScope->isConstructor()) { if (pScope->getIteratorBegin() != pScope->getIteratorEnd()) { ErrorHandler::error0( ErrorCode::ConstructorRestParameterNotFirst); } } else { ErrorHandler::error0(ErrorCode::MethodHasRestParameter); } } pParam = new AstParameter( static_cast< Direction >($2), $7, pType, $8->getName(), pScope); if ( !$8->checkType($5) ) { // WARNING } pScope->addDeclaration(pParam); } } } | error simple_type_spec { idlc()->setParseState(PS_NoState); yyerrok; } ; direction : IDL_IN { $$ = DIR_IN; } | IDL_OUT { $$ = DIR_OUT; } | IDL_INOUT { $$ = DIR_INOUT; } ; opt_rest: IDL_ELLIPSIS { $$ = true; } | /* empty */ { $$ = false; } ; opt_raises: raises | /* empty */ { $$ = nullptr; } ; raises: IDL_RAISES { idlc()->setParseState(PS_RaiseSeen); } '(' { idlc()->setParseState(PS_RaiseSqSeen); } exception_list ')' { idlc()->setParseState(PS_RaiseQsSeen); $$ = $5; } ; exception_list: exception_name { $$ = new DeclList; $$->push_back($1); } | exception_list ',' exception_name { $1->push_back($3); $$ = $1; } ; exception_name: scoped_name { // The topmost scope is either an AstOperation (for interface methods // and service constructors) or an AstAttribute (for interface // attributes), so look up exception names in the next-to-topmost scope: AstDeclaration * decl = idlc()->scopes()->nextToTop()->lookupByName( *$1); if (decl == nullptr) { ErrorHandler::lookupError(*$1); } else if (!ErrorHandler::checkPublished(decl)) { decl = nullptr; } else if (decl->getNodeType() != NT_exception) { ErrorHandler::error1(ErrorCode::IllegalRaises, decl); decl = nullptr; } delete $1; $$ = decl; } ; interface_inheritance_decl: optional_inherited_interface IDL_INTERFACE { idlc()->setParseState(PS_ServiceIFHeadSeen); } scoped_name { AstInterface * ifc = static_cast< AstInterface * >( idlc()->scopes()->top()); if (ifc->usesSingleInheritance()) { ErrorHandler::error0(ErrorCode::MixedInheritance); } else { addInheritedInterface( ifc, *$4, $1, rtl::OStringToOUString( idlc()->getDocumentation(), RTL_TEXTENCODING_UTF8)); } delete $4; } ; optional_inherited_interface: '[' IDL_OPTIONAL ']' { $$ = true; } | /* EMPTY */ { $$ = false; } ; constants_exports : constants_export constants_exports | /* EMPTY */ ; constants_export : IDL_CONST { idlc()->setParseState(PS_ConstSeen); } const_type { idlc()->setParseState(PS_ConstTypeSeen); } identifier { idlc()->setParseState(PS_ConstIDSeen); checkIdentifier($5); } '=' { idlc()->setParseState(PS_ConstAssignSeen); } expression { idlc()->setParseState(PS_ConstExprSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstConstant* pConstant = nullptr; if ( $9 && pScope ) { if ( !$9->coerce($3) ) { ErrorHandler::coercionError($9, $3); } else { pConstant = new AstConstant($3, $9, *$5, pScope); pScope->addDeclaration(pConstant); } } delete $5; idlc()->setParseState(PS_ConstantDeclSeen); } ';' {}; ; constants_dcl : IDL_CONSTANTS { idlc()->setParseState(PS_ConstantsSeen); } identifier { idlc()->setParseState(PS_ConstantsIDSeen); checkIdentifier($3); } '{' { idlc()->setParseState(PS_ConstantsSqSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstConstants* pConstants = nullptr; if ( pScope ) { pConstants = new AstConstants(*$3, pScope); if( AstDeclaration* pExists = pScope->lookupForAdd(pConstants) ) { pExists->setInMainfile(idlc()->isInMainFile()); delete(pConstants); pConstants = static_cast(pExists); } else { pScope->addDeclaration(pConstants); } idlc()->scopes()->push(pConstants); } delete $3; } constants_exports { idlc()->setParseState(PS_ConstantsBodySeen); } '}' { idlc()->setParseState(PS_ConstantsQsSeen); /* * Finished with this constants - pop it from the scope stack */ idlc()->scopes()->pop(); } ; expression : const_expr ; const_expr : or_expr ; or_expr : xor_expr | or_expr '|' xor_expr { $$ = new AstExpression(ExprComb::Or, $1, $3); } ; xor_expr : and_expr | xor_expr '^' and_expr { $$ = new AstExpression(ExprComb::Xor, $1, $3); } ; and_expr : shift_expr | and_expr '&' shift_expr { $$ = new AstExpression(ExprComb::And, $1, $3); } ; shift_expr : add_expr | shift_expr IDL_LEFTSHIFT add_expr { $$ = new AstExpression(ExprComb::Left, $1, $3); } | shift_expr IDL_RIGHTSHIFT add_expr { $$ = new AstExpression(ExprComb::Right, $1, $3); } ; add_expr : mult_expr | add_expr '+' mult_expr { $$ = new AstExpression(ExprComb::Add, $1, $3); } | add_expr '-' mult_expr { $$ = new AstExpression(ExprComb::Minus, $1, $3); } ; mult_expr : unary_expr | mult_expr '*' unary_expr { $$ = new AstExpression(ExprComb::Mul, $1, $3); } | mult_expr '/' unary_expr { $$ = new AstExpression(ExprComb::Div, $1, $3); } | mult_expr '%' unary_expr { $$ = new AstExpression(ExprComb::Mod, $1, $3); } ; unary_expr : primary_expr | '+' primary_expr { $$ = new AstExpression(ExprComb::UPlus, $2, nullptr); } | '-' primary_expr { $$ = new AstExpression(ExprComb::UMinus, $2, nullptr); } | '~' primary_expr { } ; primary_expr : scoped_name { /* * An expression which is a scoped name is not resolved now, * but only when it is evaluated (such as when it is assigned * as a constant value) */ $$ = new AstExpression($1); } | literal | '(' const_expr ')' { $$ = $2; } ; literal : IDL_INTEGER_LITERAL { $$ = new AstExpression($1); } | IDL_INTEGER_ULITERAL { $$ = new AstExpression($1); } | IDL_FLOATING_PT_LITERAL { $$ = new AstExpression($1); } | IDL_TRUE { $$ = new AstExpression(sal_Int32(1), ET_boolean); } | IDL_FALSE { $$ = new AstExpression(sal_Int32(0), ET_boolean); } ; const_type : integer_type | byte_type | boolean_type | floating_pt_type | scoped_name { AstScope* pScope = idlc()->scopes()->topNonNull(); AstDeclaration const * type = nullptr; /* * If the constant's type is a scoped name, it must resolve * to a scalar constant type */ if ( pScope && (type = pScope->lookupByName(*$1)) ) { if (!ErrorHandler::checkPublished(type)) { type = nullptr; $$ = ET_none; } else { type = resolveTypedefs(type); if (type->getNodeType() == NT_predefined) { $$ = static_cast< AstBaseType const * >(type)-> getExprType(); } else $$ = ET_any; } } else $$ = ET_any; } ; exception_header : IDL_EXCEPTION { idlc()->setParseState(PS_ExceptSeen); } identifier { idlc()->setParseState(PS_ExceptIDSeen); checkIdentifier($3); } inheritance_spec { idlc()->setParseState(PS_InheritSpecSeen); $$ = new FeInheritanceHeader(NT_exception, $3, $5, nullptr); delete $5; } ; exception_dcl : exception_header { idlc()->setParseState(PS_ExceptHeaderSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstException* pExcept = nullptr; if ( pScope ) { AstException* pBase = static_cast< AstException* >( $1->getInherits()); pExcept = new AstException(*$1->getName(), pBase, pScope); pScope->addDeclaration(pExcept); } /* * Push the scope of the exception on the scopes stack */ idlc()->scopes()->push(pExcept); delete $1; } '{' { idlc()->setParseState(PS_ExceptSqSeen); } members { idlc()->setParseState(PS_ExceptBodySeen); } '}' { idlc()->setParseState(PS_ExceptQsSeen); /* this exception is finished, pop its scope from the stack */ idlc()->scopes()->pop(); } ; property : flag_header simple_type_spec { idlc()->setParseState(PS_PropertyTypeSeen); } at_least_one_declarator { idlc()->setParseState(PS_PropertyCompleted); AstScope* pScope = idlc()->scopes()->topNonNull(); AstAttribute* pAttr = nullptr; FeDeclList* pList = $4; FeDeclarator* pDecl = nullptr; AstType const * pType = nullptr; if ( pScope->getScopeNodeType() == NT_singleton ) { ErrorHandler::error0(ErrorCode::IllegalAdd); } else { if ( ($1 & AF_ATTRIBUTE) == AF_ATTRIBUTE ) ErrorHandler::flagError(ErrorCode::WrongAttributeKeyword, AF_ATTRIBUTE); if ( ($1 & AF_PROPERTY) != AF_PROPERTY ) ErrorHandler::flagError(ErrorCode::MissingAttributeKeyword, AF_PROPERTY); /* * Create nodes representing attributes and add them to the * enclosing scope */ if ( pScope && $2 && pList ) { FeDeclList::iterator iter = pList->begin(); FeDeclList::iterator end = pList->end(); while (iter != end) { pDecl = (*iter); if ( !pDecl ) { ++iter; continue; } pType = FeDeclarator::compose($2); if ( !pType ) { ++iter; continue; } pAttr = new AstAttribute(NT_property, $1, pType, pDecl->getName(), pScope); pScope->addDeclaration(pAttr); ++iter; delete pDecl; } } } if ( pList ) delete pList; } | error ';' { yyerror("property"); yyerrok; } ; service_exports : service_exports service_export | /* EMPTY */ ; service_export : service_interface_header at_least_one_scoped_name ';' { idlc()->setParseState(PS_ServiceMemberSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstDeclaration* pDecl = nullptr; AstInterfaceMember* pIMember = nullptr; if ( pScope->getScopeNodeType() == NT_singleton ) { ErrorHandler::error0(ErrorCode::IllegalAdd); } else { /* * Create a node representing a class member. * Store it in the enclosing scope */ if ( pScope && $2 ) { for (auto const& elem : *($2)) { pDecl = pScope->lookupByName(elem); if ( pDecl && (pDecl->getNodeType() == NT_interface) ) { /* we relax the strict published check and allow to add new * interfaces if they are optional */ bool bOptional = (($1 & AF_OPTIONAL) == AF_OPTIONAL); if ( ErrorHandler::checkPublished(pDecl, bOptional) ) { pIMember = new AstInterfaceMember( $1, static_cast(pDecl), elem, pScope); pScope->addDeclaration(pIMember); } } else { ErrorHandler::lookupError(ErrorCode::InterfaceMemberLookup, elem, scopeAsDecl(pScope)); } } } } delete $2; } | service_service_header at_least_one_scoped_name ';' { idlc()->setParseState(PS_ServiceMemberSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstDeclaration* pDecl = nullptr; AstServiceMember* pSMember = nullptr; /* * Create a node representing a class member. * Store it in the enclosing scope */ if ( pScope && $2 ) { for (auto const& elem : *($2)) { pDecl = pScope->lookupByName(elem); if ( pDecl && (pDecl->getNodeType() == NT_service) ) { if ( static_cast< AstService * >(pDecl)->isSingleInterfaceBasedService() || (pScope->getScopeNodeType() == NT_singleton && pScope->nMembers() > 0) ) ErrorHandler::error0(ErrorCode::IllegalAdd); else if ( ErrorHandler::checkPublished(pDecl) ) { pSMember = new AstServiceMember( $1, static_cast(pDecl), elem, pScope); pScope->addDeclaration(pSMember); } } else { ErrorHandler::lookupError(ErrorCode::ServiceMemberLookup, elem, scopeAsDecl(pScope)); } } } delete $2; } | IDL_OBSERVES at_least_one_scoped_name ';' { idlc()->setParseState(PS_ServiceMemberSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstDeclaration* pDecl = nullptr; AstObserves* pObserves = nullptr; if ( pScope->getScopeNodeType() == NT_singleton ) { ErrorHandler::error0(ErrorCode::IllegalAdd); } else { /* * Create a node representing a class member. * Store it in the enclosing scope */ if ( pScope && $2 ) { for (auto const& elem : *($2)) { pDecl = pScope->lookupByName(elem); if ( pDecl && (pDecl->getNodeType() == NT_interface) ) { pObserves = new AstObserves(static_cast(pDecl), elem, pScope); pScope->addDeclaration(pObserves); } else { ErrorHandler::lookupError(ErrorCode::InterfaceMemberLookup, elem, scopeAsDecl(pScope)); } } } } delete $2; } | IDL_NEEDS at_least_one_scoped_name ';' { idlc()->setParseState(PS_ServiceMemberSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstDeclaration* pDecl = nullptr; AstNeeds* pNeeds = nullptr; if ( pScope->getScopeNodeType() == NT_singleton ) { ErrorHandler::error0(ErrorCode::IllegalAdd); } else { /* * Create a node representing a class member. * Store it in the enclosing scope */ if ( pScope && $2 ) { for (auto const& elem : *($2)) { pDecl = pScope->lookupByName(elem); if ( pDecl && (pDecl->getNodeType() == NT_service) ) { pNeeds = new AstNeeds(static_cast(pDecl), elem, pScope); pScope->addDeclaration(pNeeds); } else { ErrorHandler::lookupError(ErrorCode::ServiceMemberLookup, elem, scopeAsDecl(pScope)); } } } } delete $2; } | property ';' { idlc()->setParseState(PS_PropertyDeclSeen); } ; service_interface_header : IDL_INTERFACE { idlc()->setParseState(PS_ServiceIFHeadSeen); $$ = AF_INVALID; } | flag_header IDL_INTERFACE { idlc()->setParseState(PS_ServiceIFHeadSeen); if ( (AF_OPTIONAL != $1) && ( AF_INVALID != $1) ) ErrorHandler::flagError(ErrorCode::ExpectedOptional, $1); $$ = $1; } ; service_service_header : IDL_SERVICE { idlc()->setParseState(PS_ServiceSHeadSeen); $$ = AF_INVALID; } | flag_header IDL_SERVICE { idlc()->setParseState(PS_ServiceSHeadSeen); if ( (AF_OPTIONAL != $1) && ( AF_INVALID != $1) ) ErrorHandler::flagError(ErrorCode::ExpectedOptional, $1); $$ = $1; } ; service_dcl : IDL_SERVICE { idlc()->setParseState(PS_ServiceSeen); } identifier { idlc()->setParseState(PS_ServiceIDSeen); checkIdentifier($3); AstScope* pScope = idlc()->scopes()->topNonNull(); AstService* pService = nullptr; /* * Make a new service and add it to the enclosing scope */ if (pScope != nullptr) { pService = new AstService(*$3, pScope); pScope->addDeclaration(pService); } delete $3; /* * Push it on the stack */ idlc()->scopes()->push(pService); } service_dfn { /* this service is finished, pop its scope from the stack */ idlc()->scopes()->pop(); } ; service_dfn: service_interface_dfn | service_obsolete_dfn ; service_interface_dfn: ':' scoped_name { AstScope * scope = idlc()->scopes()->nextToTop(); // skip the scope pushed by service_dcl AstDeclaration * decl = scope->lookupByName(*$2); if (decl != nullptr && resolveTypedefs(decl)->getNodeType() == NT_interface) { if (ErrorHandler::checkPublished(decl)) { idlc()->scopes()->top()->addDeclaration(decl); } } else { ErrorHandler::lookupError( ErrorCode::InterfaceMemberLookup, *$2, scopeAsDecl(scope)); } delete $2; } opt_service_body { AstService * s = static_cast< AstService * >(idlc()->scopes()->top()); if (s != nullptr) { s->setSingleInterfaceBasedService(); s->setDefaultConstructor(!$4); } } ; opt_service_body: service_body { $$ = true; } | /* empty */ { $$ = false; } ; service_body: '{' constructors '}' ; constructors: constructors constructor | /* empty */ ; constructor: identifier { checkIdentifier($1); AstScope * scope = idlc()->scopes()->top(); AstOperation * ctor = new AstOperation(nullptr, *$1, scope); delete $1; scope->addDeclaration(ctor); idlc()->scopes()->push(ctor); } '(' parameters ')' opt_raises { static_cast< AstOperation * >(idlc()->scopes()->top())->setExceptions( $6); delete $6; idlc()->scopes()->pop(); if (static_cast< AstService * >(idlc()->scopes()->top())-> checkLastConstructor()) { ErrorHandler::error0(ErrorCode::SimilarConstructors); } } ';' ; singleton_dcl : IDL_SINGLETON { idlc()->setParseState(PS_SingletonSeen); } identifier { idlc()->setParseState(PS_SingletonIDSeen); checkIdentifier($3); AstScope* pScope = idlc()->scopes()->topNonNull(); AstService* pService = nullptr; /* * Make a new service and add it to the enclosing scope */ if (pScope != nullptr) { pService = new AstService(NT_singleton, *$3, pScope); pScope->addDeclaration(pService); } delete $3; /* * Push it on the stack */ idlc()->scopes()->push(pService); } singleton_dfn { /* this singelton is finished, pop its scope from the stack */ idlc()->scopes()->pop(); } ; singleton_dfn: singleton_interface_dfn | service_obsolete_dfn ; singleton_interface_dfn: ':' scoped_name { AstScope * scope = idlc()->scopes()->nextToTop(); // skip the scope (needlessly) pushed by singleton_dcl AstDeclaration * decl = scope->lookupByName(*$2); if (decl != nullptr && resolveTypedefs(decl)->getNodeType() == NT_interface) { if (ErrorHandler::checkPublished(decl)) { idlc()->scopes()->top()->addDeclaration(decl); } } else { ErrorHandler::lookupError( ErrorCode::InterfaceMemberLookup, *$2, scopeAsDecl(scope)); } delete $2; } ; service_obsolete_dfn: '{' { idlc()->setParseState( idlc()->scopes()->top()->getScopeNodeType() == NT_service ? PS_ServiceSqSeen : PS_SingletonSqSeen); } service_exports { idlc()->setParseState( idlc()->scopes()->top()->getScopeNodeType() == NT_service ? PS_ServiceBodySeen : PS_SingletonBodySeen); } '}' { idlc()->setParseState( idlc()->scopes()->top()->getScopeNodeType() == NT_service ? PS_ServiceQsSeen : PS_SingletonQsSeen); } ; type_dcl : IDL_TYPEDEF { idlc()->setParseState(PS_TypedefSeen); } type_declarator {} | struct_type {} | enum_type {} ; type_declarator : type_spec { idlc()->setParseState(PS_TypeSpecSeen); if ($1 != nullptr && $1->getNodeType() == NT_instantiated_struct) { ErrorHandler::error0(ErrorCode::InstantiatedStructTypeTypedef); } } at_least_one_declarator { idlc()->setParseState(PS_DeclaratorsSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstTypeDef* pTypeDef = nullptr; FeDeclList* pList = $3; FeDeclarator* pDecl = nullptr; AstType const * pType = nullptr; /* * Create nodes representing typedefs and add them to the * enclosing scope */ if ( pScope && $1 && pList ) { FeDeclList::iterator iter = pList->begin(); FeDeclList::iterator end = pList->end(); while (iter != end) { pDecl = (*iter); if ( !pDecl ) { ++iter; continue; } pType = FeDeclarator::compose($1); if ( !pType ) { ++iter; continue; } pTypeDef = new AstTypeDef(pType, pDecl->getName(), pScope); pScope->addDeclaration(pTypeDef); ++iter; delete pDecl; } delete pList; } } ; at_least_one_declarator : declarator declarators { if ( $2 ) { $2->push_back($1); $$ = $2; } else { FeDeclList* pList = new FeDeclList; pList->push_back($1); $$ = pList; } } ; declarators : declarators ',' { idlc()->setParseState(PS_DeclsCommaSeen); } declarator { idlc()->setParseState(PS_DeclsDeclSeen); if ( $1 ) { $1->push_back($4); $$ = $1; } else { FeDeclList* pList = new FeDeclList; pList->push_back($4); $$ = pList; } } | /* EMPTY */ { $$ = nullptr; } ; declarator : identifier { // For historic reasons, the struct com.sun.star.uno.Uik contains // members with illegal names (of the form "m_DataN"); avoid useless // warnings about them: AstScope * scope = idlc()->scopes()->top(); if (scope == nullptr || scope->getScopeNodeType() != NT_struct || (scopeAsDecl(scope)->getScopedName() != "com::sun::star::uno::Uik")) { checkIdentifier($1); } $$ = new FeDeclarator(*$1); delete $1; } ; at_least_one_scoped_name : scoped_name scoped_names { if ($2) { $2->push_front(*$1); $$ = $2; } else { std::list< OString >* pScopedNames = new std::list< OString >; // coverity [copy_paste_error] pScopedNames->push_back(*$1); $$ = pScopedNames; } delete $1; } ; scoped_names : scoped_names ',' { idlc()->setParseState(PS_SNListCommaSeen); } scoped_name { idlc()->setParseState(PS_ScopedNameSeen); if ($1) { $1->push_back(*$4); $$ = $1; } else { std::list< OString >* pNames = new std::list< OString >; pNames->push_back(*$4); $$ = pNames; } delete $4; } | /* EMPTY */ { $$ = nullptr; } ; scoped_name : identifier { idlc()->setParseState(PS_SN_IDSeen); checkIdentifier($1); $$ = $1; } | IDL_SCOPESEPARATOR { idlc()->setParseState(PS_ScopeDelimSeen); } identifier { checkIdentifier($3); OString* pName = new OString("::"); *pName += *$3; delete $3; $$ = pName; } | scoped_name IDL_SCOPESEPARATOR { } identifier { checkIdentifier($4); *$1 += ::rtl::OString("::"); *$1 += *$4; delete $4; $$ = $1; } ; type_spec : simple_type_spec | constructed_type_spec ; simple_type_spec : fundamental_type | scoped_name opt_type_args { $$ = createNamedType($1, $2); } ; fundamental_type: base_type_spec { $$ = idlc()->scopes()->bottom()->lookupPrimitiveType($1); } | sequence_type_spec ; opt_type_args: '<' type_args '>' { $$ = $2; } | /* empty */ { $$ = nullptr; } ; type_args: type_arg { $$ = new DeclList; $$->push_back(const_cast< AstDeclaration * >($1)); //TODO: const_cast } | type_args ',' type_arg { $1->push_back(const_cast< AstDeclaration * >($3)); //TODO: const_cast $$ = $1; } ; type_arg: simple_type_spec { if ($1 != nullptr && static_cast< AstType const * >($1)->isUnsigned()) { ErrorHandler::error0(ErrorCode::UnsignedTypeArgument); } $$ = $1; } ; base_type_spec : integer_type | floating_pt_type | char_type | boolean_type | byte_type | any_type | type_type | string_type ; integer_type : signed_int | unsigned_int ; signed_int : IDL_LONG { $$ = ET_long; } | IDL_HYPER { $$ = ET_hyper; } | IDL_SHORT { $$ = ET_short; } ; unsigned_int : IDL_UNSIGNED IDL_LONG { $$ = ET_ulong; } | IDL_UNSIGNED IDL_HYPER { $$ = ET_uhyper; } | IDL_UNSIGNED IDL_SHORT { $$ = ET_ushort; } ; floating_pt_type : IDL_DOUBLE { $$ = ET_double; } | IDL_FLOAT { $$ = ET_float; } ; char_type : IDL_CHAR { $$ = ET_char; } ; byte_type : IDL_BYTE { $$ = ET_byte; } ; boolean_type : IDL_BOOLEAN { $$ = ET_boolean; } ; any_type : IDL_ANY { $$ = ET_any; } ; type_type : IDL_TYPE { $$ = ET_type; } ; string_type : IDL_STRING { $$ = ET_string; } ; constructed_type_spec : struct_type | enum_type ; sequence_type_spec : IDL_SEQUENCE { idlc()->setParseState(PS_SequenceSeen); /* * Push a sequence marker on scopes stack */ idlc()->scopes()->push(nullptr); } '<' { idlc()->setParseState(PS_SequenceSqSeen); } simple_type_spec { idlc()->setParseState(PS_SequenceTypeSeen); } '>' { idlc()->setParseState(PS_SequenceQsSeen); /* * Remove sequence marker from scopes stack */ if (idlc()->scopes()->top() == nullptr) idlc()->scopes()->pop(); /* * Create a node representing a sequence */ AstScope* pScope = idlc()->scopes()->bottom(); AstDeclaration* pDecl = nullptr; AstDeclaration* pSeq = nullptr; if ( $5 ) { AstType const *pType = static_cast($5); if ( pType ) { pSeq = new AstSequence(pType, pScope); /* * Add this AstSequence to the types defined in the global scope */ pDecl = pScope->addDeclaration(pSeq); if ( pSeq != pDecl ) { // if sequence type already defined then use it delete pSeq; pSeq = pDecl; } } } $$ = pSeq; } | error '>' { yyerror("sequence declaration"); yyerrok; $$ = nullptr; } ; struct_type : structure_header { idlc()->setParseState(PS_StructHeaderSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstStruct* pStruct = nullptr; if ( pScope ) { AstStruct const* pBase= static_cast< AstStruct const* >(resolveTypedefs($1->getInherits())); pStruct = new AstStruct( *$1->getName(), $1->getTypeParameters(), pBase, pScope); pScope->addDeclaration(pStruct); } /* * Push the scope of the struct on the scopes stack */ idlc()->scopes()->push(pStruct); delete $1; } '{' { idlc()->setParseState(PS_StructSqSeen); } at_least_one_member { idlc()->setParseState(PS_StructBodySeen); } '}' { idlc()->setParseState(PS_StructQsSeen); /* this exception is finished, pop its scope from the stack */ idlc()->scopes()->pop(); } ; structure_header : IDL_STRUCT { idlc()->setParseState(PS_StructSeen); } identifier { idlc()->setParseState(PS_StructIDSeen); checkIdentifier($3); } opt_type_params inheritance_spec { idlc()->setParseState(PS_InheritSpecSeen); // Polymorphic struct type templates with base types would cause various // problems in language bindings, so forbid them here. For example, // GCC prior to version 3.4 fails with code like // // struct Base { ... }; // template< typename typeparam_T > struct Derived: public Base { // int member1 CPPU_GCC3_ALIGN(Base); // ... }; // // (Note that plain struct types with instantiated polymorphic struct // type bases, which might also cause problems in language bindings, are // already rejected on a syntactic level.) if ($5 != nullptr && $6 != nullptr) { ErrorHandler::error0(ErrorCode::StructTypeTemplateWithBase); } $$ = new FeInheritanceHeader(NT_struct, $3, $6, $5); delete $5; delete $6; } ; opt_type_params: '<' type_params '>' { $$ = $2; } | /* empty */ { $$ = nullptr; } ; type_params: identifier { $$ = new std::vector< rtl::OString >; $$->push_back(*$1); delete $1; } | type_params ',' identifier { if (std::find($1->begin(), $1->end(), *$3) != $1->end()) { ErrorHandler::error0(ErrorCode::IdenticalTypeParameters); } $1->push_back(*$3); delete $3; $$ = $1; } ; at_least_one_member : member members ; members : members member | /* EMPTY */ ; member : type_or_parameter { idlc()->setParseState(PS_MemberTypeSeen); } at_least_one_declarator { idlc()->setParseState(PS_MemberDeclsSeen); } ';' { idlc()->setParseState(PS_MemberDeclsCompleted); AstScope* pScope = idlc()->scopes()->topNonNull(); AstMember* pMember = nullptr; FeDeclList* pList = $3; FeDeclarator* pDecl = nullptr; AstType const * pType = nullptr; // !!! check recursive type if ( pScope && pList && $1 ) { FeDeclList::iterator iter = pList->begin(); FeDeclList::iterator end = pList->end(); while (iter != end) { pDecl = (*iter); if ( !pDecl ) { ++iter; continue; } pType = FeDeclarator::compose($1); if ( !pType ) { ++iter; continue; } pMember = new AstMember(pType, pDecl->getName(), pScope); if ( !pDecl->checkType($1) ) { // WARNING } pScope->addDeclaration(pMember); ++iter; delete pDecl; } delete pList; } } | error ';' { yyerror("member definition"); yyerrok; } ; type_or_parameter: fundamental_type | scoped_name opt_type_args { AstDeclaration const * decl = nullptr; AstStruct * scope = static_cast< AstStruct * >(idlc()->scopes()->top()); if (scope != nullptr && $2 == nullptr) { decl = scope->findTypeParameter(*$1); } if (decl != nullptr) { delete $1; delete $2; } else { decl = createNamedType($1, $2); if (scope != nullptr && includes(decl, scopeAsDecl(scope))) { ErrorHandler::error1( ErrorCode::RecursiveType, scopeAsDecl(scope)); decl = nullptr; } } $$ = decl; } ; enum_type : IDL_ENUM { idlc()->setParseState(PS_EnumSeen); } identifier { idlc()->setParseState(PS_EnumIDSeen); checkIdentifier($3); AstScope* pScope = idlc()->scopes()->topNonNull(); AstEnum* pEnum = nullptr; /* * Create a node representing an enum and add it to its * enclosing scope */ if (pScope != nullptr) { pEnum = new AstEnum(*$3, pScope); /* * Add it to its defining scope */ pScope->addDeclaration(pEnum); } delete $3; /* * Push the enum scope on the scopes stack */ idlc()->scopes()->push(pEnum); } '{' { idlc()->setParseState(PS_EnumSqSeen); } at_least_one_enumerator { idlc()->setParseState(PS_EnumBodySeen); } '}' { idlc()->setParseState(PS_EnumQsSeen); /* * Done with this enum. Pop its scope from the scopes stack */ if (idlc()->scopes()->top() == nullptr) $$ = nullptr; else { $$ = static_cast(idlc()->scopes()->topNonNull()); idlc()->scopes()->pop(); } } ; at_least_one_enumerator : enumerator enumerators ; enumerators : enumerators ',' { idlc()->setParseState(PS_EnumCommaSeen); } enumerator | /* EMPTY */ | error ',' { yyerror("enumerator definition"); yyerrok; } ; enumerator : identifier { checkIdentifier($1); AstScope* pScope = idlc()->scopes()->topNonNull(); AstEnum* pEnum = nullptr; AstConstant* pEnumVal = nullptr; if ( pScope && pScope->getScopeNodeType() == NT_enum) { pEnum = static_cast(pScope); if (pEnum && $1) { AstExpression* pExpr = new AstExpression(pEnum->getEnumValueCount()); pEnumVal = new AstConstant(ET_long , NT_enum_val, pExpr, *$1, pScope); } if ( pEnum->checkValue(pEnumVal->getConstValue()) ) ErrorHandler::error1(ErrorCode::Eval, pEnum); pScope->addDeclaration(pEnumVal); } delete $1; } | identifier '=' const_expr { checkIdentifier($1); AstScope* pScope = idlc()->scopes()->topNonNull(); AstEnum* pEnum = nullptr; AstConstant* pEnumVal = nullptr; if ( $3 && pScope && pScope->getScopeNodeType() == NT_enum) { $3->evaluate(); if ( $3->coerce(ET_long) ) { pEnum = static_cast(pScope); if (pEnum) { pEnumVal = new AstConstant(ET_long , NT_enum_val, $3, *$1, pScope); } if ( pEnum->checkValue(pEnumVal->getConstValue()) ) ErrorHandler::error1(ErrorCode::Eval, pEnum); pScope->addDeclaration(pEnumVal); } else { ErrorHandler::coercionError($3, ET_long); delete $3; } } delete $1; } ; identifier: IDL_IDENTIFIER | IDL_GET { $$ = new OString("get"); } | IDL_SET { $$ = new OString("set"); } | IDL_PUBLISHED { $$ = new OString("published"); } ; %% /* * Report an error situation discovered in a production */ void yyerror(char const *errmsg) { ErrorHandler::syntaxError(idlc()->getParseState(), idlc()->getLineNumber(), errmsg); idlc()->setParseState(PS_NoState); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */