/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ /* * parser.yy - BISON grammar for IDLC 1.0 */ %{ #include #ifndef _IDLC_IDLC_HXX_ #include #endif #ifndef _IDLC_ERRORHANDLER_HXX_ #include #endif #ifndef _IDLC_FEHELPER_HXX_ #include #endif #ifndef _IDLC_EXPRESSION_HXX_ #include #endif #ifndef _IDLC_ASTCONSTANTS_HXX_ #include #endif #ifndef _IDLC_ASTCONSTANT_HXX_ #include #endif #ifndef _IDLC_ASTARRAY_HXX_ #include #endif #ifndef _IDLC_ASTBASETYPE_HXX_ #include #endif #ifndef _IDLC_ASTTYPEDEF_HXX_ #include #endif #ifndef _IDLC_ASTEXCEPTION_HXX_ #include #endif #ifndef _IDLC_ASTMEMBER_HXX_ #include #endif #ifndef _IDLC_ASTENUM_HXX_ #include #endif #ifndef _IDLC_ASTSEQUENCE_HXX_ #include #endif #ifndef _IDLC_ASTATTRIBUTE_HXX_ #include #endif #ifndef _IDLC_ASTOPERATION_HXX_ #include #endif #ifndef _IDLC_ASTPARAMETER_HXX_ #include #endif #ifndef _IDLC_ASTINTERFACEMEMBER_HXX_ #include #endif #ifndef _IDLC_ASTSERVICEMEMBER_HXX_ #include #endif #ifndef _IDLC_ASTOBSERVES_HXX_ #include #endif #ifndef _IDLC_ASTNEEDS_HXX_ #include #endif #ifndef _IDLC_ASTUNION_HXX_ #include #endif #include "idlc/aststructinstance.hxx" #include "attributeexceptions.hxx" #include "rtl/strbuf.hxx" #include #include using namespace ::rtl; #define YYDEBUG 1 #define YYERROR_VERBOSE 1 extern int yylex(void); void yyerror(char const *); void checkIdentifier(::rtl::OString* 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("'"); idlc()->error()->syntaxError(idlc()->getParseState(), idlc()->getLineNumber(), msg.getStr()); } else idlc()->error()->warning0(WIDL_WRONG_NAMING_CONV, id->getStr()); } } void reportDoubleMemberDeclarations( AstInterface::DoubleMemberDeclarations const & doubleMembers) { for (AstInterface::DoubleMemberDeclarations::const_iterator i( doubleMembers.begin()); i != doubleMembers.end(); ++i) { idlc()->error()->error2(EIDL_DOUBLE_MEMBER, i->first, i->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 != 0 && resolved->getNodeType() == NT_interface) { if (idlc()->error()->checkPublished(decl)) { if (!static_cast< AstInterface const * >(resolved)->isDefined()) { idlc()->error()->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 (AstInterface::DoubleInterfaceDeclarations::iterator i( doubleDecls.interfaces.begin()); i != doubleDecls.interfaces.end(); ++i) { idlc()->error()->error1( EIDL_DOUBLE_INHERITANCE, *i); } reportDoubleMemberDeclarations(doubleDecls.members); } } } } else { idlc()->error()->lookupError( EIDL_INTERFACEMEMBER_LOOKUP, 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 == 0) { idlc()->error()->lookupError(*scopedName); } else if (!idlc()->error()->checkPublished(decl)) { decl = 0; } else if (resolved->getNodeType() == NT_struct) { if (static_cast< AstStruct const * >(resolved)->getTypeParameterCount() != (typeArgs == 0 ? 0 : typeArgs->size())) { idlc()->error()->error0(EIDL_WRONG_NUMBER_OF_TYPE_ARGUMENTS); decl = 0; } else if (typeArgs != 0) { 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 != 0) { idlc()->error()->error0(EIDL_WRONG_NUMBER_OF_TYPE_ARGUMENTS); decl = 0; } } else { idlc()->error()->noTypeError(decl); decl = 0; } delete scopedName; delete typeArgs; return decl; } bool includes(AstDeclaration const * type1, AstDeclaration const * type2) { OSL_ASSERT(type2 != 0); if (type1 != 0) { 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 __GNUC__ #pragma GCC system_header #elif defined __SUNPRO_CC #pragma disable_warn #elif defined _MSC_VER #pragma warning(push, 1) #pragma warning(disable: 4273 4701 4706) #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 */ ExprList* exlval; /* expression list 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 */ sal_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 */ StringList* slval; /* StringList value */ LabelList* llval; /* LabelList value */ AstUnionLabel* lbval; /* union label value */ AstMember* mval; /* member 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_CASE %token IDL_CONST %token IDL_CONSTANTS %token IDL_CONSTRAINED %token IDL_DEFAULT %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_REMOVEABLE %token IDL_SERVICE %token IDL_SEQUENCE %token IDL_SINGLETON %token IDL_STRUCT %token IDL_SWITCH %token IDL_TYPEDEF %token IDL_TRANSIENT %token IDL_UNION %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_ONEWAY %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 const_dcl %type array_declarator %type exception_name %type array_type constructed_type_spec enum_type op_type_spec %type sequence_type_spec simple_type_spec struct_type switch_type_spec %type template_type_spec type_spec union_type %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 positive_int_expr array_dim %type at_least_one_array_dim array_dims %type declarator simple_declarator complex_declarator %type declarators at_least_one_declarator %type exception_header structure_header interfaceheader %type flag_header opt_attrflags opt_attrflag operation_head %type direction service_interface_header service_service_header %type case_labels at_least_one_case_label %type case_label %type element_spec %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); } | const_dcl { idlc()->setParseState(PS_ConstantDeclSeen); } ';' { 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 = NULL; AstDeclaration* pExists = NULL; if ( pScope ) { pModule = new AstModule(*$3, pScope); if( (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 = (AstModule*)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 = NULL; AstDeclaration* pDecl = NULL; /* * Make a new forward interface node and add it to its enclosing scope */ if ( pScope && $1 ) { pForward = new AstInterface(*$1, NULL, pScope); if ( pDecl = pScope->lookupByName(pForward->getScopedName()) ) { if ( (pDecl != pForward) && (pDecl->getNodeType() == NT_interface) ) { delete pForward; } else { idlc()->error()->error2(EIDL_REDEF_SCOPE, 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 = NULL; AstInterface* pForward = NULL; AstDeclaration* pDecl = NULL; /* * Make a new interface node and add it to its enclosing scope */ if ( pScope && $1 ) { pInterface = new AstInterface( *$1->getName(), static_cast< AstInterface * >($1->getInherits()), pScope); if ( pInterface && (pDecl = pScope->lookupByName(pInterface->getScopedName())) ) { /* * See if we're defining a forward declared interface. */ if (pDecl->getNodeType() == NT_interface) { pForward = (AstInterface*)pDecl; if ( !pForward->isDefined() ) { /* * Check if redefining in same scope */ if ( pForward->getScope() != pScope ) { if ( pForward->getScopedName() != pInterface->getScopedName() ) { idlc()->error()->error3(EIDL_SCOPE_CONFLICT, pInterface, pForward, scopeAsDecl(pScope)); } } else if ( !pInterface->isPublished() && pForward->isPublished() ) { idlc()->error()->error0(EIDL_PUBLISHED_FORWARD); } /* * 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, 0); delete $2; } ; inheritance_spec : ':' { idlc()->setParseState(PS_InheritColonSeen); } scoped_name { $$ = $3; } | /* EMPTY */ { $$ = NULL; } ; 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); } simple_declarator { idlc()->setParseState(PS_AttrCompleted); if (($1 & ~(AF_BOUND | AF_READONLY)) != AF_ATTRIBUTE) { idlc()->error()->flagError(EIDL_BAD_ATTRIBUTE_FLAGS, $1); } AstInterface * scope = static_cast< AstInterface * >( idlc()->scopes()->top()); AstAttribute * attr = new AstAttribute( $1, $4->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 ) idlc()->error()->flagError(EIDL_DEFINED_ATTRIBUTEFLAG, $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_REMOVEABLE { idlc()->setParseState(PS_RemoveableSeen); $$ = AF_REMOVEABLE; } | error ']' { yyerror("unknown property|attribute flag"); yyerrok; } ; opt_attribute_block: '{' attribute_block_rest { $$ = $2; } | /* empty */ { $$.get.documentation = 0; $$.get.exceptions = 0; $$.set.documentation = 0; $$.set.exceptions = 0; } ; attribute_block_rest: opt_attribute_raises '}' | error '}' { yyerror("bad attribute raises block"); yyerrok; $$.get.documentation = 0; $$.get.exceptions = 0; $$.set.documentation = 0; $$.set.exceptions = 0; } ; 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 = 0; $$.get.exceptions = 0; $$.set.documentation = 0; $$.set.exceptions = 0; } ; opt_attribute_get_raises: attribute_get_raises | /* empty */ { $$.documentation = 0; $$.exceptions = 0; } ; 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 = 0; $$.exceptions = 0; } ; attribute_set_raises: IDL_SET { if (static_cast< AstAttribute * >(idlc()->scopes()->top())-> isReadonly()) { idlc()->error()->error0(EIDL_READONLY_ATTRIBUTE_SET_EXCEPTIONS); } } raises ';' { $$.documentation = new rtl::OUString( rtl::OStringToOUString( idlc()->getDocumentation(), RTL_TEXTENCODING_UTF8)); $$.exceptions = $3; } ; operation : operation_head op_type_spec { idlc()->setParseState(PS_OpTypeSeen); } identifier { idlc()->setParseState(PS_OpIDSeen); checkIdentifier($4); AstInterface * pScope = static_cast< AstInterface * >( idlc()->scopes()->top()); AstOperation* pOp = NULL; /* * Create a node representing an operation on an interface * and add it to its enclosing scope */ if ( pScope && $2 ) { AstType *pType = (AstType*)$2; if ( !pType || (pType->getNodeType() == NT_exception) ) { // type ERROR } else { pOp = new AstOperation($1, pType, *$4, pScope); AstInterface::DoubleMemberDeclarations doubleMembers( pScope->checkMemberClashes(pOp)); if (doubleMembers.empty()) { pScope->addMember(pOp); } else { reportDoubleMemberDeclarations(doubleMembers); } } } delete $4; /* * 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 = NULL; /* * Add exceptions and context to the operation */ if ( pScope && pScope->getScopeNodeType() == NT_operation) { pOp = (AstOperation*)pScope; if ( pOp ) pOp->setExceptions($12); } delete $12; /* * Done with this operation. Pop its scope from the scopes stack */ idlc()->scopes()->pop(); } ; operation_head : '[' IDL_ONEWAY { idlc()->setParseState(PS_OpOnewaySeen); } ']' { idlc()->setParseState(PS_OpHeadSeen); $$ = OP_ONEWAY; } | /* EMPTY */ { $$ = OP_NONE; } ; 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 = NULL; /* * 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 = $8->compose($5); if ( pType ) { if (pScope->isConstructor() && $2 != DIR_IN) { idlc()->error()->error0(EIDL_CONSTRUCTOR_PARAMETER_NOT_IN); } if (pScope->isVariadic()) { idlc()->error()->error0(EIDL_REST_PARAMETER_NOT_LAST); } if ($7) { AstDeclaration const * type = resolveTypedefs(pType); if (type->getNodeType() != NT_predefined || (static_cast< AstBaseType const * >(type)-> getExprType() != ET_any)) { idlc()->error()->error0(EIDL_REST_PARAMETER_NOT_ANY); } if (pScope->isConstructor()) { if (pScope->getIteratorBegin() != pScope->getIteratorEnd()) { idlc()->error()->error0( EIDL_CONSTRUCTOR_REST_PARAMETER_NOT_FIRST); } } else { idlc()->error()->error0(EIDL_METHOD_HAS_REST_PARAMETER); } } 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 */ { $$ = 0; } ; 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 == 0) { idlc()->error()->lookupError(*$1); } else if (!idlc()->error()->checkPublished(decl)) { decl = 0; } else if (decl->getNodeType() != NT_exception) { idlc()->error()->error1(EIDL_ILLEGAL_RAISES, decl); decl = 0; } 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()) { idlc()->error()->error0(EIDL_MIXED_INHERITANCE); } 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 : const_dcl { idlc()->setParseState(PS_ConstantDeclSeen); } ';' {}; const_dcl : 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 = NULL; if ( $9 && pScope ) { if ( !$9->coerce($3) ) { idlc()->error()->coercionError($9, $3); } else { pConstant = new AstConstant($3, $9, *$5, pScope); pScope->addDeclaration(pConstant); } } delete $5; } ; 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 = NULL; AstDeclaration* pExists = NULL; if ( pScope ) { pConstants = new AstConstants(*$3, pScope); if( (pExists = pScope->lookupForAdd(pConstants)) ) { pExists->setInMainfile(idlc()->isInMainFile()); delete(pConstants); pConstants = (AstConstants*)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(EC_or, $1, $3); } ; xor_expr : and_expr | xor_expr '^' and_expr { $$ = new AstExpression(EC_xor, $1, $3); } ; and_expr : shift_expr | and_expr '&' shift_expr { $$ = new AstExpression(EC_and, $1, $3); } ; shift_expr : add_expr | shift_expr IDL_LEFTSHIFT add_expr { $$ = new AstExpression(EC_left, $1, $3); } | shift_expr IDL_RIGHTSHIFT add_expr { $$ = new AstExpression(EC_right, $1, $3); } ; add_expr : mult_expr | add_expr '+' mult_expr { $$ = new AstExpression(EC_add, $1, $3); } | add_expr '-' mult_expr { $$ = new AstExpression(EC_minus, $1, $3); } ; mult_expr : unary_expr | mult_expr '*' unary_expr { $$ = new AstExpression(EC_mul, $1, $3); } | mult_expr '/' unary_expr { $$ = new AstExpression(EC_div, $1, $3); } | mult_expr '%' unary_expr { $$ = new AstExpression(EC_mod, $1, $3); } ; unary_expr : primary_expr | '+' primary_expr { $$ = new AstExpression(EC_u_plus, $2, NULL); } | '-' primary_expr { $$ = new AstExpression(EC_u_minus, $2, NULL); } | '~' 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); } ; positive_int_expr : const_expr { $1->evaluate(EK_const); if ( !$1->coerce(ET_ulong) ) { idlc()->error()->coercionError($1, ET_ulong); delete $1; $$ = NULL; } } ; const_type : integer_type | char_type | byte_type | boolean_type | floating_pt_type | scoped_name { AstScope* pScope = idlc()->scopes()->topNonNull(); AstDeclaration const * type = 0; /* * If the constant's type is a scoped name, it must resolve * to a scalar constant type */ if ( pScope && (type = pScope->lookupByName(*$1)) ) { if (!idlc()->error()->checkPublished(type)) { type = 0; } 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, 0); delete $5; } ; exception_dcl : exception_header { idlc()->setParseState(PS_ExceptHeaderSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstException* pExcept = NULL; 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 = NULL; FeDeclList* pList = $4; FeDeclarator* pDecl = NULL; AstType const * pType = NULL; if ( pScope->getScopeNodeType() == NT_singleton ) { idlc()->error()->error0(EIDL_ILLEGAL_ADD); } else { if ( ($1 & AF_ATTRIBUTE) == AF_ATTRIBUTE ) idlc()->error()->flagError(EIDL_WRONGATTRIBUTEKEYWORD, AF_ATTRIBUTE); if ( ($1 & AF_PROPERTY) != AF_PROPERTY ) idlc()->error()->flagError(EIDL_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 = pDecl->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 = NULL; AstInterfaceMember* pIMember = NULL; if ( pScope->getScopeNodeType() == NT_singleton ) { idlc()->error()->error0(EIDL_ILLEGAL_ADD); } else { /* * Create a node representing a class member. * Store it in the enclosing scope */ if ( pScope && $2 ) { StringList::iterator iter = $2->begin(); StringList::iterator end = $2->end(); while ( iter != end ) { pDecl = pScope->lookupByName(*iter); 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 ( idlc()->error()->checkPublished(pDecl, bOptional) ) { pIMember = new AstInterfaceMember( $1, (AstInterface*)pDecl, *iter, pScope); pScope->addDeclaration(pIMember); } } else { idlc()->error()-> lookupError(EIDL_INTERFACEMEMBER_LOOKUP, *iter, scopeAsDecl(pScope)); } iter++; } } } delete $2; } | service_service_header at_least_one_scoped_name ';' { idlc()->setParseState(PS_ServiceMemberSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstDeclaration* pDecl = NULL; AstServiceMember* pSMember = NULL; /* * Create a node representing a class member. * Store it in the enclosing scope */ if ( pScope && $2 ) { StringList::iterator iter = $2->begin(); StringList::iterator end = $2->end(); while ( iter != end ) { pDecl = pScope->lookupByName(*iter); if ( pDecl && (pDecl->getNodeType() == NT_service) ) { if ( pScope->getScopeNodeType() == NT_singleton && pScope->nMembers() > 0 ) idlc()->error()->error0(EIDL_ILLEGAL_ADD); else if ( idlc()->error()->checkPublished(pDecl) ) { pSMember = new AstServiceMember( $1, (AstService*)pDecl, *iter, pScope); pScope->addDeclaration(pSMember); } } else { idlc()->error()-> lookupError(EIDL_SERVICEMEMBER_LOOKUP, *iter, scopeAsDecl(pScope)); } iter++; } } delete $2; } | IDL_OBSERVES at_least_one_scoped_name ';' { idlc()->setParseState(PS_ServiceMemberSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstDeclaration* pDecl = NULL; AstObserves* pObserves = NULL; if ( pScope->getScopeNodeType() == NT_singleton ) { idlc()->error()->error0(EIDL_ILLEGAL_ADD); } else { /* * Create a node representing a class member. * Store it in the enclosing scope */ if ( pScope && $2 ) { StringList::iterator iter = $2->begin(); StringList::iterator end = $2->end(); while ( iter != end ) { pDecl = pScope->lookupByName(*iter); if ( pDecl && (pDecl->getNodeType() == NT_interface) ) { pObserves = new AstObserves((AstInterface*)pDecl, *iter, pScope); pScope->addDeclaration(pObserves); } else { idlc()->error()-> lookupError(EIDL_INTERFACEMEMBER_LOOKUP, *iter, scopeAsDecl(pScope)); } iter++; } } } delete $2; } | IDL_NEEDS at_least_one_scoped_name ';' { idlc()->setParseState(PS_ServiceMemberSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstDeclaration* pDecl = NULL; AstNeeds* pNeeds = NULL; if ( pScope->getScopeNodeType() == NT_singleton ) { idlc()->error()->error0(EIDL_ILLEGAL_ADD); } else { /* * Create a node representing a class member. * Store it in the enclosing scope */ if ( pScope && $2 ) { StringList::iterator iter = $2->begin(); StringList::iterator end = $2->end(); while ( iter != end ) { pDecl = pScope->lookupByName(*iter); if ( pDecl && (pDecl->getNodeType() == NT_service) ) { pNeeds = new AstNeeds((AstService*)pDecl, *iter, pScope); pScope->addDeclaration(pNeeds); } else { idlc()->error()-> lookupError(EIDL_SERVICEMEMBER_LOOKUP, *iter, scopeAsDecl(pScope)); } iter++; } } } 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) ) idlc()->error()->flagError(EIDL_OPTIONALEXPECTED, $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) ) idlc()->error()->flagError(EIDL_OPTIONALEXPECTED, $1); $$ = $1; } ; service_dcl : IDL_SERVICE { idlc()->setParseState(PS_ServiceSeen); } identifier { idlc()->setParseState(PS_ServiceIDSeen); checkIdentifier($3); AstScope* pScope = idlc()->scopes()->topNonNull(); AstService* pService = NULL; /* * Make a new service and add it to the enclosing scope */ if (pScope != NULL) { 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 != 0 && resolveTypedefs(decl)->getNodeType() == NT_interface) { if (idlc()->error()->checkPublished(decl)) { idlc()->scopes()->top()->addDeclaration(decl); } } else { idlc()->error()->lookupError( EIDL_INTERFACEMEMBER_LOOKUP, *$2, scopeAsDecl(scope)); } delete $2; } opt_service_body { AstService * s = static_cast< AstService * >(idlc()->scopes()->top()); if (s != 0) { 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(OP_NONE, 0, *$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()) { idlc()->error()->error0(EIDL_SIMILAR_CONSTRUCTORS); } } ';' ; singleton_dcl : IDL_SINGLETON { idlc()->setParseState(PS_SingletonSeen); } identifier { idlc()->setParseState(PS_SingletonIDSeen); checkIdentifier($3); AstScope* pScope = idlc()->scopes()->topNonNull(); AstService* pService = NULL; /* * Make a new service and add it to the enclosing scope */ if (pScope != NULL) { 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 != 0 && resolveTypedefs(decl)->getNodeType() == NT_interface) { if (idlc()->error()->checkPublished(decl)) { idlc()->scopes()->top()->addDeclaration(decl); } } else { idlc()->error()->lookupError( EIDL_INTERFACEMEMBER_LOOKUP, *$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 {} | union_type {} | enum_type {} ; type_declarator : type_spec { idlc()->setParseState(PS_TypeSpecSeen); if ($1 != 0 && $1->getNodeType() == NT_instantiated_struct) { idlc()->error()->error0(EIDL_INSTANTIATED_STRUCT_TYPE_TYPEDEF); } } at_least_one_declarator { idlc()->setParseState(PS_DeclaratorsSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstTypeDef* pTypeDef = NULL; FeDeclList* pList = $3; FeDeclarator* pDecl = NULL; AstType const * pType = NULL; /* * 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 = pDecl->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 */ { $$ = NULL; } ; declarator : simple_declarator | complex_declarator ; simple_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 == 0 || scope->getScopeNodeType() != NT_struct || (scopeAsDecl(scope)->getScopedName() != "com::sun::star::uno::Uik")) { checkIdentifier($1); } $$ = new FeDeclarator(*$1, FeDeclarator::FD_simple, NULL); delete $1; } ; complex_declarator : array_declarator { $$ = new FeDeclarator($1->getLocalName(), FeDeclarator::FD_complex, $1); } ; array_declarator : identifier { idlc()->setParseState(PS_ArrayIDSeen); checkIdentifier($1); } at_least_one_array_dim { idlc()->setParseState(PS_ArrayCompleted); $$ = new AstArray(*$1, NULL, *$3, idlc()->scopes()->bottom()); delete $1; } ; at_least_one_array_dim : array_dim array_dims { if( $2 ) { $2->push_front($1); $$ = $2; } else { ExprList* pList = new ExprList(); pList->push_back($1); $$ = pList; } } ; array_dims : array_dims array_dim { if( $1 ) { $1->push_back($2); $$ = $1; } else { ExprList* pList = new ExprList(); pList->push_back($2); $$ = pList; } } | /* EMPTY */ { $$ = NULL; } ; array_dim : '[' { idlc()->setParseState(PS_DimSqSeen); } positive_int_expr { idlc()->setParseState(PS_DimExprSeen); } ']' { idlc()->setParseState(PS_DimQsSeen); /* * Array dimensions are expressions which must be coerced to * positive integers */ if ( !$3 || !$3->coerce(ET_uhyper) ) { idlc()->error()->coercionError($3, ET_uhyper); $$ = NULL; } else $$ = $3; } ; at_least_one_scoped_name : scoped_name scoped_names { if ($2) { $2->push_front(*$1); $$ = $2; } else { StringList* pNames = new StringList(); pNames->push_back(*$1); $$ = pNames; } delete($1); } ; scoped_names : scoped_names ',' { idlc()->setParseState(PS_SNListCommaSeen); } scoped_name { idlc()->setParseState(PS_ScopedNameSeen); if ($1) { $1->push_back(*$4); $$ = $1; } else { StringList* pNames = new StringList(); pNames->push_back(*$4); $$ = pNames; } delete($4); } | /* EMPTY */ { $$ = NULL; } ; 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); } | template_type_spec ; opt_type_args: '<' type_args '>' { $$ = $2; } | /* empty */ { $$ = 0; } ; 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 != 0 && static_cast< AstType const * >($1)->isUnsigned()) { idlc()->error()->error0(EIDL_UNSIGNED_TYPE_ARGUMENT); } $$ = $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; } ; template_type_spec : sequence_type_spec | array_type ; constructed_type_spec : struct_type | union_type | enum_type ; array_type : simple_type_spec { idlc()->setParseState(PS_ArrayTypeSeen); } at_least_one_array_dim { idlc()->setParseState(PS_ArrayCompleted); AstScope* pScope = idlc()->scopes()->bottom(); AstDeclaration* pDecl = NULL; AstDeclaration* pArray = NULL; if ( $1 ) { pArray = new AstArray((AstType*)$1, *$3, idlc()->scopes()->bottom()); if ( pScope ) { pDecl = pScope->addDeclaration(pArray); if ( pArray != pDecl ) { // if array type already defined then use it delete pArray; pArray = pDecl; } } } $$ = pArray; } ; sequence_type_spec : IDL_SEQUENCE { idlc()->setParseState(PS_SequenceSeen); /* * Push a sequence marker on scopes stack */ idlc()->scopes()->push(NULL); } '<' { 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() == NULL) idlc()->scopes()->pop(); /* * Create a node representing a sequence */ AstScope* pScope = idlc()->scopes()->bottom(); AstDeclaration* pDecl = NULL; AstDeclaration* pSeq = NULL; if ( $5 ) { AstType *pType = (AstType*)$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; $$ = 0; } ; struct_type : structure_header { idlc()->setParseState(PS_StructHeaderSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstStruct* pStruct = NULL; if ( pScope ) { AstStruct* pBase= static_cast< AstStruct* >($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 != 0 && $6 != 0) { idlc()->error()->error0(EIDL_STRUCT_TYPE_TEMPLATE_WITH_BASE); } $$ = new FeInheritanceHeader(NT_struct, $3, $6, $5); delete $5; delete $6; } ; opt_type_params: '<' type_params '>' { $$ = $2; } | /* empty */ { $$ = 0; } ; 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()) { idlc()->error()->error0(EIDL_IDENTICAL_TYPE_PARAMETERS); } $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 = NULL; FeDeclList* pList = $3; FeDeclarator* pDecl = NULL; AstType const * pType = NULL; // !!! 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 = pDecl->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 = 0; AstStruct * scope = static_cast< AstStruct * >(idlc()->scopes()->top()); if (scope != 0 && $2 == 0) { decl = scope->findTypeParameter(*$1); } if (decl != 0) { delete $1; delete $2; } else { decl = createNamedType($1, $2); if (scope != 0 && includes(decl, scopeAsDecl(scope))) { idlc()->error()->error1( EIDL_RECURSIVE_TYPE, scopeAsDecl(scope)); decl = 0; } } $$ = decl; } ; enum_type : IDL_ENUM { idlc()->setParseState(PS_EnumSeen); } identifier { idlc()->setParseState(PS_EnumIDSeen); checkIdentifier($3); AstScope* pScope = idlc()->scopes()->topNonNull(); AstEnum* pEnum = NULL; /* * Create a node representing an enum and add it to its * enclosing scope */ if (pScope != NULL) { 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() == NULL) $$ = NULL; else { $$ = (AstEnum*)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 = NULL; AstConstant* pEnumVal = NULL; if ( pScope && pScope->getScopeNodeType() == NT_enum) { pEnum = (AstEnum*)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()) ) idlc()->error()->error1(EIDL_EVAL_ERROR, pEnum); pScope->addDeclaration(pEnumVal); } delete $1; } | identifier '=' const_expr { checkIdentifier($1); AstScope* pScope = idlc()->scopes()->topNonNull(); AstEnum* pEnum = NULL; AstConstant* pEnumVal = NULL; if ( $3 && pScope && pScope->getScopeNodeType() == NT_enum) { $3->evaluate(EK_const); if ( $3->coerce(ET_long) ) { pEnum = (AstEnum*)pScope; if (pEnum) { pEnumVal = new AstConstant(ET_long , NT_enum_val, $3, *$1, pScope); } if ( pEnum->checkValue(pEnumVal->getConstValue()) ) idlc()->error()->error1(EIDL_EVAL_ERROR, pEnum); pScope->addDeclaration(pEnumVal); } else { idlc()->error()->coercionError($3, ET_long); delete $3; } } delete $1; } ; union_type : IDL_UNION { idlc()->setParseState(PS_UnionSeen); } identifier { idlc()->setParseState(PS_UnionIDSeen); checkIdentifier($3); } IDL_SWITCH { idlc()->setParseState(PS_SwitchSeen); } '(' { idlc()->setParseState(PS_SwitchOpenParSeen); } switch_type_spec { idlc()->setParseState(PS_SwitchTypeSeen); } ')' { idlc()->setParseState(PS_SwitchCloseParSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstUnion* pUnion = NULL; /* * Create a node representing a union. Add it to its enclosing * scope */ if ( $9 && pScope ) { AstType* pType = (AstType*)$9; if ( !pType) { idlc()->error()->noTypeError($9); } else { pUnion = new AstUnion(*$3, pType, pScope); pScope->addDeclaration(pUnion); } } delete $3; /* * Push the scope of the union on the scopes stack */ idlc()->scopes()->push(pUnion); } '{' { idlc()->setParseState(PS_UnionSqSeen); } at_least_one_case_branch { idlc()->setParseState(PS_UnionBodySeen); } '}' { idlc()->setParseState(PS_UnionQsSeen); /* this union is finished, pop its scope from the stack */ idlc()->scopes()->pop(); } ; switch_type_spec : integer_type { $$ = idlc()->scopes()->bottom()->lookupPrimitiveType($1); } | char_type { $$ = idlc()->scopes()->bottom()->lookupPrimitiveType($1); } | boolean_type { $$ = idlc()->scopes()->bottom()->lookupPrimitiveType($1); } | enum_type | scoped_name { AstScope* pScope = idlc()->scopes()->topNonNull(); AstBaseType* pBaseType = NULL; AstDeclaration const * pDecl = NULL; AstTypeDef* pTypeDef = NULL; sal_Bool bFound = sal_False; /* * If the constant's type is a scoped name, it must resolve * to a scalar constant type */ if ( pScope && (pDecl = pScope->lookupByName(*$1)) ) { /* * Look through typedefs */ while ( !bFound ) { switch (pDecl->getNodeType()) { case NT_enum: $$ = pDecl; bFound = sal_True; break; case NT_predefined: pBaseType = (AstBaseType*)pDecl; if ( pBaseType ) { switch (pBaseType->getExprType()) { case ET_short: case ET_ushort: case ET_long: case ET_ulong: case ET_hyper: case ET_uhyper: case ET_char: case ET_byte: case ET_boolean: $$ = pBaseType; bFound = sal_True; break; default: $$ = NULL; bFound = sal_True; break; } } break; case NT_typedef: pTypeDef = (AstTypeDef*)pDecl; if ( pTypeDef ) pDecl = pTypeDef->getBaseType(); break; default: $$ = NULL; bFound = sal_True; break; } } } else $$ = NULL; if ($$ == NULL) idlc()->error()->lookupError(*$1); } ; at_least_one_case_branch : case_branch case_branches ; case_branches : case_branches case_branch | /* EMPTY */ ; case_branch : at_least_one_case_label { idlc()->setParseState(PS_UnionLabelSeen); } element_spec { idlc()->setParseState(PS_UnionElemSeen); AstScope* pScope = idlc()->scopes()->topNonNull(); AstUnionLabel* pLabel = NULL; AstUnionBranch* pBranch = NULL; AstMember* pMember = $3; /* * Create several nodes representing branches of a union. * Add them to the enclosing scope (the union scope) */ if ( pScope && $1 && $3 ) { LabelList::iterator iter = $1->begin(); LabelList::iterator end = $1->end(); for (;iter != end; iter++) { pLabel = *iter; if ( !pLabel ) { iter++; continue; } pBranch = new AstUnionBranch(pLabel, pMember->getType(), pMember->getLocalName(), pScope); pScope->addDeclaration(pBranch); } } if ( $1 ) delete($1); } ; at_least_one_case_label : case_label case_labels { if ( $2 ) { $2->push_front($1); $$ = $2; } else { LabelList* pLabels = new LabelList(); pLabels->push_back($1); $$ = pLabels; } } ; case_labels : case_labels case_label { if ( $1 ) { $1->push_back($2); $$ = $1; } else { LabelList* pLabels = new LabelList(); pLabels->push_back($2); $$ = pLabels; } } | /* EMPTY */ { $$ = NULL; } ; case_label : IDL_DEFAULT { idlc()->setParseState(PS_DefaultSeen); } ':' { idlc()->setParseState(PS_LabelColonSeen); $$ = new AstUnionLabel(UL_default, NULL); } | IDL_CASE { idlc()->setParseState(PS_CaseSeen); } const_expr { idlc()->setParseState(PS_LabelExprSeen); } ':' { idlc()->setParseState(PS_LabelColonSeen); $$ = new AstUnionLabel(UL_label, $3); } ; element_spec : type_spec { idlc()->setParseState(PS_UnionElemTypeSeen); } declarator { idlc()->setParseState(PS_UnionElemDeclSeen); } ';' { idlc()->setParseState(PS_UnionElemCompleted); AstScope* pScope = idlc()->scopes()->topNonNull(); /* * Check for illegal recursive use of type */ // if ( $1 && AST_illegal_recursive_type($1)) // idlc()->error()->error1(EIDL_RECURSIVE_TYPE, $1); /* * Create a field in a union branch */ if ( $1 && $3 ) { AstType const * pType = $3->compose($1); if ( !pType ) $$ = NULL; else $$ = new AstMember(pType, $3->getName(), pScope); } else $$ = NULL; if ( $3 ) delete $3; } | error ';' { $$ = NULL; } ; 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) { idlc()->error()->syntaxError(idlc()->getParseState(), idlc()->getLineNumber(), errmsg); idlc()->setParseState(PS_NoState); }