diff options
Diffstat (limited to 'idlc/source/parser.y')
-rw-r--r-- | idlc/source/parser.y | 3292 |
1 files changed, 3292 insertions, 0 deletions
diff --git a/idlc/source/parser.y b/idlc/source/parser.y new file mode 100644 index 000000000000..8da9c7ad63b5 --- /dev/null +++ b/idlc/source/parser.y @@ -0,0 +1,3292 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/* + * parser.yy - BISON grammar for IDLC 1.0 + */ + +%{ +#include <string.h> + +#ifndef _IDLC_IDLC_HXX_ +#include <idlc/idlc.hxx> +#endif +#ifndef _IDLC_ERRORHANDLER_HXX_ +#include <idlc/errorhandler.hxx> +#endif +#ifndef _IDLC_FEHELPER_HXX_ +#include <idlc/fehelper.hxx> +#endif +#ifndef _IDLC_EXPRESSION_HXX_ +#include <idlc/astexpression.hxx> +#endif +#ifndef _IDLC_ASTCONSTANTS_HXX_ +#include <idlc/astconstants.hxx> +#endif +#ifndef _IDLC_ASTCONSTANT_HXX_ +#include <idlc/astconstant.hxx> +#endif +#ifndef _IDLC_ASTARRAY_HXX_ +#include <idlc/astarray.hxx> +#endif +#ifndef _IDLC_ASTBASETYPE_HXX_ +#include <idlc/astbasetype.hxx> +#endif +#ifndef _IDLC_ASTTYPEDEF_HXX_ +#include <idlc/asttypedef.hxx> +#endif +#ifndef _IDLC_ASTEXCEPTION_HXX_ +#include <idlc/astexception.hxx> +#endif +#ifndef _IDLC_ASTMEMBER_HXX_ +#include <idlc/astmember.hxx> +#endif +#ifndef _IDLC_ASTENUM_HXX_ +#include <idlc/astenum.hxx> +#endif +#ifndef _IDLC_ASTSEQUENCE_HXX_ +#include <idlc/astsequence.hxx> +#endif +#ifndef _IDLC_ASTATTRIBUTE_HXX_ +#include <idlc/astattribute.hxx> +#endif +#ifndef _IDLC_ASTOPERATION_HXX_ +#include <idlc/astoperation.hxx> +#endif +#ifndef _IDLC_ASTPARAMETER_HXX_ +#include <idlc/astparameter.hxx> +#endif +#ifndef _IDLC_ASTINTERFACEMEMBER_HXX_ +#include <idlc/astinterfacemember.hxx> +#endif +#ifndef _IDLC_ASTSERVICEMEMBER_HXX_ +#include <idlc/astservicemember.hxx> +#endif +#ifndef _IDLC_ASTOBSERVES_HXX_ +#include <idlc/astobserves.hxx> +#endif +#ifndef _IDLC_ASTNEEDS_HXX_ +#include <idlc/astneeds.hxx> +#endif +#ifndef _IDLC_ASTUNION_HXX_ +#include <idlc/astunion.hxx> +#endif +#include "idlc/aststructinstance.hxx" + +#include "attributeexceptions.hxx" + +#include "rtl/strbuf.hxx" + +#include <algorithm> +#include <vector> + +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 <sval> 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 <strval> IDL_LEFTSHIFT +%token <strval> IDL_RIGHTSHIFT +%token <strval> IDL_SCOPESEPARATOR + +%token <ival> IDL_INTEGER_LITERAL +%token <uval> IDL_INTEGER_ULITERAL +%token <dval> IDL_FLOATING_PT_LITERAL + +/* + * These are production names: + */ +%type <dclval> type_dcl const_dcl +%type <dclval> array_declarator +%type <dclval> exception_name +%type <cdclval> array_type constructed_type_spec enum_type op_type_spec +%type <cdclval> sequence_type_spec simple_type_spec struct_type switch_type_spec +%type <cdclval> template_type_spec type_spec union_type +%type <cdclval> fundamental_type type_arg type_or_parameter +%type <dclsval> opt_raises raises exception_list +%type <attexcpval> opt_attribute_get_raises attribute_get_raises +%type <attexcpval> opt_attribute_set_raises attribute_set_raises +%type <dclsval> opt_type_args type_args + +%type <sval> identifier +%type <sval> interface_decl +%type <sval> scoped_name inheritance_spec +%type <slval> scoped_names at_least_one_scoped_name + +%type <etval> const_type integer_type char_type boolean_type +%type <etval> floating_pt_type any_type signed_int string_type +%type <etval> unsigned_int base_type_spec byte_type type_type + +%type <exval> expression const_expr or_expr xor_expr and_expr +%type <exval> add_expr mult_expr unary_expr primary_expr shift_expr +%type <exval> literal positive_int_expr array_dim + +%type <exlval> at_least_one_array_dim array_dims + +%type <fdval> declarator simple_declarator complex_declarator +%type <dlval> declarators at_least_one_declarator + +%type <ihval> exception_header structure_header interfaceheader + +%type <ulval> flag_header opt_attrflags opt_attrflag operation_head +%type <ulval> direction service_interface_header service_service_header + +%type <llval> case_labels at_least_one_case_label +%type <lbval> case_label +%type <mval> element_spec + +%type <bval> optional_inherited_interface opt_rest opt_service_body + +%type <attexcval> opt_attribute_block attribute_block_rest opt_attribute_raises + +%type <svals> 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); +} |