/*****************************************************************************/ /** Microsoft LAN Manager **/ /** Copyright(c) Microsoft Corp., 1987-1990 **/ /*****************************************************************************/ /***************************************************************************** File : grammar.y Title : the midl grammar file : Description: contains the syntactic and semantic handling of the : idl file History : 08-Aug-1991 VibhasC Create 15-Sep-1993 GregJen Rewrite for MIDL 2.0 *****************************************************************************/ %{ /**************************************************************************** *** local defines ***************************************************************************/ #define pascal #define FARDATA #define NEARDATA #define FARCODE #define NEARCODE #define NEARSWAP #define YYFARDATA #define PASCAL pascal #define CDECL #define VOID void #define CONST const #define GLOBAL #define YYSTYPE lextype_t #define YYNEAR NEARCODE #define YYPASCAL PASCAL #define YYPRINT printf #define YYSTATIC static #define YYCONST static const #define YYLEX yylex #define YYPARSER yyparse #ifdef gajdebug3 #define YYDEBUG #endif #define IS_CUR_INTERFACE_LOCAL() ( \ (BOOL) (pInterfaceInfoDict->IsInterfaceLocal()) ) /**************************************************************************** *** include files ***************************************************************************/ #include "nulldefs.h" extern "C" { #include #include #include #include #include int yyparse(); } #include "allnodes.hxx" #include "lexutils.hxx" #include "gramutil.hxx" #include "idict.hxx" #include "filehndl.hxx" #include "cmdana.hxx" #include "control.hxx" #include "tlgen.hxx" extern "C" { #include "lex.h" extern char * KeywordToString( token_t ); } /*************************************************************************** * local data **************************************************************************/ BOOL fBaseImported = FALSE; BOOL fOdlBaseImported = FALSE; BOOL fLibrary = FALSE; /*************************************************************************** * external data **************************************************************************/ extern CMD_ARG * pCommand; extern node_error * pErrorTypeNode; extern node_e_attr * pErrorAttrNode; extern SymTable * pBaseSymTbl; extern SymTable * pCurSymTbl; extern nsa * pSymTblMgr; extern short ImportLevel; extern BOOL fTypeGraphInited; extern BOOL fPragmaImportOn; extern CCONTROL * pCompiler; extern node_source * pSourceNode; extern NFA_INFO * pImportCntrl; extern PASS_1 * pPass1; extern IINFODICT * pInterfaceInfoDict; extern unsigned short LexContext; extern BOOL fRedundantImport; extern node_skl * pBaseImplicitHandle; extern unsigned short CurrentZp; extern node_pragma_pack * pPackStack; /*************************************************************************** * external functions **************************************************************************/ extern void yyunlex( token_t ); extern BOOL IsTempName( char * ); extern char * GenTempName(); extern char * GenIntfName(); extern char * GenCompName(); extern void CopyNode( node_skl *, node_skl * ); extern STATUS_T GetBaseTypeNode( node_skl **, short, short, short); extern ATTRLIST GenerateFieldAttribute( ATTR_T, expr_list *); extern node_skl * SearchTag( char *, NAME_T ); extern void SyntaxError( STATUS_T, short ); extern int PossibleMissingToken( short, short ); extern char * MakeNewStringWithProperQuoting( char * ); extern void CheckGlobalNamesClash( SymKey ); extern void CheckSpecialForwardTypedef( node_skl *, node_skl *, type_node_list *); extern void PushZpStack( node_pragma_pack * & PackStack, unsigned short & CurrentZp ); extern void PopZpStack( node_pragma_pack * & PackStack, unsigned short & CurrentZp ); /*************************************************************************** * local data **************************************************************************/ /*************************************************************************** * local defines **************************************************************************/ #define YY_CATCH(x) #define DEFINE_STRING "#define" #define LEN_DEFINE (7) %} /****************************************************************************/ %start RpcProg %token KWINTERFACE %token KWCLASS %token KWEXESERVER %token KWDLLSERVER %token KWIMPORT %token KWIMPORTIDLBASE %token KWIMPORTODLBASE %token KWCPPQUOTE %token KWCPRAGMA %token KWCPRAGMAPACK %token KWMPRAGMAIMPORT %token KWMPRAGMAECHO %token KWMPRAGMAIMPORTCLNTAUX %token KWMPRAGMAIMPORTSRVRAUX %token TYPENAME %token LIBNAME %token KWVOID %token KWUNSIGNED %token KWSIGNED %token KWFLOAT %token KWDOUBLE %token KWINT %token KWBYTE %token KWCHAR %token KWSMALL %token KWLONG %token KWSHORT %token KWHYPER %token KWINT64 %token KWSTRUCT %token KWUNION %token KWENUM %token KWSHORTENUM %token KWLONGENUM %token KWCONST %token KWVOLATILE %token KW_C_INLINE %token KWTYPEDEF %token KWEXTERN %token KWSTATIC %token KWAUTO %token KWREGISTER %token KWERRORSTATUST %token KWBOOLEAN %token KWISOLATIN1 %token KWPRIVATECHAR8 %token KWISOMULTILINGUAL %token KWPRIVATECHAR16 %token KWISOUCS %token KWPIPE %token KWSWITCH %token KWCASE %token KWDEFAULT %token KWUUID %token KWVERSION %token KWOPAQUE %token KWSTRING %token KWBSTRING %token KWIN %token KWOUT %token KWIIDIS %token KWFIRSTIS %token KWLASTIS %token KWMAXIS %token KWMINIS %token KWLENGTHIS %token KWSIZEIS /* start of ODL key words */ %token KWID %token KWHC /* helpcontext attribute */ %token KWHSC /* helpstring context attribute */ %token KWLCID %token KWDLLNAME %token KWHELPSTR %token KWHELPFILE %token KWENTRY %token KWPROPGET %token KWPROPPUT %token KWPROPPUTREF %token KWOPTIONAL %token KWVARARG %token KWAPPOBJECT %token KWRESTRICTED %token KWPUBLIC %token KWREADONLY %token KWODL %token KWSOURCE %token KWBINDABLE %token KWREQUESTEDIT %token KWDISPLAYBIND %token KWDEFAULTBIND %token KWLICENSED %token KWPREDECLID %token KWHIDDEN %token KWRETVAL %token KWCONTROL %token KWDUAL %token KWNONEXTENSIBLE %token KWNONCREATABLE %token KWOLEAUTOMATION %token KWLIBRARY %token KWMODULE %token KWDISPINTERFACE %token KWCOCLASS %token KWMETHODS %token KWPROPERTIES %token KWIMPORTLIB %token KWFUNCDESCATTR %token KWIDLDESCATTR %token KWTYPEDESCATTR %token KWVARDESCATTR %token KWSAFEARRAY %token KWAGGREGATABLE %token KWUIDEFAULT %token KWNONBROWSABLE %token KWDEFAULTCOLLELEM %token KWDEFAULTVALUE %token KWCUSTOM %token KWDEFAULTVTABLE %token KWIMMEDIATEBIND %token KWUSESGETLASTERROR %token KWREPLACEABLE /* end of ODL key words */ %token KWHANDLET /* Formerly RPCHNDL */ %token KWHANDLE /* Formerly GEN_HNDL */ %token KWCONTEXTHANDLE /* Aka LRPC_CTXT_HNDL */ %token KWMSUNION %token KWENDPOINT %token KWDEFAULTPOINTER %token KWLOCAL %token KWSWITCHTYPE %token KWSWITCHIS %token KWTRANSMITAS %token KWWIREMARSHAL %token KWIGNORE %token KWREF %token KWUNIQUE %token KWPTR %token KWV1ARRAY %token KWV1STRUCT %token KWV1ENUM %token KWV1STRING %token KWIDEMPOTENT %token KWBROADCAST %token KWMAYBE %token KWASYNC %token KWINPUTSYNC %token KWCALLBACK %token KWALIGN %token KWUNALIGNED %token KWOPTIMIZE %token STRING %token WIDECHARACTERSTRING %token KWTOKENNULL %token NUMERICCONSTANT %token NUMERICUCONSTANT %token NUMERICLONGCONSTANT %token NUMERICULONGCONSTANT %token HEXCONSTANT %token HEXUCONSTANT %token HEXLONGCONSTANT %token HEXULONGCONSTANT %token OCTALCONSTANT %token OCTALUCONSTANT %token OCTALLONGCONSTANT %token OCTALULONGCONSTANT %token CHARACTERCONSTANT %token WIDECHARACTERCONSTANT %token IDENTIFIER %token KWSIZEOF %token TOKENTRUE %token TOKENFALSE /* These are Microsoft C abominations */ %token MSCDECLSPEC %token MSCDLLIMPORT %token MSCDLLEXPORT %token MSCEXPORT %token MSCFORTRAN %token MSCCDECL %token MSCSTDCALL %token MSCLOADDS %token MSCSAVEREGS %token MSCFASTCALL %token MSCSEGMENT %token MSCINTERRUPT %token MSCSELF %token MSCNEAR %token MSCFAR %token MSCUNALIGNED %token MSCHUGE %token MSCPASCAL %token MSCEMIT %token MSCASM /* Microsoft proposed extentions to NIDL */ %token KWNOCODE /* Allowed in .IDL in addition to .ACF */ /* These are residual C tokens I'm not sure we should even allow */ %token POINTSTO %token INCOP %token DECOP %token MULASSIGN %token DIVASSIGN %token MODASSIGN %token ADDASSIGN %token SUBASSIGN %token LEFTASSIGN %token RIGHTASSIGN %token ANDASSIGN %token XORASSIGN %token ORASSIGN %token DOTDOT %token LTEQ %token GTEQ %token NOTEQ %token LSHIFT %token RSHIFT %token ANDAND %token EQUALS %token OROR /* used by lex internally to signify "get another token" */ %token NOTOKEN /* garbage token - should cause parse errors */ %token GARBAGETOKEN /* OLE extensions */ %token KWOBJECT /* Note that we're assuming that we get constants back and can check bounds (e.g. "are we integer") in the semantic actoins. */ /* ACF - Specific Tokens */ %token KWSHAPE %token KWBYTECOUNT %token KWIMPLICITHANDLE %token KWAUTOHANDLE %token KWEXPLICITHANDLE %token KWREPRESENTAS %token KWCALLAS %token KWCODE %token KWINLINE %token KWOUTOFLINE %token KWINTERPRET %token KWNOINTERPRET %token KWCOMMSTATUS %token KWFAULTSTATUS %token KWHEAP %token KWINCLUDE %token KWPOINTERSIZE %token KWOFFLINE %token KWALLOCATE %token KWENABLEALLOCATE %token KWMANUAL %token KWNOTIFY %token KWNOTIFYFLAG %token KWUSERMARSHAL %token KWENCODE %token KWDECODE /* Currently Unsupported Tokens */ %token KWBITSET %token UUIDTOKEN %token VERSIONTOKEN %token EOI %token LASTTOKEN /* moved to ACF... */ /***************************************************************************** * %types of various non terminals and terminals *****************************************************************************/ %type AcfCallType %type AcfImpHdlTypeSpec %type AcfInterfaceAttribute %type AdditiveExpr %type AddOp %type AndExpr %type ArgExprList %type ArrayBoundsPair %type ArrayDecl %type ArrayDecl2 %type AssignmentExpr %type Attributes %type AttributesWithDefault %type AttrList %type AttrListWithDefault %type AttrSet %type AttrSetWithDefault %type AttrVar %type AttrVarList %type BaseInterfaceList %type BaseTypeSpec %type BitSetType %type CastExpr %type CHARACTERCONSTANT %type CharSpecs %type CoclassMember %type CoclassMemberList %type CoclassName %type ComClassDecl %type ComClassList %type ComServer %type ConditionalExpr %type ConstantExpr %type ConstantExprs %type CPragmaSet %type Declaration %type DeclarationAccessories %type DeclarationSpecifiers %type Declarator %type Declarator2 %type DispatchInterfaceBody %type DispatchInterfaceHeader %type DispatchInterfaceName %type TypedefDeclarator %type TypedefDeclaratorList %type TypedefDeclaratorListElement %type DefaultCase %type DirectionalAttribute %type EndPtSpec %type EndPtSpecs %type EnumerationType %type Enumerator %type EnumeratorList %type EnumSpecifier %type EqualityExpr %type ExclusiveOrExpr %type Expr %type FieldAttribute %type FuncModifier %type Guid %type HEXCONSTANT %type HEXLONGCONSTANT %type HEXUCONSTANT %type HEXULONGCONSTANT %type IDENTIFIER %type Import %type ImportName %type ImportList %type InclusiveOrExpr %type InitDeclarator %type InitDeclaratorList %type InternationalCharacterType %type IntModifiers %type IntSize %type IntSpec %type Initializer %type InitializerList %type InputFile %type InterfaceAttribute %type InterfaceBody %type InterfaceComp %type InterfaceComponent %type InterfaceComponents %type InterfaceHeader %type InterfaceList %type InterfaceName %type KWCPRAGMA %type LibraryBody %type LibraryHeader %type LibraryInterfaceList %type LibraryName %type LogicalAndExpr %type LogicalOrExpr %type MemberDeclaration %type MemberDeclarator %type MemberDeclaratorList %type MethodDeclaration %type MethodList %type MidlPragmaSet %type Modifier %type ModifierList %type ModuleBody %type ModuleHeader %type ModuleName %type MultOp %type MultipleImport %type MultExpr %type NidlMemberDeclaration %type NidlUnionBody %type NidlUnionCase %type NidlUnionCaseLabel %type NidlUnionCaseLabelList %type NidlUnionCases %type NidlUnionSwitch %type NUMERICCONSTANT %type NUMERICLONGCONSTANT %type NUMERICUCONSTANT %type NUMERICULONGCONSTANT %type ObjectName %type OCTALCONSTANT %type OCTALUCONSTANT %type OCTALLONGCONSTANT %type OCTALULONGCONSTANT %type OdlAttribute %type OneAttribute %type OneAttributeWithDefault %type OneInterface %type OperationAttribute %type OptionalAttrList %type OptionalAttrListWithDefault %type OptionalBaseIF %type OptionalComma %type OptionalConst %type OptionalDeclarator %type OptionalInitDeclaratorList %type OptionalMethodList %type OptionalModifierList %type OptionalModuleBody %type OptionalPropertyList %type OptionalTag %type OptPackIndex %type OptShape %type PackIndex %type ParameterDeclaration %type ParameterList %type ParameterTypeList %type ParamsDecl2 %type PhantomInputFile %type Pointer %type PostfixExpr %type PredefinedTypeSpec %type PrimaryExpr %type PropertyList %type PtrAttr %type PtrModifier %type PushOrPop %type RelationalExpr %type ServerType %type ShiftExpr %type SignSpecs %type SimpleTypeSpec %type StorageClassSpecifier %type STRING %type StructDeclarationList %type SwitchSpec %type SwitchTypeSpec %type Tag %type TaggedSpec %type TaggedStructSpec %type TaggedUnionSpec %type TypeAttribute %type TypeDeclarationSpecifiers %type TYPENAME %type TypeName %type LIBNAME %type TypeQualifier %type TypeSpecifier %type UnaryExpr %type UnaryOp %type UnimplementedTypeAttribute %type UnionBody %type UnionCase %type UnionCaseLabel %type UnionCases %type UnionName %type UUIDTOKEN %type VariableExpr %type VERSIONTOKEN %type WIDECHARACTERCONSTANT %type WIDECHARACTERSTRING /****************************************************************************/ %% RpcProg: ForceBaseIdl InputFile { node_source * pSource = new node_source; pSource->SetMembers( $2 ); pSourceNode = pSource; /** ** If there were errors detected in the 1st pass, the dont do ** anything. **/ if( !pCompiler->GetErrorCount() ) { /** ** If we found no errors, the first compiler phase is over **/ return; } else { // if the errors prevented a resolution pass and semantics // to be performed, then issue a message. For that purpose // look at the node state of the source node. If it indicates // presence of a forward decl, then we must issue the error ParseError( ERRORS_PASS1_NO_PASS2, (char *)0 ); } /** ** If we reached here, there were errors detected, and we dont ** want to invoke the subsequent passes, Just quit. **/ pSourceNode = (node_source *)NULL; returnflag = 1; return; } ; InputFile: InterfaceList EOI { // create file node, add imports node_file * pFile; named_node * pN; char * pInputFileName; /** ** pick up the details of the file, because we need to set the ** file nodes name with this file **/ pImportCntrl->GetInputDetails( &pInputFileName ); pFile = new node_file( pInputFileName, ImportLevel ); /** ** Attach the interface nodes as a member of the file node. ** Also, point the interface nodes to their parent file node. **/ pFile->SetMembers( $1.Members ); MEM_ITER MemIter(pFile); while ( pN = MemIter.GetNext() ) { pN->SetFileNode( pFile ); } /** ** we may have collected the more file nodes as part of the reduction ** process. If so, then attach this node to the list. If not then ** generate a new list and attach the file node there **/ if( $1.Imports ) $$ = $1.Imports; else $$.Init(); $$.SetPeer( pFile ); } ; InterfaceList: InterfaceList OneInterface { if( !pCommand->IsSwitchDefined( SWITCH_MS_EXT ) ) { ParseError( MULTIPLE_INTF_NON_OSF, NULL ); } // if we have dangling definitions, add them to the intf if ( $2.Members.Tail() && ( !$2.Members.Tail()->IsInterfaceOrObject() ) ) { node_interface * pIntf = pInterfaceInfoDict->GetInterfaceNode(); $$ = $1; $$.Imports.Merge( $2.Imports ); pIntf->MergeMembersToTail( $2.Members ); if ( $1.Members.Tail() != pIntf ) $$.Members.Add( pIntf ); } else { // merge interface list and imports list $$ = $1; $$.Imports.Merge( $2.Imports ); $$.Members.Merge( $2.Members ); } } | OneInterface { if ( $1.Members.Tail() && ( !$1.Members.Tail()->IsInterfaceOrObject() ) ) { node_interface * pIntf = pInterfaceInfoDict->GetInterfaceNode(); // gets siblist of declarations pIntf->MergeMembersToTail( $1.Members ); $$.Imports = $1.Imports; $$.Members.Init( pIntf ); } else { // pass interface list and imports list $$ = $1; } } ; LibraryInterfaceList: LibraryInterfaceList OneInterface { // merge interface list and imports list $$ = $1; $$.Imports.Merge( $2.Imports ); $$.Members.Merge( $2.Members ); } | OneInterface ; OneInterface: InterfaceHeader InterfaceBody '}' OptionalSemicolon { /** ** This is the place where the complete interface construct ** has been reduced. We need to hook the body to the interface ** and pass it up, with the imports **/ node_interface * pInterface = $1.pInterface; pInterface->SetMembers( $2.Members ); $$.Imports = $2.Imports; $$.Members.Init( pInterface ); /** ** Start a new interface info dict in case there are ** multiple interfaces in this file. **/ pInterfaceInfoDict->EndNewInterface(); pInterfaceInfoDict->StartNewInterface(); // start a dummy interface for intervening stuff node_interface * pOuter = new node_interface; pOuter->SetSymName( GenIntfName() ); pInterfaceInfoDict->SetInterfaceNode( pOuter ); pOuter->SetAttribute( new battr( ATTR_LOCAL ) ); pOuter->SetProcTbl( (ImportLevel != 0) ? new SymTable : pBaseSymTbl ); } | OptionalAttrList InterfaceName ';' { // put in a forward declaration SymKey SKey( $2, NAME_DEF ); named_node * pNode; pNode = new node_forward( SKey, pBaseSymTbl ); pNode->SetSymName( $2 ); // tbd - error if $1.NonNull() named_node * pFound; pFound = pBaseSymTbl->SymSearch( SKey ); if (pFound && pFound->NodeKind() != NODE_HREF && pFound->NodeKind() != NODE_INTERFACE && NULL != pFound->GetDefiningFile()) { pBaseSymTbl->SymDelete( SKey ); } if(!pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, pNode )) { // ParseError( DUPLICATE_DEFINITION, pName ); } $$.Imports.Init(); $$.Members.Init( pNode ); } | OptionalAttrList DispatchInterfaceName ';' { // put in a forward declaration SymKey SKey( $2, NAME_DEF ); named_node * pNode; pNode = new node_forward( SKey, pBaseSymTbl ); pNode->SetSymName( $2 ); // tbd - error if $1.NonNull() named_node * pFound; pFound = pBaseSymTbl->SymSearch( SKey ); if (pFound && pFound->NodeKind() != NODE_HREF && pFound->NodeKind() != NODE_DISPINTERFACE && NULL != pFound->GetDefiningFile()) { pBaseSymTbl->SymDelete( SKey ); } if(!pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, pNode )) { // ParseError( DUPLICATE_DEFINITION, pName ); } $$.Imports.Init(); $$.Members.Init( pNode ); } | OptionalAttrList CoclassName ';' { // put in a forward declaration SymKey SKey( $2, NAME_DEF ); named_node * pNode; pNode = new node_forward( SKey, pBaseSymTbl ); pNode->SetSymName( $2 ); // tbd - error if $1.NonNull() named_node * pFound; pFound = pBaseSymTbl->SymSearch( SKey ); if (pFound && pFound->NodeKind() != NODE_HREF && pFound->NodeKind() != NODE_COCLASS && NULL != pFound->GetDefiningFile()) { pBaseSymTbl->SymDelete( SKey ); } if(!pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, pNode )) { // ParseError( DUPLICATE_DEFINITION, pName ); } $$.Imports.Init(); $$.Members.Init( pNode ); } | OptionalAttrList ModuleName ';' { // put in a forward declaration SymKey SKey( $2, NAME_DEF ); named_node * pNode; pNode = new node_forward( SKey, pBaseSymTbl ); pNode->SetSymName( $2 ); // tbd - error if $1.NonNull() named_node * pFound; pFound = pBaseSymTbl->SymSearch( SKey ); if (pFound && pFound->NodeKind() != NODE_HREF && pFound->NodeKind() != NODE_MODULE && NULL != pFound->GetDefiningFile()) { pBaseSymTbl->SymDelete( SKey ); } if(!pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, pNode )) { // ParseError( DUPLICATE_DEFINITION, pName ); } $$.Imports.Init(); $$.Members.Init( pNode ); } | OptionalAttrList ObjectName ';' { // put in a forward declaration SymKey SKey( $2, NAME_DEF ); named_node * pNode; pNode = new node_forward( SKey, pBaseSymTbl ); pNode->SetSymName( $2 ); // tbd - error if $1.NonNull() if(!pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, pNode )) { // ParseError( DUPLICATE_DEFINITION, pName ); } $$.Imports.Init(); $$.Members.Init( pNode ); } | Import { if( !pCommand->IsSwitchDefined( SWITCH_MS_EXT ) && !((node_file*)$1.Tail())->IsXXXBaseIdl() ) { ParseError( OUTSIDE_OF_INTERFACE, NULL ); } // returns siblist // these need to get saved up so they will be added to // the header file $$.Imports = $1; $$.Members.Init(); } | InterfaceComponent { if( !pCommand->IsSwitchDefined( SWITCH_MS_EXT ) ) { ParseError( OUTSIDE_OF_INTERFACE, NULL ); } // pass up a sibling list $$.Imports.Init(); $$.Members = $1; } | ComServer { $$.Imports.Init(); $$.Members.Init( $1 ); } | LibraryHeader ForceBaseOdl LibraryBody '}' OptionalSemicolon { /** ** This is the place where the complete library construct ** has been reduced. We need to hook the body to the library ** and pass it up, with the imports **/ node_library * pLibrary = $1.pLibrary; pLibrary->SetMembers( $3.Members ); $$.Imports = $3.Imports; $$.Members.Init( pLibrary ); // Throw the big "case sensitive again" switch here gfCaseSensitive = TRUE; // return to the previous Import Level ImportLevel--; } | KWIMPORTLIB '(' STRING ')' ';' { if ( !FAddImportLib($3) ) { ParseError(TYPELIB_NOT_LOADED, $3); } $$.Imports.Init(); $$.Members.Init(); } | ModuleHeader PhantomPushSymtab OptionalModuleBody OptionalSemicolon { /** ** discard the inner symbol table contents (unless it had fwds) **/ pCurSymTbl->DiscardScope(); /** ** restore the symbol table level **/ pSymTblMgr->PopSymLevel( &pCurSymTbl ); node_module * pModule = $1.pModule; pModule->SetMembers($3); $$.Members.Init( pModule ); $$.Imports.Init(); /** ** Start a new interface info dict in case there are ** multiple interfaces in this file. **/ pInterfaceInfoDict->EndNewInterface(); pInterfaceInfoDict->StartNewInterface(); // start a dummy interface for intervening stuff node_interface * pOuter = new node_interface; pOuter->SetSymName( GenIntfName() ); pInterfaceInfoDict->SetInterfaceNode( pOuter ); pOuter->SetAttribute( new battr( ATTR_LOCAL ) ); pOuter->SetProcTbl( (ImportLevel != 0) ? new SymTable : pBaseSymTbl ); } | DispatchInterfaceHeader PhantomPushSymtab DispatchInterfaceBody '}' OptionalSemicolon { /** ** discard the inner symbol table contents (unless it had fwds) **/ pCurSymTbl->DiscardScope(); /** ** restore the symbol table level **/ pSymTblMgr->PopSymLevel( &pCurSymTbl ); node_dispinterface * pDispInterface = $1.pDispInterface; pDispInterface->SetMembers($3); $$.Members.Init(pDispInterface); $$.Imports.Init(); /** ** Start a new interface info dict in case there are ** multiple interfaces in this file. **/ pInterfaceInfoDict->EndNewInterface(); pInterfaceInfoDict->StartNewInterface(); // start a dummy interface for intervening stuff node_interface * pOuter = new node_interface; pOuter->SetSymName( GenIntfName() ); pInterfaceInfoDict->SetInterfaceNode( pOuter ); pOuter->SetAttribute( new battr( ATTR_LOCAL ) ); pOuter->SetProcTbl( (ImportLevel != 0) ? new SymTable : pBaseSymTbl ); } | OptionalAttrList CoclassName '{' PhantomPushSymtab CoclassMemberList '}' OptionalSemicolon { /** ** discard the inner symbol table contents (unless it had fwds) **/ pCurSymTbl->DiscardScope(); /** ** restore the symbol table level **/ pSymTblMgr->PopSymLevel( &pCurSymTbl ); char * szName = $2; node_coclass * pCoclass = new node_coclass(); pCoclass->AddAttributes($1); pCoclass->SetSymName(szName); pCoclass->SetMembers( $5); // add coclass node to the global symbol table SymKey SKey (szName, NAME_DEF); named_node * pFound; pFound = pBaseSymTbl->SymSearch( SKey ); //if (pFound && ( pFound->NodeKind() == NODE_FORWARD || pFound->NodeKind() == NODE_HREF )) if (pFound && ( pFound->NodeKind() == NODE_FORWARD || NULL != pFound->GetDefiningFile() )) { pBaseSymTbl->SymDelete( SKey ); } if (!pBaseSymTbl->SymInsert(SKey, (SymTable *) NULL, pCoclass)) { ParseError(DUPLICATE_DEFINITION, szName); } $$.Members.Init( pCoclass ); $$.Imports.Init(); } ; ModuleHeader: OptionalAttrList ModuleName '{' { char * szName = $2; node_module * pModule = new node_module(); pModule->AddAttributes($1); pModule->SetSymName(szName); // modules get a private scope for procs pModule->SetProcTbl(new SymTable); // start the new module pInterfaceInfoDict->SetInterfaceNode(pModule); // add module node to the base symbol table SymKey SKey (szName, NAME_DEF); named_node * pFound; pFound = pBaseSymTbl->SymSearch( SKey ); //if (pFound && ( pFound->NodeKind() == NODE_FORWARD || pFound->NodeKind() == NODE_HREF )) if (pFound && ( pFound->NodeKind() == NODE_FORWARD || NULL != pFound->GetDefiningFile() )) { pBaseSymTbl->SymDelete( SKey ); } if (!pBaseSymTbl->SymInsert(SKey, (SymTable *) NULL, pModule)) { ParseError(DUPLICATE_DEFINITION, szName); } $$.pModule = pModule; } ; DispatchInterfaceHeader: OptionalAttrList DispatchInterfaceName '{' { char * szName = $2; node_dispinterface * pDispInterface = new node_dispinterface(); pDispInterface->AddAttributes($1); pDispInterface->SetSymName(szName); // dipatchinterfaces get a private scope for procs pDispInterface->SetProcTbl(new SymTable); // start the new dispatchinterface pInterfaceInfoDict->SetInterfaceNode(pDispInterface); // add dispinterface node to the global symbol table SymKey SKey (szName, NAME_DEF); named_node * pFound; pFound = pBaseSymTbl->SymSearch( SKey ); //if (pFound && ( pFound->NodeKind() == NODE_FORWARD || pFound->NodeKind() == NODE_HREF )) if (pFound && ( pFound->NodeKind() == NODE_FORWARD || NULL != pFound->GetDefiningFile() )) { pBaseSymTbl->SymDelete( SKey ); } if (!pBaseSymTbl->SymInsert(SKey, (SymTable *) NULL, pDispInterface)) { ParseError(DUPLICATE_DEFINITION, szName); } $$.pDispInterface = pDispInterface; } ; OptionalSemicolon: ';' | /* nothing */ ; LibraryHeader: OptionalAttrList LibraryName '{' { // make sure that only one library statement exists char * szName = $2; if (fLibrary) { ParseError(TWO_LIBRARIES, szName); } fLibrary = TRUE; // create library node node_library * pLibrary = new node_library(); $$.pLibrary = pLibrary; pLibrary->AddAttributes($1); pLibrary->SetSymName(szName); // throw the big "case insensitive" switch here gfCaseSensitive = FALSE; // Bump the Import Level to ensure that interfaces under the // library statement are treated correctly. ImportLevel++; } ; LibraryName: KWLIBRARY Tag { $$ = $2; } ; LibraryBody: LibraryInterfaceList // just pass back what we get from the list of interfaces | /* nothing */ { // initialize and return an empty list $$.Imports.Init(); $$.Members.Init(); } ; ModuleName: KWMODULE Tag { $$ = $2; } ; OptionalModuleBody: ModuleBody '}' | '}' { $$.Init(); } ; ModuleBody: ModuleBody MethodDeclaration { $$.Merge($2); } | MethodDeclaration ; DispatchInterfaceName: KWDISPINTERFACE Tag { $$ = $2; } ; DispatchInterfaceBody: KWPROPERTIES ':' OptionalPropertyList KWMETHODS ':' OptionalMethodList { $$ = $3; $$.Merge($6); // Can I tell where the properties stop and the methods begin? // And does it really matter? } | InterfaceName ';' { // put in a forward declaration SymKey SKey( $1, NAME_DEF ); named_node * pNode; pNode = new node_forward( SKey, pBaseSymTbl ); pNode->SetSymName( $1 ); // tbd - error if $1.NonNull() if(!pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, pNode )) { // ParseError( DUPLICATE_DEFINITION, pName ); } $$.Init( pNode ); } | /* nothing */ { $$.Init(); } ; OptionalPropertyList: PropertyList | /* nothing */ { $$.Init(); } ; PropertyList: PropertyList MemberDeclaration { $$.Merge($2); } | MemberDeclaration ; OptionalMethodList: MethodList | /* nothing */ { $$.Init(); } ; MethodList: MethodList MethodDeclaration { $$.Merge($2); } | MethodDeclaration ; MethodDeclaration: OptionalAttrList Declaration { $2.AddAttributes($1); $$ = $2; /** ** Check to see if it has a property attribute. ** If it does, remove its name from the symbol table, ** decorate it with the appropriate decoration ** and re-insert it into the symbol table **/ BOOL fPropPut = FALSE; BOOL fPropGet = FALSE; BOOL fPropPutRef = FALSE; node_base_attr * pCur = $1.GetFirst(); named_node * pNode = $$.Tail(); char * szName = pNode->GetSymName(); while (pCur) { if (pCur->GetAttrID() == ATTR_MEMBER) { switch(((node_member_attr *)pCur)->GetAttr()) { case MATTR_PROPPUT: fPropPut = TRUE; if (fPropGet | fPropPutRef) ParseError(MULTIPLE_PROPERTY_ATTRIBUTES, szName); break; case MATTR_PROPGET: fPropGet = TRUE; if (fPropPut | fPropPutRef) ParseError(MULTIPLE_PROPERTY_ATTRIBUTES, szName); break; case MATTR_PROPPUTREF: fPropPutRef = TRUE; if (fPropGet | fPropPut) ParseError(MULTIPLE_PROPERTY_ATTRIBUTES, szName); break; } } pCur = pCur->GetNext(); } if (fPropPut | fPropGet | fPropPutRef) { // remove the name from the correct symbol table SymKey SKey(szName, NAME_PROC); SymTable * pSymTable = pInterfaceInfoDict->GetInterfaceProcTable(); named_node * pFound = pSymTable->SymSearch(SKey); if (pNode == pFound) { pSymTable->SymDelete(SKey); char * szNewName; if (fPropPut) { szNewName = new char[strlen(szName) + 5]; sprintf(szNewName , "put_%s", szName); } else if (fPropGet) { szNewName = new char[strlen(szName) + 5]; sprintf(szNewName , "get_%s", szName); } else { szNewName = new char[strlen(szName) + 8]; sprintf(szNewName , "putref_%s", szName); } pFound->SetSymName(szNewName); SymKey SNewKey(szNewName, NAME_PROC); pSymTable->SymInsert(SNewKey, (SymTable *)NULL, pFound); } else ParseError(ILLEGAL_USE_OF_PROPERTY_ATTRIBUTE, szName); } } ; CoclassName: KWCOCLASS Tag { $$ = $2; } ; CoclassMemberList: CoclassMemberList CoclassMember { $$.Merge($2); } | CoclassMember ; CoclassMember: OptionalAttrListWithDefault DispatchInterfaceName ';' { // put in a forward declaration SymKey SKey( $2, NAME_DEF ); named_node * pNode; pNode = new node_forward( SKey, pBaseSymTbl ); pNode->SetSymName( $2 ); // tbd - error if $2.NonNull() if(!pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pNode )) { // ParseError( DUPLICATE_DEFINITION, pName ); } // bugbug - how to I verify that the name actually belongs to a DispInterface? $$.Init( pNode ); $$.AddAttributes($1); } | OptionalAttrListWithDefault InterfaceName ';' { // put in a forward declaration SymKey SKey( $2, NAME_DEF ); named_node * pNode; pNode = new node_forward( SKey, pBaseSymTbl ); pNode->SetSymName( $2 ); // tbd - error if $2.NonNull() if(!pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pNode )) { // ParseError( DUPLICATE_DEFINITION, pName ); } // bugbug - how to I verify that the name actually belongs to an Interface? $$.Init( pNode ); $$.AddAttributes($1); } ; ForceBaseOdl: /* nothing */ { /* force the lexer to return import "oaidl.idl"; */ if ( !fOdlBaseImported) { /* Make sure the MS_EXT and C_EXT switches get defined */ pCommand->SwitchDefined( SWITCH_MS_EXT ); pCommand->SwitchDefined( SWITCH_C_EXT ); // make sure the change sticks pCommand->SetModeSwitchConfigMask(); LexContext = LEX_ODL_BASE_IMPORT; fOdlBaseImported = TRUE; } } ForceBaseIdl: /* nothing */ { /* force the lexer to return import "idlbase.idl" ; * in the first interface */ if ( !fBaseImported ) { if( pCommand->IsSwitchDefined( SWITCH_IDLBASE ) ) LexContext = LEX_BASE_IMPORT2; fBaseImported = TRUE; } node_interface * pOuter = new node_interface; pOuter->SetSymName( GenIntfName() ); pInterfaceInfoDict->SetInterfaceNode( pOuter ); pOuter->SetAttribute( new battr( ATTR_LOCAL ) ); pOuter->SetProcTbl( (ImportLevel != 0) ? new SymTable : pBaseSymTbl ); } ; InterfaceHeader: OptionalAttrList InterfaceName OptionalBaseIF '{' { node_interface_reference * pRef; char * pName = $2; node_interface * pIntf = new node_interface(); $$.pInterface = pIntf; pIntf->AddAttributes( $1 ); // interfaces with inheritance implicitly become object interfaces now... if ( $3 ) { if ( !pIntf->FInSummary( ATTR_OBJECT ) ) { pIntf->SetAttribute( ATTR_OBJECT ); } } // object intfs get a private scope for procs, imported intfs, too if ( pIntf->FInSummary( ATTR_OBJECT ) || ( ImportLevel != 0 ) ) pIntf->SetProcTbl( new SymTable ); else pIntf->SetProcTbl( pBaseSymTbl ); pIntf->SetSymName( pName ); if ( !strcmp( pName, "IUnknown" ) ) pIntf->SetValidRootInterface(); pRef = new node_interface_reference( pIntf ); // add the interface reference node to the base symbol table as if // it were a typedef SymKey SKey( pName, NAME_DEF ); named_node * pFound; pFound = pBaseSymTbl->SymSearch( SKey ); //if ( pFound && ( pFound->NodeKind() == NODE_FORWARD || pFound->NodeKind() == NODE_HREF) ) if (pFound && ( pFound->NodeKind() == NODE_FORWARD || NULL != pFound->GetDefiningFile() )) { pBaseSymTbl->SymDelete( SKey ); } if(!pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, pRef )) { ParseError( DUPLICATE_DEFINITION, pName ); } // set the base interface of this interface // this MAY be a node_forward pIntf->SetMyBaseInterfaceReference( (named_node *) $3 ); // start the new interface pInterfaceInfoDict->SetInterfaceNode( pIntf ); } | OptionalAttrList ObjectName BaseInterfaceList '{' { node_interface_reference * pRef; char * pName = $2; node_object * pIntf = new node_object(); $$.pInterface = pIntf; pIntf->AddAttributes( $1 ); // objects get a private scope for procs pIntf->SetProcTbl( new SymTable ); pIntf->SetSymName( pName ); pRef = new node_interface_reference( pIntf ); // add the interface reference node to the base symbol table as if // it were a typedef SymKey SKey( pName, NAME_DEF ); named_node * pFound; pFound = pBaseSymTbl->SymSearch( SKey ); //if ( pFound && ( pFound->NodeKind() == NODE_FORWARD || pFound->NodeKind() == NODE_HREF )) if (pFound && ( pFound->NodeKind() == NODE_FORWARD || NULL != pFound->GetDefiningFile() )) { pBaseSymTbl->SymDelete( SKey ); } if(!pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, pRef )) { ParseError( DUPLICATE_DEFINITION, pName ); } // set the base interface list of this object // this MAY include node_forwards pIntf->SetMyBaseInterfaceList( $3 ); // start the new interface/object pInterfaceInfoDict->SetInterfaceNode( pIntf ); } ; OptionalBaseIF: ':' Tag { node_skl * pNode; SymKey SKey( $2, NAME_DEF ); BOOL fNotFound = ! ( pNode = pBaseSymTbl->SymSearch( SKey ) ); if( fNotFound || (pNode->NodeKind() == NODE_FORWARD ) ) { pNode = new node_forward( SKey, pBaseSymTbl ); ((named_node *)pNode)->SetSymName( $2 ); } //Return a node_forward or a node_interface_reference. $$ = pNode; } | /* Empty */ { $$ = NULL; } ; BaseInterfaceList: ':' Tag { node_skl * pNode; SymKey SKey( $2, NAME_DEF ); BOOL fNotFound = ! ( pNode = pBaseSymTbl->SymSearch( SKey ) ); if( fNotFound || (pNode->NodeKind() == NODE_FORWARD ) ) { pNode = new node_forward( SKey, pBaseSymTbl ); ((named_node *)pNode)->SetSymName( $2 ); } //Return a new list with a node_forward or a node_interface_reference. $$ = new type_node_list; if( pNode ) $$->SetPeer( pNode ); } | BaseInterfaceList ',' Tag { node_skl * pNode; SymKey SKey( $3, NAME_DEF ); BOOL fNotFound = ! ( pNode = pBaseSymTbl->SymSearch( SKey ) ); if( fNotFound || (pNode->NodeKind() == NODE_FORWARD ) ) { pNode = new node_forward( SKey, pBaseSymTbl ); ((named_node *)pNode)->SetSymName( $3 ); } //Add a node_forward or a node_interface_reference to the list. $$ = $1; $$->SetPeer(pNode); } ; InterfaceName: KWINTERFACE Tag { $$ = $2; } ; ObjectName: KWCLASS Tag { // complain if they werent supposed to use these if ( !pCommand->IsComClassOK() ) ParseError( UNDEFINED_SYMBOL, "class" ); $$ = $2; } ; ComServer: ServerType OptionalTag '{' ComClassList '}' { node_com_server * pServer = new node_com_server( $2 ); pServer->SetServerType( $1 ); pServer->SetClassList( $4 ); $$ = pServer; } ; ComClassList: ComClassList ComClassDecl { $$ = $1; $$->SetPeer( $2 ); } | ComClassDecl { type_node_list * pList = new type_node_list( $1 ); $$ = pList; } ; TypeName: TYPENAME | LIBNAME "." TYPENAME { char * szType = $3->GetSymName(); node_skl * pNode = (named_node *)AddQualifiedReferenceToType($1, szType); if (!pNode) { char * sz = new char [strlen($1) + strlen(szType) + 2]; strcpy(sz, $1); strcat(sz, "."); strcat(sz, szType); ParseError( UNDEFINED_SYMBOL, sz); pNode = $3; } $$ = pNode; } ; ComClassDecl: KWCLASS TypeName ';' { $$ = $2; } ; ServerType: KWDLLSERVER { // complain if they werent supposed to use these if ( !pCommand->IsComClassOK() ) ParseError( UNDEFINED_SYMBOL, "dllserver" ); $$ = COM_SERVER_IS_DLL; } | KWEXESERVER { // complain if they werent supposed to use these if ( !pCommand->IsComClassOK() ) ParseError( UNDEFINED_SYMBOL, "exeserver" ); $$ = COM_SERVER_IS_EXE; } ; InterfaceBody: MultipleImport InterfaceComp { /** ** This production is reduced when there is at least 1 imported ** file **/ $$.Imports = $1; $$.Members = $2; } | InterfaceComp { /** ** This production is reduced when there is NO import in the file **/ $$.Imports.Init(); $$.Members = $1; } ; /** ** All the interface components have been reduced. **/ InterfaceComp: InterfaceComponents | /* Nothing */ { $$.Init(); } ; MultipleImport: MultipleImport Import { $$ = $1; $$.Merge( $2 ); } | Import ; Import: KWIMPORT ImportList ';' { $$ = $2; } | KWIMPORTIDLBASE ImportList { $$ = $2; ((node_file*)$$.Tail()) ->SetXXXBaseIdl(); } | KWIMPORTODLBASE ImportList { $$ = $2; } ; ImportList: ImportName | ImportList ',' ImportName { $$ = $1; $$.Merge( $3 ); } ; /** ** Imports are handled by making them part of the syntax. The following set of ** productions control the import. As soon as an import string is seen, we ** must get the productions from another idl file. It would be great if we ** could recursively call the parser here. But yacc does not generate a ** parser which can be recursivel called. So we make the idl syntax right ** recursive by introducing "InputFile" at the rhs of the Importname ** production. The type graph then gets generated with the imported parts of ** the type graph compeleting first. We keep merging the type graphs from the ** imported files. The beauty of this is that the parser does not have to do ** any work at all. The parse tells the import controller to push his import ** level, and switch input from another file. The import controller can do ** this very easily. Then when the parser driver asks for the next token, it ** will be from the imported file. Thus the parser conspires with the file ** handler to fool itself and the lexer. This whole scheme makes it very ** easy on all components - the parser, lexer and the file handler. ** ** import of an already imported file is an idempotent operation. We can ** generate the type graph of the reduncdantly imported file and then throw it ** away, but that is wasteful. Again, the file handler helps. If it finds that ** a file was redundantly imported, it just sets itself up so that it returns ** an end of file on the next getchar operation on the file. This makes it ** very easy for the parser. It can either expect an interface syntax after the ** import statement or it can expect an end of file. Thus 2 simple productions ** take care of this entire problem. **/ ImportName: STRING { /** ** we just obtained the import file name as a string. Immediately ** following, we must switch the input from the imported file. **/ // push the current case sensitive setting on the stack gCaseStack.Push(gfCaseSensitive); // switch to case sensitive mode gfCaseSensitive = TRUE; pImportCntrl->PushLexLevel(); if( pImportCntrl->SetNewInputFile( $1 ) != STATUS_OK ) { $$.Init(); returnflag = 1; return; } /** ** update the quick reference import level indicator **/ ImportLevel++; // the new file gets its own Zp stack PushZpStack( pPackStack, CurrentZp ); // prepare for anything not in an interface body pInterfaceInfoDict->StartNewInterface(); node_interface * pOuter = new node_interface; pOuter->SetSymName( GenIntfName() ); pInterfaceInfoDict->SetInterfaceNode( pOuter ); pOuter->SetAttribute( new battr( ATTR_LOCAL ) ); pOuter->SetProcTbl( (ImportLevel != 0) ? new SymTable : pBaseSymTbl ); } PhantomInputFile { /** ** The phantom interface production is introduced to unify the actions ** from a successful and unsuccessful import. An import can be ** errorneous if the file being imported has been imported before. **/ BOOL fError = !( ( $$ = $3 ).NonNull() ); /** ** Restore the lexical level of the import controller. **/ pImportCntrl->PopLexLevel(); pInterfaceInfoDict->EndNewInterface(); // return to the enclosing files Zp stack PopZpStack( pPackStack, CurrentZp ); ImportLevel--; // // The filehandler will return an end of file if the file was a // redundant import OR there was a genuine end of file. It will set // a flag, fRedundantImport to differentiate between the two situations. // Report different syntax errors in both these cases. // if( fError ) { if( fRedundantImport ) ParseError( REDUNDANT_IMPORT, $1 ); else { ParseError( UNEXPECTED_END_OF_FILE, $1 ); } } fRedundantImport = FALSE; // pop the previous case sensitive mode back off the stack gCaseStack.Pop(gfCaseSensitive); } ; PhantomInputFile: InputFile { /** ** InputFile is a list of file nodes **/ char * pInputFileName; $$ = $1; pImportCntrl->GetInputDetails( &pInputFileName ); AddFileToDB( pInputFileName ); } | EOI { $$.Init(); } ; InterfaceComponents: InterfaceComponents InterfaceComponent { $$ = $1; $$.Merge( $2 ); } | InterfaceComponent ; /* Note that we have to semantically verify that the declaration which has operation attributes is indeed a function prototype. */ InterfaceComponent: CPragmaSet { $$.Init($1); } | MidlPragmaSet { $$.Init($1); } | KWCPPQUOTE '(' STRING ')' { ParseError( CPP_QUOTE_NOT_OSF, (char *)0 ); $3 = MakeNewStringWithProperQuoting( $3 ); $$.Init( new node_echo_string( $3 ) ); } | MethodDeclaration ; CPragmaSet: KWCPRAGMA { /** ** we need to emit the c pragma strings as they are. ** we introduce the echo string node, so that the back end can ** emit it without even knowing the difference. **/ #define PRAGMA_PACK_STRING ("#pragma pack( ") #define PRAGMA_STRING ("#pragma ") char * p = new char [ strlen( $1 ) + strlen( PRAGMA_STRING ) + 1 ]; strcpy( p, PRAGMA_STRING ); strcat( p, $1 ); $$ = new node_echo_string( p ); } | KWCPRAGMAPACK '(' ')' { node_pragma_pack * pPack; /* return to global packing level */ pPack = new node_pragma_pack( NULL, pCommand->GetZeePee(), PRAGMA_PACK_RESET ); CurrentZp = pCommand->GetZeePee(); $$ = pPack; } | KWCPRAGMAPACK '(' PackIndex ')' { /* set current packing level */ if ( $3 ) { node_pragma_pack * pPack; /* switch top to new packing level */ pPack = new node_pragma_pack( NULL, 0, PRAGMA_PACK_SET, $3 ); CurrentZp = $3; $$ = pPack; } else $$ = NULL; } | KWCPRAGMAPACK '(' PushOrPop OptPackIndex ')' { node_pragma_pack * pPack; switch( $3 ) { case PRAGMA_PACK_PUSH: { // do push things // push current zp /* switch top to new packing level */ pPack = new node_pragma_pack( NULL, CurrentZp, PRAGMA_PACK_PUSH, $4 ); pPack->Push( pPackStack ); $$ = pPack; if ( $4 ) CurrentZp = $4; break; } case PRAGMA_PACK_POP: { // do pop things /* switch top to new packing level */ pPack = new node_pragma_pack( NULL, $4, PRAGMA_PACK_POP ); CurrentZp = pPack->Pop( pPackStack ); if ( !CurrentZp ) { CurrentZp = pCommand->GetZeePee(); ParseError(MISMATCHED_PRAGMA_POP, NULL ); } $$ = pPack; break; } default: $$ = NULL; } } | KWCPRAGMAPACK '(' PushOrPop ',' IDENTIFIER OptPackIndex ')' { node_pragma_pack * pPack; switch( $3 ) { case PRAGMA_PACK_PUSH: { // do push things // push current zp /* switch top to new packing level */ pPack = new node_pragma_pack( $5, CurrentZp, PRAGMA_PACK_PUSH, $6 ); pPack->Push( pPackStack ); $$ = pPack; if ( $6 ) CurrentZp = $6; break; } case PRAGMA_PACK_POP: { // do pop things /* switch top to new packing level */ pPack = new node_pragma_pack( $5, $6, PRAGMA_PACK_POP ); CurrentZp = pPack->Pop( pPackStack ); if ( !CurrentZp ) { CurrentZp = pCommand->GetZeePee(); ParseError(MISMATCHED_PRAGMA_POP, NULL ); } $$ = pPack; break; } default: $$ = NULL; } } ; PushOrPop: IDENTIFIER { if ( !strcmp( $1, "push" ) ) { $$ = PRAGMA_PACK_PUSH; } else if ( !strcmp( $1, "pop" ) ) { $$ = PRAGMA_PACK_POP; } else { ParseError( UNKNOWN_PRAGMA_OPTION, $1); $$ = PRAGMA_PACK_GARBAGE; } } ; OptPackIndex: ',' PackIndex { $$ = $2; } | /* null */ { $$ = 0; } ; PackIndex: NUMERICCONSTANT { switch ( $1.Val ) { case 1: case 2: case 4: case 8: $$ = (short) $1.Val; break; default: ParseError( UNKNOWN_PRAGMA_OPTION, $1.pValStr); $$ = 0; } } ; MidlPragmaSet: KWMPRAGMAIMPORT '(' IDENTIFIER ')' { /** ** We need to set import on and off here **/ char * p; if( strcmp( $3, "off" ) == 0 ) { p = "/* import off */"; fPragmaImportOn = FALSE; } else if( strcmp( $3, "on" ) == 0 ) { p = "/* import on */"; fPragmaImportOn = TRUE; } else p = "/* import unknown */"; $$ = new node_echo_string( p ); } | KWMPRAGMAECHO '(' STRING ')' { $3 = MakeNewStringWithProperQuoting( $3 ); $$ = new node_echo_string( $3 ); } | KWMPRAGMAIMPORTCLNTAUX '(' STRING ',' STRING ')' { $$ = NULL; } | KWMPRAGMAIMPORTSRVRAUX '(' STRING ',' STRING ')' { $$ = NULL; } ; Declaration: KWTYPEDEF OptionalAttrList TypeDeclarationSpecifiers TypedefDeclaratorList { /** ** create new typedef nodes for each of the declarators, apply any ** type attributes to the declarator. The declarators will have a ** basic type as specied by the Declaration specifiers. ** Check for the presence of a init expression. The typedef derives ** the declarators from the same place as the other declarators, so ** an init list must be explicitly checked for and reported as a ** syntax error. But dont report errors for each declarator, instead ** report it only once at the end. **/ class _DECLARATOR * pDec; char * pName; node_skl * pType; DECLARATOR_LIST_MGR pDeclList( $4 ); /** ** prepare for a list of typedefs to be made into interface ** components **/ $$.Init(); while( pDec = pDeclList.DestructiveGetNext() ) { node_def_fe * pDef = (node_def_fe *) pDec->pHighest; pType = $3.pNode; if (NULL == pDef) { /** ** The declaration is a forward declaration following the ** goofy mktyplib syntax: typedef struct foo; (or union). ** We need to verify that the mktyplib203 switch is set ** (only allow this syntax in mktyplib compatibility mode) ** and we need to create a forward declaration so that ** future references will resolve correctly. **/ pName = pType->GetSymName(); SymKey SKey( pName, NAME_DEF ); node_forward * pFwd = new node_forward( SKey, pCurSymTbl ); pFwd->SetSymName( pName ); pDef = new node_def_fe(pName, pFwd); pDec->Init(pDef); if (!pCommand->IsSwitchDefined(SWITCH_MKTYPLIB)) ParseError( ILLEGAL_USE_OF_MKTYPLIB_SYNTAX, pName); } else { pName = pDef->GetSymName(); } /** ** set the basic type of the declarator. **/ pDec->pLowest->SetChild( pType ); // complain about invalid redef of wchar_t or error_status_t if (pName) { if ( strcmp( pName, "wchar_t" ) == 0 ) { node_skl * pN = pType; if( !((pN->NodeKind() == NODE_SHORT) && pN->FInSummary( ATTR_UNSIGNED) ) ) { ParseError( WCHAR_T_ILLEGAL, (char *)0 ); } } else if( strcmp( pName, "error_status_t" ) == 0 ) { node_skl * pN = pType; if( !((pN->NodeKind() == NODE_LONG) && pN->FInSummary( ATTR_UNSIGNED) ) ) { ParseError( ERROR_STATUS_T_ILLEGAL, (char *)0 ); } } } else ParseError( BENIGN_SYNTAX_ERROR, "" ); // // if the type specifier is a forward declared type, then // the only syntax allowed is when context_handle is applied // to the type. If not, report an error // //gaj CheckSpecialForwardTypedef( pDef, pType, $2); /** ** The typedef node graph is all set up, ** apply attributes and enter into symbol table **/ $$.Add( pDef ); /** ** Remember that we have to apply the attributes to each of ** the declarators, so we must clone the attribute list for ** each declarator, the apply the type attribute list to each ** of the declarators **/ if ( $2.NonNull() ) { pDef->AddAttributes( $2 ); } /** ** similarly, apply the remnant attributes collected from ** declaration specifiers, to the declarator ** ** Only the first declarator to use a composite type gets to ** be the declaration; all the others reference that declaration; ** e.g. struct FOO { xxx } foo, *pfoo ** is treated as: struct FOO { xxx } foo ** struct FOO *pfoo **/ #ifdef gajdebug11 printf("setting modifiers %08x on %s\n", $3.modifiers, (pName)? pName : "(unknown)" ); #endif pDec->pLowest->SetModifiers( $3.modifiers ); $3.modifiers |= SetModifierBit( ATTR_TAGREF ); } } | DeclarationSpecifiers OptionalInitDeclaratorList ';' { /** ** All declarations other than typedefs are collected here. ** They are collected and passed up to the interface component ** production **/ node_skl * pType = $1.pNode; DECLARATOR_LIST_MGR DeclList( $2 ); long TempModifiers; long TopModifiers; #ifdef gajdebug3 printf("DeclarationSpecifiers OptionalInitDeclaratorList\n"); #endif $$.Init(); /** ** It is possible that there are no declarators, only a type decla- ** ration. eg, the definition of a structure. **/ if ( DeclList.NonEmpty() ) { class _DECLARATOR * pDec; /** ** for each declarator, set the basic type, set the attributes ** if any **/ while( pDec = DeclList.DestructiveGetNext() ) { pDec->pLowest->SetChild( pType ); /** ** Apply the remnant attributes from the declaration specifier ** prodn to this declarator; **/ // magic trick to push extern, etc up to top TempModifiers = $1.modifiers; TopModifiers = TempModifiers & 0x0000000f; TempModifiers -= TopModifiers; pDec->pLowest->SetModifiers( TempModifiers ); pDec->pHighest->SetModifiers( TopModifiers ); $1.modifiers |= SetModifierBit( ATTR_TAGREF ); /** ** shove the type node up. **/ $$.Add( (named_node *) pDec->pHighest ); } } else { #ifdef gajdebug3 printf("\t\t...no declarators\n"); #endif /** ** This is the case when no specific declarator existed. Just ** pass on the declaration to interface component. However, it ** is possible that the declaration is a forward declaration, ** in that case, just generate a dummy typedef. The dummy typedef ** exists, so that the whole thing is transparent to the back end. **/ named_node * pDef = (named_node *) $1.pNode; /** ** Apply the remnant attributes from the declaration specifier ** prodn to this declarator; **/ if( $1.modifiers ) { pDef->SetModifiers( $1.modifiers ); } /** ** shove the type node up. **/ $$.Add( pDef ); } } ; TypeDeclarationSpecifiers: DeclarationSpecifiers | IDENTIFIER { node_forward * pFwd; SymKey SKey( $1, NAME_DEF ); pFwd = new node_forward( SKey, pCurSymTbl ); pFwd->SetSymName( $1 ); $$.pNode = pFwd; $$.modifiers = 0; } ; SimpleTypeSpec: BaseTypeSpec { node_base_type * pNode; GetBaseTypeNode( (node_skl**) &pNode, $1.TypeSign, $1.TypeSize, $1.BaseType); $$ = pNode; if ( pNode->NodeKind() == NODE_INT ) ParseError( BAD_CON_INT, NULL ); } | PredefinedTypeSpec | TypeName /* TYPENAME */ ; DeclarationSpecifiers: DeclarationAccessories TypeSpecifier { $$.pNode = $2.pNode; $$.modifiers = $1 | $2.modifiers; } | TypeSpecifier ; DeclarationAccessories: DeclarationAccessories StorageClassSpecifier { $$ = $1 | $2; } | DeclarationAccessories TypeQualifier { $$ = $1 | $2; } | StorageClassSpecifier | TypeQualifier ; StorageClassSpecifier: KWEXTERN { $$ = SetModifierBit(ATTR_EXTERN); } | KWSTATIC { $$ = SetModifierBit(ATTR_STATIC); } | KWAUTO { $$ = SetModifierBit(ATTR_AUTO); } | KWREGISTER { $$ = SetModifierBit(ATTR_REGISTER); } ; TypeSpecifier: BaseTypeSpec { node_base_type * pNode; GetBaseTypeNode( (node_skl**) &pNode, $1.TypeSign, $1.TypeSize, $1.BaseType); $$.pNode = pNode; if ( pNode->NodeKind() == NODE_INT ) ParseError( BAD_CON_INT, NULL ); $$.modifiers = SetModifierBit(ATTR_TAGREF); } | PredefinedTypeSpec { $$.pNode = $1; $$.modifiers = SetModifierBit(ATTR_TAGREF); } | TaggedSpec | EnumerationType | BitSetType { $$.pNode = $1; $$.modifiers = SetModifierBit(ATTR_TAGREF); } | TypeName /* TYPENAME */ { /** ** Note that there is no need to check for whether the symbol table ** has the entry or not. If it did not, the TYPENAME token would not ** have come in. If the TYPENAME is for a forward reference, see ** if it has been satisfied; if so, create a NEW typedef that is the ** same, but without the forward reference. **/ node_def_fe * pDef = (node_def_fe *) $1; if ( ( pDef->NodeKind() == NODE_DEF ) && pDef->GetChild() && ( pDef->GetChild()->NodeKind() == NODE_FORWARD ) ) { node_forward * pFwd = (node_forward *) pDef->GetChild(); node_skl * pNewSkl = pFwd->ResolveFDecl(); if ( pNewSkl ) { ATTRLIST alist; pDef->GetAttributeList(alist); pDef = new node_def_fe( pDef->GetSymName(), pNewSkl ); pDef->SetAttributes(alist); SymKey SKey(pDef->GetSymName(), NAME_DEF); pBaseSymTbl->SymDelete(SKey); pBaseSymTbl->SymInsert(SKey, (SymTable *) NULL, (named_node*) pDef); } }; $$.pNode = pDef; $$.modifiers = SetModifierBit(ATTR_TAGREF); } | KWSAFEARRAY DeclarationSpecifiers OptionalDeclarator ')' { node_skl * pNode = pErrorTypeNode; if( $2.pNode ) { if( $3.pHighest ) { $3.pLowest->SetChild( $2.pNode ); pNode = $3.pHighest; if( $2.modifiers ) { ( (named_node *) $3.pLowest)->SetModifiers( $2.modifiers ); } } else pNode = $2.pNode; } $$.pNode = new node_safearray( pNode ); $$.modifiers = SetModifierBit(ATTR_TAGREF); } | KWPIPE TypeSpecifier { node_skl * pNode = pErrorTypeNode; if ($2.pNode ) { pNode = $2.pNode; } $$.pNode = new node_pipe( pNode ); $$.modifiers = SetModifierBit(ATTR_TAGREF) ; } ; BitSetType: IntSize KWBITSET '{' IdentifierList '}' { ParseError( UNIMPLEMENTED_FEATURE, "bitset" ); $$ = pErrorTypeNode; } ; IdentifierList: IDENTIFIER | IdentifierList ',' IDENTIFIER ; EnumerationType: /** IntSize EnumSpecifier **/ EnumSpecifier ; EnumSpecifier: KWENUM OptionalTag '{' EnumeratorList OptionalComma '}' { /** ** We just obtained a complete enum definition. Check for ** duplicate definition and break circular label list; **/ BOOL fFound = FALSE; BOOL fEnumIsForwardDecl = FALSE; node_skl * pNode; SymKey SKey( $2, NAME_ENUM ); pNode = pBaseSymTbl->SymSearch( SKey ); if( fFound = (pNode != (node_skl *) NULL) ) fEnumIsForwardDecl = ( pNode->NodeKind() == NODE_FORWARD || pNode->NodeKind() == NODE_HREF ); if( fFound && !fEnumIsForwardDecl ) { ParseError( DUPLICATE_DEFINITION, $2 ); $$.pNode = (node_skl *)pErrorTypeNode; } else { /** ** This is a new definition of enum. Enter into symbol table ** Also, pick up the label graph and attach it. **/ node_enum * pEnum = new node_enum( $2 ); $$.pNode = pEnum; pEnum->SetMembers( $4.NodeList ); /** ** Note that the enum symbol table entry need not have a next ** scope since the enum labels are global in scope.If the enum was ** a forward decl into the symbol table, delete it. **/ if( fEnumIsForwardDecl ) { pBaseSymTbl->SymDelete( SKey ); } pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, (named_node *) $$.pNode ); CheckGlobalNamesClash( SKey ); } // if the enumerator is sparse, report an error if the // switch configuration is not correct. if( $4.fSparse ) ParseError( SPARSE_ENUM, (char *)NULL ); $$.modifiers = 0; } | KWENUM Tag { /** ** Search for the enum definition, if not found, return the type ** as a forward declarator node. The semantic analysis will register ** the forward declaration and resolve it when the second pass occurs. ** See TaggedStruct production for a description on why we want to ** enter even a fdecl enum in the symbol table. **/ SymKey SKey( $2, NAME_ENUM ); BOOL fNotFound = ! ( $$.pNode = pBaseSymTbl->SymSearch( SKey ) ); if( fNotFound || ($$.pNode->NodeKind() == NODE_FORWARD ) ) { $$.pNode = new node_forward( SKey, pBaseSymTbl ); } $$.modifiers = SetModifierBit(ATTR_TAGREF); } ; EnumeratorList: Enumerator { /** ** this is the first label on an enum list. Set up the circular list ** pointing to the tail, and set it's expr to 0L if there was none **/ expr_node * pExpr; node_label * pLabel = (node_label *) $1.pLabel; pExpr = ($1.pExpr) ? $1.pExpr : GetConstant0(); pLabel->pExpr = pExpr; $$.fSparse = $1.fSparse; $$.pPrevLabel = pLabel; $$.NodeList.Init( pLabel ); } | EnumeratorList ',' Enumerator { /** ** This is a new label we reduced. ** ** if there was an expression associated with the label, use that ** else use the already collected expression, and add 1 to it. **/ expr_node * pExpr = (expr_node *)0; node_label * pLabel = (node_label *) $3.pLabel; pExpr = $3.pExpr; // next node has no expression, give it an expression of: // + 1; if (pExpr == NULL ) { expr_named_constant * pPrev = new expr_named_constant( $1.pPrevLabel->GetSymName(), $1.pPrevLabel ); pExpr = new expr_b_arithmetic(OP_PLUS, pPrev, GetConstant1() ); } pLabel->pExpr = pExpr; $$ = $1; $$.NodeList.Add( pLabel ); $$.pPrevLabel = pLabel; $$.fSparse += $3.fSparse; } ; Enumerator: OptionalAttrList IDENTIFIER { /** ** We have obtained an enum label, without an expression. Since ** we dont know if this is the first label (most probably not), ** we just indicate the absence of an expression by an NULL pointer. ** The next parse state would know if this was the first or not ** and take appropriate action ** ** The enum labels go into the global name space. Search for ** duplicates on the base symbol table. **/ node_label * pLabel; SymKey SKey( $2, NAME_LABEL ); if( pBaseSymTbl->SymSearch( SKey ) ) { ParseError( DUPLICATE_DEFINITION, $2 ); pLabel = new node_label( GenTempName(), NULL ); } else { /** ** If the label has an expression, use it, else it is 0. Also ** propogate the expression to $$, so that the next labels will ** get it. Note that we DO NOT evaluate the expressions here. ** The MIDL compiler will evaluate the expressions later. **/ pLabel = new node_label( $2, NULL ); /** ** Insert into the global table **/ pBaseSymTbl->SymInsert(SKey, (SymTable *)NULL,(named_node *)pLabel); CheckGlobalNamesClash( SKey ); } if ( $1.NonNull() ) { pLabel->AddAttributes( $1 ); } $$.pLabel = pLabel; $$.pExpr = NULL; $$.fSparse = 0; } | OptionalAttrList IDENTIFIER '=' ConstantExpr { /** ** This enum label has an expression associated with it. Use it. ** sparse enums are illegal in osf mode **/ node_label * pLabel; SymKey SKey( $2, NAME_LABEL ); if ($4->IsStringConstant()) ParseError(ENUM_TYPE_MISMATCH, $2); if( pBaseSymTbl->SymSearch( SKey ) ) { ParseError( DUPLICATE_DEFINITION, $2 ); pLabel = new node_label( GenTempName(), NULL ); } else { /** ** If the label has an expression, use it, else it is 0. Also ** propogate the expression to $$, so that the next labels will ** get it. Note that we DO NOT evaluate the expressions. The MIDL ** compiler will just dump the expressions for the c compiler to ** evaluate. **/ pLabel = new node_label( $2, $4 ); /** ** Insert into the global table **/ pBaseSymTbl->SymInsert(SKey, (SymTable *)NULL,(named_node *)pLabel); CheckGlobalNamesClash( SKey ); } if ( $1.NonNull() ) { pLabel->AddAttributes( $1 ); } $$.pLabel = pLabel; $$.pExpr = $4; $$.fSparse = 1; } ; PredefinedTypeSpec: InternationalCharacterType { ParseError( UNIMPLEMENTED_TYPE, KeywordToString( $1 ) ); $$ = (node_skl *)pErrorTypeNode; } ; BaseTypeSpec: KWFLOAT { $$.BaseType = TYPE_FLOAT; $$.TypeSign = SIGN_UNDEF; $$.TypeSize = SIZE_UNDEF; } | KWLONG KWDOUBLE { $$.BaseType = TYPE_DOUBLE; $$.TypeSign = SIGN_UNDEF; $$.TypeSize = SIZE_UNDEF; } | KWDOUBLE { $$.BaseType = TYPE_DOUBLE; $$.TypeSign = SIGN_UNDEF; $$.TypeSize = SIZE_UNDEF; } | KWVOID { $$.BaseType = TYPE_VOID; $$.TypeSign = SIGN_UNDEF; $$.TypeSize = SIZE_UNDEF; } | KWBOOLEAN { $$.BaseType = TYPE_BOOLEAN; $$.TypeSign = SIGN_UNDEF; $$.TypeSize = SIZE_UNDEF; } | KWBYTE { $$.BaseType = TYPE_BYTE; $$.TypeSign = SIGN_UNDEF; $$.TypeSize = SIZE_UNDEF; } | KWHANDLET { $$.BaseType = TYPE_HANDLE_T; $$.TypeSign = SIGN_UNDEF; $$.TypeSize = SIZE_UNDEF; } | IntSpec { $$ = $1; if( $$.BaseType == TYPE_UNDEF ) $$.BaseType = TYPE_INT; if( $$.TypeSign == SIGN_UNDEF ) { if( ($$.TypeSize != SIZE_SMALL) && ($$.TypeSize != SIZE_CHAR) ) $$.TypeSign = SIGN_SIGNED; } } | CharSpecs { $$.BaseType = TYPE_INT; $$.TypeSign = $1.TypeSign; $$.TypeSize = SIZE_CHAR; } ; CharSpecs: SignSpecs KWCHAR { $$.TypeSign = $1.TypeSign; } | KWCHAR { $$.TypeSign = SIGN_UNDEF; } ; IntSpec: IntModifiers KWINT { BaseTypeSpecAnalysis( &($1), TYPE_INT ); } | IntModifiers | KWINT IntModifiers { $$ = $2; $$.BaseType = TYPE_UNDEF; } | KWINT { $$.BaseType = TYPE_UNDEF; $$.TypeSign = SIGN_UNDEF; $$.TypeSize = SIZE_UNDEF; } ; IntModifiers: IntSize { $$.TypeSign = SIGN_UNDEF; $$.TypeSize = $1; $$.BaseType = TYPE_UNDEF; } | SignSpecs | IntSize SignSpecs { $$.TypeSign = $2.TypeSign; $$.TypeSize = $1; $$.BaseType = TYPE_UNDEF; } | SignSpecs IntSize { $$.TypeSign = $1.TypeSign; $$.TypeSize = $2; $$.BaseType = TYPE_UNDEF; } ; SignSpecs: KWSIGNED { ParseError(SIGNED_ILLEGAL, (char *)0); $$.BaseType = TYPE_UNDEF; $$.TypeSign = SIGN_SIGNED; $$.TypeSize = SIZE_UNDEF; } | KWUNSIGNED { $$.BaseType = TYPE_UNDEF; $$.TypeSign = SIGN_UNSIGNED; $$.TypeSize = SIZE_UNDEF; } ; IntSize: KWHYPER { $$ = SIZE_HYPER; } | KWLONG KWLONG { $$ = SIZE_LONGLONG; } | KWINT64 { $$ = SIZE_HYPER; } | KWLONG { $$ = SIZE_LONG; } | KWSHORT { $$ = SIZE_SHORT; } | KWSMALL { $$ = SIZE_SMALL; } ; PhantomPushSymtab: { /** ** We just obtained a starter for a new scope. Push the ** symbol table to the next level for the rest of the including ** production **/ pSymTblMgr->PushSymLevel( &pCurSymTbl ); } /* START TAGGED SPEC */ TaggedSpec: TaggedStructSpec | TaggedUnionSpec ; /* START TAGGED STRUCT */ TaggedStructSpec: KWSTRUCT OptionalTag '{' PhantomPushSymtab StructDeclarationList '}' { /** ** The entire struct was sucessfully reduced. Attach the fields as ** members of the struct. Insert a new symbol table entry for the ** struct and attach the lower scope of the symbol table to it. ** Check for dupliate structure definition **/ BOOL fFound = FALSE; BOOL fStructIsForwardDecl = FALSE; node_struct * pStruct; SymTable * pSymLowerScope = pCurSymTbl; SymKey SKey( $2, NAME_TAG ); /** ** discard the inner symbol table contents (unless it had fwds) **/ pCurSymTbl->DiscardScope(); /** ** restore the symbol table level **/ pSymTblMgr->PopSymLevel( &pCurSymTbl ); /** ** if this is a duplicate definition, dont do anything. Note that ** the struct tag name shares the global name space with enum and ** union tag names. **/ pStruct = (node_struct *) pBaseSymTbl->SymSearch( SKey ); if( fFound = ( pStruct != (node_struct *)NULL ) ) fStructIsForwardDecl = (pStruct->NodeKind() == NODE_FORWARD || pStruct->NodeKind() == NODE_HREF); if( fFound && !fStructIsForwardDecl ) { ParseError( DUPLICATE_DEFINITION, $2 ); pStruct = (node_struct *)pErrorTypeNode; } else { /** ** this is a valid entry. Build the graph for it and ** enter into symbol table. If the struct entry was present as ** a forward decl, delete it **/ if( fStructIsForwardDecl ) { pBaseSymTbl->SymDelete( SKey ); } pStruct = new node_struct( $2 ); pStruct->SetMembers( $5 ); pStruct->SetZeePee( CurrentZp ); pBaseSymTbl->SymInsert( SKey, pSymLowerScope, pStruct ); CheckGlobalNamesClash( SKey ); } $$.pNode = pStruct; $$.modifiers = 0; } | KWSTRUCT Tag { /** ** This is the invocation of a struct. If the struct was not ** defined as yet, then return a forward declarator node. The ** semantics will register the forward declaration and resolve it. ** But there is a loop hole in this. If we do not enter the struct into ** the symbol table, the user may define a union/enum of the same name. ** We will let him, since we do not yet have an entry in the symbol ** table. We will then never check for duplication, since the parser ** is the only place we check for this. We will then generate wrong ** code, with the struct and a union/enum with the same name !! The ** solution is to enter a symbol entry with a fdecl node as the type ** graph of the struct. **/ SymKey SKey( $2, NAME_TAG ); named_node * pNode = pBaseSymTbl->SymSearch( SKey ); if( !pNode || (pNode->NodeKind() == NODE_FORWARD ) ) { pNode = new node_forward( SKey, pBaseSymTbl ); pNode->SetSymName( $2 ); } $$.pNode = pNode; $$.modifiers = SetModifierBit(ATTR_TAGREF); } ; OptionalTag: Tag | /* Empty */ { $$ = GenCompName(); } ; Tag: IDENTIFIER { $$ = $1; } | TypeName { //$$ = $1; $$ = $1->GetCurrentSpelling(); } ; StructDeclarationList: StructDeclarationList MemberDeclaration { $$.Merge( $2 ); } | MemberDeclaration ; MemberDeclaration: OptionalAttrList DeclarationSpecifiers MemberDeclaratorList ';' { /** ** This is a complete field declaration. For each declarator, ** set up a field with the basic type as the declaration specifier, ** apply the field attributes, and add to the list of fields for the ** struct / union ** field **/ class _DECLARATOR * pDec; node_skl * pType; DECLARATOR_LIST_MGR DeclList( $3 ); $$.Init(); while( pDec = DeclList.DestructiveGetNext() ) { node_field * pField = (node_field *) pDec->pHighest; /** ** if the field was a bit field, we need to set up some additional ** info. **/ pType = $2.pNode; pDec->pLowest->SetChild( pType ); /** ** Apply the field attributes and set the field as part of the ** list of fields of the struct/union **/ if ( $1.NonNull() ) { pField->AddAttributes( $1 ); } /** ** similarly, apply the remnant attributes collected from ** declaration specifiers, to the declarator **/ if( $2.modifiers ) { pDec->pLowest->SetModifiers( $2.modifiers ); }; /** ** shove the type graph up **/ $$.Add( pField ); } } ; /* START UNION */ TaggedUnionSpec: KWUNION OptionalTag '{' PhantomPushSymtab UnionBody '}' { /** ** The union bosy has been completely reduced. Attach the fields as ** members, insert a new symbol table entry for the union **/ BOOL fFound = FALSE; BOOL fUnionIsForwardDecl = FALSE; node_union * pUnion; SymTable * pSymLowerScope = pCurSymTbl; SymKey SKey( $2, NAME_UNION ); /** ** discard the inner symbol table contents (unless it had fwds) **/ pCurSymTbl->DiscardScope(); /** ** restore the symbol table level **/ pSymTblMgr->PopSymLevel( &pCurSymTbl ); /** ** if this is a duplicate definition, dont do anything, else ** enter into the symbol table, attach members. Note that the ** symbol table search is actually a search for the tag becuase ** the union tag shares the same name as the struct/enum names **/ pUnion = (node_union *)pBaseSymTbl->SymSearch( SKey ); if( fFound = (pUnion != (node_union *) NULL ) ) fUnionIsForwardDecl = ( pUnion->NodeKind() == NODE_FORWARD || pUnion->NodeKind() == NODE_HREF ); if( fFound && !fUnionIsForwardDecl ) { ParseError( DUPLICATE_DEFINITION, $2 ); pUnion = (node_union *)pErrorTypeNode; } else { /** ** This is a valid entry, build the type graph and insert into ** the symbol table. Delete the entry first if it was a forward ** decl. **/ pUnion = new node_union( $2 ); pUnion->SetMembers( $5 ); if( fUnionIsForwardDecl ) { pBaseSymTbl->SymDelete( SKey ); } pBaseSymTbl->SymInsert( SKey, pSymLowerScope, pUnion ); CheckGlobalNamesClash( SKey ); } /** ** pass this union up **/ pUnion->SetZeePee( CurrentZp ); $$.pNode = pUnion; $$.modifiers = 0; } | KWUNION Tag { /** ** this is an invocation of the union. If the union was not defined ** then return a forward declarator node as the type node. The ** semantics will register the forward declaration and resolve it ** later. See TaggedStruct production for an explanation why we want to ** enter even a forward declaration into the symbol table. **/ SymKey SKey( $2, NAME_UNION ); named_node * pNode = pBaseSymTbl->SymSearch( SKey ); if( !pNode || (pNode->NodeKind() == NODE_FORWARD ) ) { pNode = new node_forward( SKey, pBaseSymTbl ); pNode->SetSymName( $2 ); } $$.pNode = pNode; $$.modifiers = SetModifierBit(ATTR_TAGREF); } | KWUNION OptionalTag NidlUnionSwitch '{' PhantomPushSymtab NidlUnionBody '}' { /** ** The union body has been completely reduced. Attach the fields as ** members, insert a new symbol table entry for the union **/ BOOL fFound = FALSE; BOOL fStructIsForwardDecl = FALSE; node_en_union * pUnion; SymTable * pSymLowerScope = pCurSymTbl; /** ** discard the inner symbol table contents (unless it had fwds) **/ pCurSymTbl->DiscardScope(); /** ** restore the symbol table level **/ pSymTblMgr->PopSymLevel( &pCurSymTbl ); pUnion = new node_en_union( GenCompName() ); pUnion->SetMembers( $6 ); SymKey SKey( pUnion->GetSymName(), NAME_UNION ); pBaseSymTbl->SymInsert( SKey, pSymLowerScope, pUnion ); CheckGlobalNamesClash( SKey ); // // The union is inserted into the base symbol table. // Now insert into the base symbol table, a new struct entry // corresponding to the struct entry that the encapsulated union // results in. // pSymTblMgr->PushSymLevel( &pCurSymTbl ); SIBLING_LIST Fields; node_field * pSwitchField = (node_field *) $3.pNode; node_field * pUnionField = new node_field; node_switch_type * pSwType = new node_switch_type( pSwitchField->GetChild() ); if( IsTempName( $3.pName ) ) $3.pName = "tagged_union"; pUnionField->SetSymName( $3.pName ); pUnionField->SetChild( pUnion ); Fields.Init( pSwitchField ); Fields.Add( pUnionField ); // // apply the switch_is attribute to the union field. // pUnionField->SetAttribute( $3.pSwitch ); // and the switch_type attribute to the union itself pUnion->SetAttribute( pSwType ); // // current symbol table is pointing to a new scope. Enter the two // fields into this scope. // SKey.SetKind( NAME_MEMBER ); SKey.SetString( pSwitchField->GetSymName() ); pCurSymTbl->SymInsert( SKey, (SymTable *)0, pSwitchField ); CheckGlobalNamesClash( SKey ); SKey.SetString( pUnionField->GetSymName() ); pCurSymTbl->SymInsert( SKey, (SymTable *)0, pUnionField ); CheckGlobalNamesClash( SKey ); pSymLowerScope = pCurSymTbl; pSymTblMgr->PopSymLevel( &pCurSymTbl ); // // create a new structure entry and enter into the symbol table. // node_struct * pStruct; SKey.SetKind( NAME_UNION ); SKey.SetString( $2 ); pStruct = (node_struct *)pBaseSymTbl->SymSearch( SKey ); if( fFound = ( pStruct != (node_struct *)NULL ) ) fStructIsForwardDecl = (pStruct->NodeKind() == NODE_FORWARD || pStruct->NodeKind() == NODE_HREF ); if( fFound && !fStructIsForwardDecl ) { ParseError( DUPLICATE_DEFINITION, $2 ); pStruct = (node_struct *)pErrorTypeNode; } else { /** ** this is a valid entry. Build the graph for it and ** enter into symbol table. If the struct entry was present as ** a forward decl, delete it **/ // enter the struct as a union. SKey.SetKind( NAME_UNION ); SKey.SetString( $2 ); if( fStructIsForwardDecl ) { pBaseSymTbl->SymDelete( SKey ); } pStruct = new node_en_struct( $2 ); pStruct->SetMembers( Fields ); pStruct->SetZeePee( CurrentZp ); pBaseSymTbl->SymInsert( SKey, pSymLowerScope, pStruct ); CheckGlobalNamesClash( SKey ); } pUnion->SetZeePee( CurrentZp ); $$.pNode = pStruct; $$.modifiers = 0; } ; UnionBody: UnionCases ; UnionCases: UnionCases UnionCase { ($$ = $1).Merge( $2 ); } | UnionCase ; UnionCase: UnionCaseLabel MemberDeclaration { /** ** for each of the fields, attach the case label attribute. **/ named_node * pNode; SIBLING_ITER MemIter( $2 ); $$ = $2; while( pNode = MemIter.Next() ) { pNode->SetAttribute( $1 ); } } | UnionCaseLabel ';' { /** ** An empty arm. Allocate a field with a node_error as a basic type ** and set the attribute as a case label **/ node_field * pField = new node_field( GenTempName() ); pField->SetChild( pErrorTypeNode ); pField->SetAttribute( $1 ); /** ** Generate a list of union fields and add this to the list of ** union fields **/ $$.Init( pField ); } | MemberDeclaration { /** ** A member declaration without a case label **/ $$ = $1; } | DefaultCase ; UnionCaseLabel: '[' KWCASE '(' ConstantExprs ')' ']' { $$ = new node_case( $4 ); } ; DefaultCase: '[' KWDEFAULT ']' MemberDeclaration { named_node * pNode; SIBLING_ITER MemIter( $4 ); $$ = $4; while( pNode = MemIter.Next() ) { pNode->SetAttribute( ATTR_DEFAULT ); } } | '[' KWDEFAULT ']' ';' { /** ** This is a default with an empty arm. Set up a dummy field. ** The upper productions will then mark set field with a ** default attribute during semantic analysis. The type of this field ** is set up to be an error node for uniformity. **/ node_field * pField = new node_field( GenTempName() ); pField->SetAttribute( ATTR_DEFAULT ); pField->SetChild( pErrorTypeNode ); $$.Init( pField ); } ; NidlUnionSwitch: SwitchSpec { $$ = $1; $$.pName = GenCompName(); } | SwitchSpec UnionName { $$ = $1; $$.pName = $2; } ; NidlUnionBody: NidlUnionCases { $$ = $1.CaseList; if( $1.DefCount > 1 ) ParseError( TWO_DEFAULT_CASES, (char *)0 ); } ; NidlUnionCases: NidlUnionCases NidlUnionCase { $$.DefCount += $2.DefCount; $$.CaseList.Merge( $2.CaseList ); } | NidlUnionCase ; NidlUnionCase: NidlUnionCaseLabelList NidlMemberDeclaration { named_node * pNode; // // set the case and default attributes. // $$.CaseList = $2; if( $1.pExprList && $1.pExprList->GetCount() ) { SIBLING_ITER CaseIter( $2 ); while( pNode = CaseIter.Next() ) { pNode->SetAttribute( new node_case( $1.pExprList )); } } // // pick up default attribute. pick up the count of number of // times the user specified default so that we can report the // error later. // Let the default case list count travel upward to report an // error when the total list of case labels is seen. // if( $1.pDefault && ( $$.DefCount = $1.DefCount ) ) { SIBLING_ITER CaseIter( $2 ); while( pNode = CaseIter.Next() ) { pNode->SetAttribute( $1.pDefault ); } } } ; NidlMemberDeclaration: MemberDeclaration | ';' { node_field * pNode = new node_field( GenTempName() ); pNode->SetChild( pErrorTypeNode ); $$.Init( pNode ); } ; NidlUnionCaseLabelList: NidlUnionCaseLabelList NidlUnionCaseLabel { if( $2.pExpr ) $$.pExprList->SetPeer( $2.pExpr ); if( !($$.pDefault) ) $$.pDefault = $2.pDefault; if( $2.pDefault ) $$.DefCount++; } | NidlUnionCaseLabel { $$.pExprList = new expr_list; if( $1.pExpr ) $$.pExprList->SetPeer( $1.pExpr ); if( $$.pDefault = $1.pDefault) { $$.DefCount = 1; } } ; NidlUnionCaseLabel: KWCASE ConstantExpr ':' { $$.pExpr = $2; $$.pDefault = 0; } | KWDEFAULT ':' { $$.pExpr = 0; $$.pDefault = new battr( ATTR_DEFAULT ); } ; SwitchSpec: KWSWITCH '(' SwitchTypeSpec IDENTIFIER ')' { node_field * pField = new node_field( $4 ); $$.pSwitch = new node_switch_is( new expr_variable( $4, pField )); $$.pNode = pField; pField->SetChild( $3 ); pField->SetModifiers( SetModifierBit( ATTR_TAGREF ) ); } ; UnionName: IDENTIFIER ; /** ** NIDL UNION END **/ ConstantExprs: ConstantExprs ',' ConstantExpr { $$->SetPeer( $3 ); } | ConstantExpr { $$ = new expr_list; $$->SetPeer( $1 ); } ; /* END UNION */ TypeQualifier: KWVOLATILE { $$ = SetModifierBit(ATTR_VOLATILE); } | KWCONST { $$ = SetModifierBit(ATTR_CONST); } | KW_C_INLINE { $$ = SetModifierBit(ATTR_C_INLINE); } ; MemberDeclaratorList: MemberDeclarator { $$.Init( $1 ); } | MemberDeclaratorList ',' MemberDeclarator { $$ = $1; $$.Add( $3 ); } ; MemberDeclarator: Declarator { /** ** a declarator without bit fields specified; a plain field. **/ if ( ($1.pHighest == NULL) || ( $1.pHighest->NodeKind() != NODE_ID )) { node_def_fe * pDef = new node_def_fe( GenTempName(), pErrorTypeNode ); // gaj - report error ParseError( BENIGN_SYNTAX_ERROR, "expecting a declarator"); } else { // convert top node of declarator chain to node_field // and add the field to the symbol table node_field * pField = new node_field( (node_id_fe *) $1.pHighest ); char * pName = pField->GetSymName(); SymKey SKey( pName, NAME_MEMBER ); $$.pHighest = pField; // if the top node was the only node, set pLowest accordingly $$.pLowest = ( $1.pLowest == $1.pHighest ) ? pField : $1.pLowest ; delete (node_id_fe *) $1.pHighest; if( !pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pField ) ) { ParseError( DUPLICATE_DEFINITION, pName ); } else CheckGlobalNamesClash( SKey ); }; } | ':' ConstantExpr { /** ** This is a declarator specified without the field name **/ node_bitfield * pField = new node_bitfield(); char * pName = GenTempName(); pField->SetSymName(pName); $$.pHighest = pField; $$.pLowest = pField; // add the field to the symbol table SymKey SKey( pName, NAME_MEMBER ); if( !pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pField ) ) { ParseError( DUPLICATE_DEFINITION, pName ); } else CheckGlobalNamesClash( SKey ); pField->fBitField = (unsigned char)$2->Evaluate(); } | Declarator ':' ConstantExpr { /** ** The complete bit field specification. **/ if ( ($1.pHighest == NULL) || ( $1.pHighest->NodeKind() != NODE_ID )) { // gaj - report error } else { // convert top node of declarator chain to node_field node_bitfield * pField = new node_bitfield( (node_id_fe *) $1.pHighest ); char * pName = pField->GetSymName(); $$.pHighest = pField; // if the top node was the only node, set pLowest accordingly $$.pLowest = ( $1.pLowest == $1.pHighest ) ? pField : $1.pLowest; delete (node_id_fe *) $1.pHighest; // add the field to the symbol table SymKey SKey( pName, NAME_MEMBER ); if( !pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pField ) ) { ParseError( DUPLICATE_DEFINITION, pName ); } else CheckGlobalNamesClash( SKey ); pField->fBitField = (unsigned char)$3->Evaluate(); } } | /** Empty **/ { // this is used for unnamed nested struct references node_field * pField = new node_field(); char * pName = GenTempName(); pField->SetSymName( pName); $$.pHighest = pField; $$.pLowest = pField; } ; OptionalInitDeclaratorList: InitDeclaratorList | /* Empty */ { $$.Init(); } ; InitDeclaratorList: InitDeclarator { $$.Init( $1 ); } | InitDeclaratorList ',' InitDeclarator { $$ = $1; $$.Add( $3 ); } ; InitDeclarator: Declarator { node_id_fe * pID = (node_id_fe *) $1.pHighest; /** ** If the top node of the declarator is null, create a dummy ID ** but not if the top is a proc... **/ if ( ($1.pHighest == NULL) || ( ( $1.pHighest->NodeKind() != NODE_ID ) && ( $1.pHighest->NodeKind() != NODE_PROC) ) ) { pID = new node_id_fe( GenTempName() ); pID->SetChild( $1.pHighest ); $$.pHighest = pID; $$.pLowest = ( $1.pLowest ) ? $1.pLowest : pID; // in case of null }; /** ** and add the id to the symbol table ** for node_proc's, leave original in symbol table **/ if ( $1.pHighest->NodeKind() != NODE_PROC ) { char * pName = pID->GetSymName(); SymKey SKey( pName, NAME_ID ); if( !pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pID ) ) { ParseError( DUPLICATE_DEFINITION, pName ); } else CheckGlobalNamesClash( SKey ); } }; | Declarator '=' Initializer { if ( ($1.pHighest == NULL) || ( $1.pHighest->NodeKind() != NODE_ID )) { // gaj - report error } else { node_id_fe * pID = (node_id_fe *) $1.pHighest; // fill in initializer pID->pInit = $3; $$ = $1; // and add the id to the symbol table char * pName = pID->GetSymName(); SymKey SKey( pName, NAME_ID ); if( !pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pID ) ) { ParseError( DUPLICATE_DEFINITION, pName ); } else CheckGlobalNamesClash( SKey ); }; } ; TypedefDeclaratorList: ';' { $$.Init(); } | TypedefDeclaratorListElement ';' ; TypedefDeclaratorListElement: TypedefDeclarator { $$.Init( $1 ); } | TypedefDeclaratorListElement ',' TypedefDeclarator { $$ = $1; $$.Add( $3 ); } ; TypedefDeclarator: Declarator { node_def_fe * pDef; char * pName; if ($1.pHighest == NULL) { // gaj - report error } else if ( $1.pHighest->NodeKind() == NODE_PROC ) { // build new node_def and attach to top node_proc * pProc = (node_proc *) $1.pHighest; pName = pProc->GetSymName(); pDef = new node_def_fe( (node_proc *) $1.pHighest ); pDef->SetSymName(pName); pDef->SetChild( $1.pHighest ); if ( !strcmp(pName, "HRESULT") || !strcmp(pName, "SCODE") ) pDef->SetIsHResultOrSCode(); $$.pHighest = pDef; $$.pLowest = $1.pLowest; SymKey SkeyOld( pName, NAME_PROC ); pInterfaceInfoDict->GetInterfaceProcTable()->SymDelete( SkeyOld ); SymKey SKey( pName, NAME_DEF ); if( !pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pDef ) ) { ParseError( DUPLICATE_DEFINITION, pName ); } else CheckGlobalNamesClash( SKey ); } else if ( $1.pHighest->NodeKind() == NODE_ID ) { // convert top node of declarator chain to node_def // and add the def to the symbol table node_def_fe * pDef = new node_def_fe( (node_id_fe *) $1.pHighest ); char * pName = pDef->GetSymName(); SymKey SKey( pName, NAME_DEF ); if ( !pName ) pDef->SetSymName( GenTempName() ); if ( !strcmp(pName, "HRESULT") || !strcmp(pName, "SCODE") ) pDef->SetIsHResultOrSCode(); $$.pHighest = pDef; // if the top node was the only node, set pLowest accordingly $$.pLowest = ( $1.pLowest == $1.pHighest ) ? pDef : $1.pLowest; delete (node_id_fe *) $1.pHighest; named_node * pFound; // Allow redefinition of imported types. pFound = pBaseSymTbl->SymSearch( SKey ); // if (pFound && ( pFound->NodeKind() == NODE_HREF )) if (pFound && ( NULL != pFound->GetDefiningFile() )) { pBaseSymTbl->SymDelete( SKey ); } if(!pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pDef )) { // // allow benign redef of wchar_t & error_status_t. // if ( ( strcmp( pName, "wchar_t" ) != 0 ) && ( strcmp( pName, "error_status_t" ) != 0 ) ) { ParseError( DUPLICATE_DEFINITION, pName ); } } else { CheckGlobalNamesClash( SKey ); } }; } ; OptionalDeclarator: Declarator | /* Empty */ { $$.Init(); } ; /*** *** declarators are the last part of declarations; e.g. with *** long *p, **q, f(long abc); *** each of "*p", "**q", and "f(long abc)" are declarators. *** *** As declarators are built, they are just dangling parts of the *** typegraph, so we pass the topmost node and the lowest node (with *** no child set yet) *** ***/ Declarator: OptionalModifierList Declarator2 { // note that leading modifiers eventually attach to the // lowest node of the declarator $2.pLowest->SetModifiers( $1 ); $$ = $2; } | Pointer | Pointer OptionalModifierList Declarator2 { // point dangling declarator2 lowest to pointer highest, // set modifiers on Declarator2 // return declarator2 highest with pointer lowest $3.pLowest->SetModifiers($2); $3.pLowest->SetChild($1.pHighest); $$.pLowest = $1.pLowest; $$.pHighest = $3.pHighest; } ; /*** *** Note that modifiers get stored with the pointer or declarator2 FOLLOWING *** the attribute *** *** Note also that pHighest and pLowest are guaranteed to be non-null *** for pointers. ***/ Pointer: OptionalModifierList '*' { node_pointer * pPtr = new node_pointer( (node_pointer *) NULL ); pPtr->SetModifiers( $1 ); #ifdef gajdebug8 printf("\t\t attaching modifier to lone ptr: %08x\n",$1); #endif // create node_pointer with modifierlist $$.Init( pPtr ); } | Pointer OptionalModifierList '*' { node_pointer * pPtr = new node_pointer( $1.pHighest ); pPtr->SetModifiers( $2 ); // create node_pointer, set child, apply modifierlist to it $$.Init( pPtr, $1.pLowest ); } ; OptionalModifierList: ModifierList | /* Empty */ { $$ = 0; } ; ModifierList: Modifier | ModifierList Modifier { $$ = $1 | $2; } ; Modifier: PtrModifier | FuncModifier | TypeQualifier ; PtrModifier: MSCFAR { $$ = SetModifierBit(ATTR_FAR); ParseError( BAD_CON_MSC_CDECL, "__far" ); } | MSCNEAR { $$ = SetModifierBit(ATTR_NEAR); ParseError( BAD_CON_MSC_CDECL, "__near" ); } | MSCHUGE { $$ = SetModifierBit(ATTR_HUGE); ParseError( BAD_CON_MSC_CDECL, "__huge" ); } | MSCUNALIGNED { $$ = SetModifierBit(ATTR_MSCUNALIGNED); ParseError( BAD_CON_MSC_CDECL, "unaligned" ); } ; FuncModifier: MSCPASCAL { $$ = SetModifierBit(ATTR_PASCAL); ParseError( BAD_CON_MSC_CDECL, "__pascal" ); } | MSCFORTRAN { $$ = SetModifierBit(ATTR_FORTRAN); ParseError( BAD_CON_MSC_CDECL, "__fortran" ); } | MSCCDECL { $$ = SetModifierBit(ATTR_CDECL); ParseError( BAD_CON_MSC_CDECL, "__cdecl" ); } | MSCSTDCALL { $$ = SetModifierBit(ATTR_STDCALL); ParseError( BAD_CON_MSC_CDECL, "__stdcall" ); } | MSCLOADDS /* potentially interesting */ { $$ = SetModifierBit(ATTR_LOADDS); ParseError( BAD_CON_MSC_CDECL, "__loadds" ); } | MSCSAVEREGS { $$ = SetModifierBit(ATTR_SAVEREGS); ParseError( BAD_CON_MSC_CDECL, "__saveregs" ); } | MSCFASTCALL { $$ = SetModifierBit(ATTR_FASTCALL); ParseError( BAD_CON_MSC_CDECL, "__fastcall" ); } | MSCSEGMENT { $$ = SetModifierBit(ATTR_SEGMENT); ParseError( BAD_CON_MSC_CDECL, "__segment" ); } | MSCINTERRUPT { $$ = SetModifierBit(ATTR_INTERRUPT); ParseError( BAD_CON_MSC_CDECL, "__interrupt" ); } | MSCSELF { $$ = SetModifierBit(ATTR_SELF); ParseError( BAD_CON_MSC_CDECL, "__self" ); } | MSCEXPORT { $$ = SetModifierBit(ATTR_EXPORT); ParseError( BAD_CON_MSC_CDECL, "__export" ); } | MSCDECLSPEC '(' MSCDLLIMPORT ')' { $$ = SetModifierBit(ATTR_DLLIMPORT); ParseError( BAD_CON_MSC_CDECL, "__declspec(dllimport)" ); } | MSCDECLSPEC '(' MSCDLLEXPORT ')' { $$ = SetModifierBit(ATTR_DLLEXPORT); ParseError( BAD_CON_MSC_CDECL, "__declspec(dllexport)" ); } | MSCEMIT NUMERICCONSTANT { $$ = SetModifierBit(ATTR_NONE); ParseError( BAD_CON_MSC_CDECL, "__emit" ); } ; /* Declarator2 is whatever is left of the declarator after all the pointer stuff has been eaten */ Declarator2: '(' Declarator ')' { $$ = $2; } | Declarator2 PhantomPushSymtab ParamsDecl2 OptionalConst { node_proc * pProc; char * pName; SymTable * pParamSymTbl = pCurSymTbl; BOOL IsProc = TRUE; /** ** If the declarator was an ID and just a simple ID (basic type is ** a null), we have just seen a declaration of a procedure. ** If we saw an ID which had a basic type, then the ID is a declarator ** whose basic type is a procedure (like in a typedef of a proc or ** pointer to proc). **/ /** ** if the node is a simple ID, then copy node details, else, ** set the basic type of the declarator as this proc, and set the ** procs name to a temporary. **/ // gaj - check for null... if ( ( $1.pHighest == $1.pLowest) && ($1.pLowest->NodeKind() == NODE_ID ) ) { pProc = new node_proc( ImportLevel, IS_CUR_INTERFACE_LOCAL(), (node_id_fe *) $1.pHighest); pName = pProc->GetSymName(); $$.pHighest = pProc; $$.pLowest = pProc; delete (node_id_fe *) $1.pHighest; } else { pProc = new node_proc( ImportLevel, IS_CUR_INTERFACE_LOCAL() ); pProc->SetSymName( pName = GenTempName() ); $1.pLowest->SetChild( pProc ); $$.pHighest = $1.pHighest; $$.pLowest = pProc; IsProc = FALSE; } /** ** Set members of the procedure node as the parameter nodes. **/ pProc->SetMembers( $3 ); /** ** discard the inner symbol table contents (unless it had fwds) **/ pCurSymTbl->DiscardScope(); /** ** restore the symbol tables scope to normal, since we have already ** picked up a pointer to the next scope symbol table. **/ pSymTblMgr->PopSymLevel( &pCurSymTbl ); /** ** if this proc was entered into our symbol table, then this is a ** redeclaration.But wait ! This is true only if the importlevel is 0 ** I.e , if there was a proc of the same name defined at an import ** level greater, we dont care. (Actually, we must really check ** signatures, so that valid redeclarations are ok, with a warning ) **/ if( IsProc ) { SymKey SKey( pName , NAME_PROC ); //if ( ImportLevel == 0 ) { if( !pInterfaceInfoDict->GetInterfaceProcTable()-> SymInsert( SKey, pParamSymTbl, pProc ) ) { ParseError( DUPLICATE_DEFINITION, pName ); } } /******** else CheckGlobalNamesClash( SKey ); ********/ } /** ** finally, for the const support, if the optional const is true ** apply the const attribute on the proc **/ pProc->SetModifiers( $4 ); } | '(' ')' OptionalConst { /** ** this is an abstract declarator for a procedure. Generate a ** new proc node with a temp name, enter the name into the symbol ** table. **/ char * pName = GenTempName(); SymKey SKey( pName, NAME_PROC ); node_proc * pProc = new node_proc( ImportLevel, IS_CUR_INTERFACE_LOCAL() ); $$.Init ( pProc ); pProc->SetSymName( pName ); /** ** enter this into the symbol table , only if we are in the base idl ** file, not an imported file. **/ if( ImportLevel == 0 ) pInterfaceInfoDict->GetInterfaceProcTable()->SymInsert( SKey, (SymTable *)NULL, (named_node *) $$.pHighest ); /** ** finally, for the const support, if the optional const is true ** apply the const attribute on the proc **/ pProc->SetModifiers( $3 ); } | Declarator2 ArrayDecl { /** ** The basic type of the declarator is the array **/ $$.pHighest = $1.pHighest; $1.pLowest->SetChild( $2.pHighest ); $$.pLowest = $2.pLowest; } | ArrayDecl { $$ = $1; } | IDENTIFIER { char * pName = $1; if ( !pName ) pName = GenTempName(); $$.Init( new node_id_fe( pName ) ); } | TypeName { /** ** This production ensures that a declarator can be the same name ** as a typedef. The lexer will return all lexemes which are ** typedefed as TYPENAMEs and we need to permit the user to specify ** a declarator of the same name as the type name too! This conflict ** arises only in the declarator productions, so this is an easy way ** to support it. **/ $$.Init( new node_id_fe( $1->GetCurrentSpelling() ) ); } ; /* Note: the omition of param_decl2 above precludes int foo( int (bar) ); a real ambiguity of C. If bar is a predefined type then the parameter of foo can be either: 1. a function with a bar param, and an int return value, as in int foo( int func(bar) ); 2. A function with an int parameter by the name of bar, as in int foo( int bar ); */ ParamsDecl2: '(' ')' { /** ** this production corresponds to no params to a function. **/ /** ** Return it as an empty list of parameters **/ $$.Init( NULL ); } | '(' ParameterTypeList ')' { $$ = $2; } ; ParameterTypeList: ParameterList | ParameterList ',' DOTDOT '.' { /** ** This is meaningless in rpc, but we consume it and report an ** error during semantics, if a proc using this param ever gets ** remoted. We call this a param node with the name "...". And set its ** basic type to an error node, so that a param is properly terminated. ** The backend can emit a "..." for the name, so that this whole ** thing is essentially transparent to it. **/ if ( 1 ) //ImportLevel == 0 ) <- change back when imported params not needed { node_param * pParam = new node_param; pParam->SetSymName( "..." ); pParam->SetChild( pErrorTypeNode ); $$ = $1; $$.Add( pParam ); } } ; ParameterList: ParameterDeclaration { $$.Init( $1 ); } | ParameterList ',' ParameterDeclaration { if ( $3 && $1.NonNull() ) { $$.Add( (named_node *) $3 ); } else { // tbd - error if later parameters are void } } ; ParameterDeclaration: OptionalAttrList DeclarationSpecifiers Declarator { if (0) // ( ImportLevel > 0 ) { if ( $3.pHighest->NodeKind() == NODE_ID ) delete (node_id_fe *) $3.pHighest; $$ = NULL; } else { node_param * pParam; char * pName; node_id_fe * pOriginal = NULL; /** ** Apply the declaration specifier to the declarator as a basic type **/ $3.pLowest->SetChild( $2.pNode ); /** ** apply any attributes specified to the declaration specifiers **/ $3.pLowest->SetModifiers( $2.modifiers ); /** ** if the declarator was just an id, then we have to copy the ** node details over, else set the basic type of the param to ** the declarator **/ if ( $3.pHighest->NodeKind() == NODE_ID ) { pOriginal = (node_id_fe *) $3.pHighest; pParam = new node_param( pOriginal ); } else { pParam = new node_param; pParam->SetChild( $3.pHighest ); }; /** ** prepare for symbol table entry. **/ if( !(pName = pParam->GetSymName()) ) { pParam->SetSymName(pName = GenTempName() ); } if ( IsTempName( pParam->GetSymName() ) ) ParseError( ABSTRACT_DECL, (char *)NULL ); SymKey SKey( pName, NAME_MEMBER ); /** ** enter the parameter into the symbol table. ** If the user specified more than one param with the same name, ** report an error, else insert the symbol into the table **/ if( !pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pParam ) ) { // // dont complain on another param of name void. This check is // made elsewhere. // if( strcmp( pName, "void" ) != 0 ) ParseError( DUPLICATE_DEFINITION, pName ); } else CheckGlobalNamesClash( SKey ); if ( $1 ) { pParam->AddAttributes( $1 ); } // clean up any old node_id if ( pOriginal ) delete pOriginal; /** ** return the node back **/ $$ = pParam; } } | OptionalAttrList DeclarationSpecifiers { /** ** This is the case when the user specified a simple abstract ** declaration eg proc1( short ). In other words, the declarator is ** optional. Abstract declarators are illegal in osf mode. ** If the declaration specifier is a void then skip the parameter **/ if( // ( ImportLevel > 0 ) || ( $2.pNode->NodeKind() == NODE_VOID ) ) { $$ = NULL; } else { char * pName = GenTempName(); SymKey SKey( pName, NAME_MEMBER ); node_param * pParam = new node_param; pParam->SetSymName( pName ); pParam->SetChild( $2.pNode ); ParseError( ABSTRACT_DECL, (char *)NULL ); /** ** enter into symbol table, just like anything else. **/ if( !pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pParam ) ) { ParseError( DUPLICATE_DEFINITION, pName ); } /** ** apply any attributes specified to the declaration specifiers **/ pParam->SetModifiers( $2.modifiers ); if ( $1 ) { pParam->AddAttributes( $1 ); } $$ = pParam; } } ; OptionalConst: KWCONST { $$ = SetModifierBit(ATTR_PROC_CONST); } | /* empty */ { $$ = 0; } ; ArrayDecl: ArrayDecl2 { $$.Init( new node_array( $1.LowerBound, $1.UpperBound ) ); } ; ArrayDecl2: '[' ']' { /** ** we identify a conformant array by setting the upperbound to -1 ** and the lower to 0 **/ $$.UpperBound = (expr_node *) -1; $$.LowerBound = (expr_node *) 0; } | '[' '*' ']' { /** ** This is also taken to mean a conformant array, upper bound known ** only at runtime. The lower bound is 0 **/ $$.UpperBound = (expr_node *)-1; $$.LowerBound = (expr_node *)0; } | '[' ConstantExpr ']' { /** ** this is the case of an array whose lower bound is 0 **/ $$.UpperBound = $2; $$.LowerBound = (expr_node *)0; } | '[' ArrayBoundsPair ']' { if( ($2.LowerBound)->Evaluate() != 0 ) ParseError( ARRAY_BOUNDS_CONSTRUCT_BAD, (char *)NULL ); $$ = $2; } ; ArrayBoundsPair: ConstantExpr DOTDOT ConstantExpr { /** ** the fact that the expected expression is not a constant is ** verified by the constantExpr production. All we have to do here is ** to pass the expression up. **/ $$.LowerBound = $1; $$.UpperBound = new expr_b_arithmetic( OP_PLUS, $3, GetConstant1() ); } ; InternationalCharacterType: KWISOLATIN1 { $$ = KWISOLATIN1; } | KWPRIVATECHAR8 { $$ = KWPRIVATECHAR8; } | KWISOMULTILINGUAL { $$ = KWISOMULTILINGUAL; } | KWPRIVATECHAR16 { $$ = KWPRIVATECHAR16; } | KWISOUCS { $$ = KWISOUCS; } ; /********************************* MIDL attributes **********************/ OptionalAttrList: AttrList | /* Empty */ { $$.MakeAttrList(); } ; OptionalAttrListWithDefault: AttrListWithDefault | /* Empty */ { $$.MakeAttrList(); } ; AttrList: AttrList AttrSet { // note that in all left-recursive productions like this we are // relying on an implicit $$ = $1 operation $$.Merge( $2 ); } | AttrSet ; AttrListWithDefault: AttrListWithDefault AttrSetWithDefault { // note that in all left-recursive productions like this we are // relying on an implicit $$ = $1 operation $$.Merge( $2 ); } | AttrSetWithDefault ; AttrSet: '[' Attributes ']' { $$ = $2; } ; AttrSetWithDefault: '[' AttributesWithDefault ']' { $$ = $2; } ; Attributes: Attributes ',' OneAttribute { $$.Merge( $3 ); } | OneAttribute ; AttributesWithDefault: AttributesWithDefault ',' OneAttributeWithDefault { $$.Merge( $3 ); } | OneAttributeWithDefault ; OneAttribute: InterfaceAttribute { $$.MakeAttrList( $1 ); } | TypeAttribute { $$.MakeAttrList( $1 ); } | FieldAttribute | PtrAttr { $$.MakeAttrList( $1 ); } | DirectionalAttribute { $$.MakeAttrList( $1 ); } | OperationAttribute { $$.MakeAttrList( $1 ); } | OdlAttribute { $$.MakeAttrList( $1 ); } ; OneAttributeWithDefault: InterfaceAttribute { $$.MakeAttrList( $1 ); } | TypeAttribute { $$.MakeAttrList( $1 ); } | FieldAttribute | PtrAttr { $$.MakeAttrList( $1 ); } | DirectionalAttribute { $$.MakeAttrList( $1 ); } | OperationAttribute { $$.MakeAttrList( $1 ); } | OdlAttribute { $$.MakeAttrList( $1 ); } | KWDEFAULT { $$.MakeAttrList(new battr( ATTR_DEFAULT )); } ; ; InterfaceAttribute: KWENDPOINT '(' EndPtSpecs ')' { $$ = $3; } | KWUUID '(' { LexContext = LEX_GUID; /* turned off by the lexer */ } Guid ')' { $$ = $4; } | KWLOCAL { $$ = new battr( ATTR_LOCAL ); } | KWOBJECT { ParseError( INVALID_OSF_ATTRIBUTE, "[object]" ); $$ = new battr( ATTR_OBJECT ); } | KWVERSION '(' { LexContext = LEX_VERSION; /* LexContext is reset by lexer */ } VERSIONTOKEN ')' { $$ = (new node_version( $4 )); } | KWDEFAULTPOINTER '(' PtrAttr ')' { $$ = $3; } | AcfInterfaceAttribute { if( !pCommand->IsSwitchDefined( SWITCH_APP_CONFIG ) ) { ParseError( ACF_IN_IDL_NEEDS_APP_CONFIG, ($1)->GetNodeNameString() ); } $$ = $1; } | /* empty attribute */ { $$ = NULL; } ; Guid: UUIDTOKEN { $$ = (new node_guid( $1 )); } ; EndPtSpecs: EndPtSpec { $$ = new node_endpoint( $1 ); } | EndPtSpecs ',' EndPtSpec { $$ = $1; ( (node_endpoint *) $$)->SetEndPointString( $3 ); } ; EndPtSpec: STRING ; AcfInterfaceAttribute: KWIMPLICITHANDLE '(' AcfImpHdlTypeSpec IDENTIFIER ')' { $$ = (new node_implicit( $3, new node_id_fe($4) )); } | KWAUTOHANDLE { $$ = (new acf_attr( ATTR_AUTO )); } ; AcfImpHdlTypeSpec: KWHANDLET { GetBaseTypeNode( &($$), SIGN_UNDEF, SIZE_UNDEF, TYPE_HANDLE_T ); } | IDENTIFIER { node_forward * pFwd; SymKey SKey( $1, NAME_DEF ); pFwd = new node_forward( SKey, pCurSymTbl ); pFwd->SetSymName( $1 ); pFwd->SetAttribute( ATTR_HANDLE ); $$ = pFwd; // // keep a track of this node to ensure it is not used as a // context handle. // if( ImportLevel == 0 ) { pBaseImplicitHandle = $$; } } | TypeName ; TypeAttribute: UnimplementedTypeAttribute { $$ = NULL; } | KWHANDLE { $$ = new battr( ATTR_HANDLE ); } | KWSTRING { $$ = (new battr( ATTR_STRING )); } | KWBSTRING { $$ = (new battr( ATTR_BSTRING )); } | KWCONTEXTHANDLE { $$ = (new battr( ATTR_CONTEXT )); } | KWSWITCHTYPE '(' SwitchTypeSpec ')' { $$ = (new node_switch_type( $3 )); } | KWTRANSMITAS '(' SimpleTypeSpec ')' { $$ = (new node_transmit( $3 )); } | KWWIREMARSHAL '(' SimpleTypeSpec ')' { $$ = (new node_wire_marshal( $3 )); } | KWCALLAS '(' AcfCallType ')' { $$ = $3; } | KWMSUNION { $$ = new battr( ATTR_MS_UNION ); } | KWOPAQUE { $$ = new battr( ATTR_OPAQUE ); } | KWV1ENUM { $$ = new battr( ATTR_V1_ENUM ); } ; AcfCallType: IDENTIFIER { SymKey SKey( $1, NAME_PROC ); node_proc * pProc = (node_proc *) pInterfaceInfoDict->GetInterfaceProcTable()->SymSearch( SKey ); $$ = new node_call_as( $1, pProc ); } ; UnimplementedTypeAttribute: KWALIGN '(' IntSize ')' { ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[align]"); } | KWUNALIGNED { ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[unaligned]"); } | KWV1ARRAY { ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[v1_array]"); } | KWV1STRING { ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[v1_string]"); } | KWV1STRUCT { ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[v1_struct]"); } ; PtrAttr: KWREF { $$ = new node_ptr_attr( PTR_REF ); } | KWUNIQUE { $$ = new node_ptr_attr( PTR_UNIQUE ); } | KWPTR { $$ = new node_ptr_attr( PTR_FULL ); } | KWIGNORE { $$ = new battr( ATTR_IGNORE ); } ; SwitchTypeSpec: IntSpec { if( $1.BaseType == TYPE_UNDEF ) $1.BaseType = TYPE_INT; if( $1.TypeSign == SIGN_UNDEF ) $1.TypeSign = SIGN_SIGNED; GetBaseTypeNode( &($$), $1.TypeSign, $1.TypeSize, $1.BaseType ); } | CharSpecs { GetBaseTypeNode( &($$), $1.TypeSign, SIZE_CHAR, TYPE_INT ); } | KWBYTE { GetBaseTypeNode( &($$), SIGN_UNDEF, SIZE_UNDEF, TYPE_BYTE ); } | KWBOOLEAN { GetBaseTypeNode( &($$), SIGN_UNDEF, SIZE_UNDEF, TYPE_BOOLEAN ); } | KWENUM Tag { SymKey SKey( $2, NAME_ENUM ); if( ! ($$ = pBaseSymTbl->SymSearch( SKey ) ) ) { ParseError( UNDEFINED_SYMBOL, $2 ); $$ = new node_error; } } | TypeName /* TYPENAME */ ; FieldAttribute: KWFIRSTIS '(' AttrVarList ')' { $$ = (GenerateFieldAttribute( ATTR_FIRST, $3 )); } | KWLASTIS '(' AttrVarList ')' { $$ = (GenerateFieldAttribute( ATTR_LAST, $3 )); } | KWLENGTHIS '(' AttrVarList ')' { $$ = (GenerateFieldAttribute( ATTR_LENGTH, $3 )); } | KWMINIS '(' AttrVarList ')' { $$ = (GenerateFieldAttribute( ATTR_MIN, $3 )); } | KWMAXIS '(' AttrVarList ')' { $$ = (GenerateFieldAttribute( ATTR_MAX, $3 )); } | KWSIZEIS '(' AttrVarList ')' { $$ = (GenerateFieldAttribute( ATTR_SIZE, $3 )); } | KWSWITCHIS '(' AttrVar ')' { $$.MakeAttrList( new node_switch_is( $3 )); } | KWIIDIS '(' AttrVar ')' { ParseError( INVALID_OSF_ATTRIBUTE, "[iid_is()]" ); $$.MakeAttrList( new size_attr( $3, ATTR_IID_IS )); } | KWID '(' ConstantExpr ')' { $$.MakeAttrList( new node_constant_attr( $3, ATTR_ID)); } | KWHC '(' ConstantExpr ')' { $$.MakeAttrList( new node_constant_attr( $3, ATTR_HELPCONTEXT )); } | KWHSC '(' ConstantExpr ')' { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[helpstringcontext()]"); } $$.MakeAttrList( new node_constant_attr( $3, ATTR_HELPSTRINGCONTEXT )); } | KWLCID '(' ConstantExpr ')' { $$.MakeAttrList( new node_constant_attr( $3, ATTR_LCID )); } | KWFUNCDESCATTR '(' ConstantExpr ')' { $$.MakeAttrList( new node_constant_attr( $3, ATTR_FUNCDESCATTR )); } | KWIDLDESCATTR '(' ConstantExpr ')' { $$.MakeAttrList( new node_constant_attr( $3, ATTR_IDLDESCATTR )); } | KWTYPEDESCATTR '(' ConstantExpr ')' { $$.MakeAttrList( new node_constant_attr( $3, ATTR_TYPEDESCATTR )); } | KWVARDESCATTR '(' ConstantExpr ')' { $$.MakeAttrList( new node_constant_attr( $3, ATTR_VARDESCATTR )); } | KWDLLNAME '(' STRING ')' { $$.MakeAttrList( new node_text_attr( $3, ATTR_DLLNAME )); } | KWHELPSTR '(' STRING ')' { TranslateEscapeSequences($3); $$.MakeAttrList( new node_text_attr( $3, ATTR_HELPSTRING )); } | KWHELPFILE '(' STRING ')' { TranslateEscapeSequences($3); $$.MakeAttrList( new node_text_attr( $3, ATTR_HELPFILE )); } | KWENTRY '(' STRING ')' { $$.MakeAttrList( new node_entry_attr( $3 )); } | KWENTRY '(' NUMERICCONSTANT ')' { $$.MakeAttrList( new node_entry_attr( (long) $3.Val )); } | KWENTRY '(' HEXCONSTANT ')' { $$.MakeAttrList( new node_entry_attr( (long) $3.Val )); } | KWENTRY '(' OCTALCONSTANT ')' { $$.MakeAttrList( new node_entry_attr( (long) $3.Val )); } | KWDEFAULTVALUE '(' ConstantExpr ')' { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[defaultvalue()]"); } $$.MakeAttrList( new node_constant_attr( $3, ATTR_DEFAULTVALUE )); } | KWCUSTOM '(' { LexContext = LEX_GUID; /* turned off by the lexer */ } Guid ',' ConstantExpr ')' { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[custom()]"); } $$.MakeAttrList( new node_custom_attr( (node_guid *)$4, $6 )); } ; AttrVarList: AttrVarList ',' AttrVar { $$->SetPeer( $3 ); } | AttrVar { $$ = new expr_list; $$->SetPeer( $1 ); } ; AttrVar: VariableExpr | /* empty */ { $$ = NULL; } ; DirectionalAttribute: KWIN OptShape { $$ = new battr ( ATTR_IN ); /***************** if( $2 ) $$.Merge( ATTRLIST Shape_Attr($2) ); ******************/ } | KWOUT OptShape { $$ = new battr ( ATTR_OUT ); /***************** if( $2 ) $$.Merge( ATTRLIST Shape_Attr($2) ); ******************/ } ; OperationAttribute: KWCALLBACK { $$ = (new battr( ATTR_CALLBACK )); } | KWIDEMPOTENT { $$ = (new battr( ATTR_IDEMPOTENT )); } | KWBROADCAST { $$ = (new battr( ATTR_BROADCAST )); } | KWMAYBE { $$ = (new battr( ATTR_MAYBE )); } | KWASYNC { $$ = (new battr( ATTR_ASYNC )); } | KWINPUTSYNC { $$ = (new battr( ATTR_INPUTSYNC )); } ; OdlAttribute: KWHIDDEN { $$ = (new battr( ATTR_HIDDEN )); } | KWPROPGET { $$ = (new node_member_attr( MATTR_PROPGET )); } | KWPROPPUT { $$ = (new node_member_attr( MATTR_PROPPUT )); } | KWPROPPUTREF { $$ = (new node_member_attr( MATTR_PROPPUTREF )); } | KWOPTIONAL { $$ = (new node_member_attr( MATTR_OPTIONAL )); } | KWVARARG { $$ = (new node_member_attr( MATTR_VARARG )); } | KWRESTRICTED { $$ = (new node_member_attr( MATTR_RESTRICTED )); } | KWREADONLY { $$ = (new node_member_attr( MATTR_READONLY )); } | KWSOURCE { $$ = (new node_member_attr( MATTR_SOURCE )); } | KWDEFAULTVTABLE { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[defaultvtable]"); } $$ = (new node_member_attr( MATTR_DEFAULTVTABLE )); } | KWIMMEDIATEBIND { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[immediatebind]"); } $$ = (new node_member_attr( MATTR_IMMEDIATEBIND )); } | KWREPLACEABLE { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[replaceable]"); } $$ = (new node_member_attr( MATTR_REPLACEABLE )); } | KWUSESGETLASTERROR { $$ = (new node_member_attr( MATTR_USESGETLASTERROR )); } | KWBINDABLE { $$ = (new node_member_attr( MATTR_BINDABLE )); } | KWREQUESTEDIT { $$ = (new node_member_attr( MATTR_REQUESTEDIT )); } | KWDISPLAYBIND { $$ = (new node_member_attr( MATTR_DISPLAYBIND )); } | KWDEFAULTBIND { $$ = (new node_member_attr( MATTR_DEFAULTBIND )); } | KWPREDECLID { $$ = (new node_member_attr( MATTR_PREDECLID )); } | KWRETVAL { $$ = (new node_member_attr( MATTR_RETVAL )); } | KWAPPOBJECT { $$ = (new node_type_attr( TATTR_APPOBJECT )); } | KWPUBLIC { $$ = (new node_type_attr( TATTR_PUBLIC )); } | KWODL { $$ = NULL; } | KWLICENSED { $$ = (new node_type_attr( TATTR_LICENSED )); } | KWCONTROL { $$ = (new node_type_attr( TATTR_CONTROL )); } | KWDUAL { $$ = (new node_type_attr( TATTR_DUAL )); } | KWNONEXTENSIBLE { $$ = (new node_type_attr( TATTR_NONEXTENSIBLE )); } | KWOLEAUTOMATION { $$ = (new node_type_attr( TATTR_OLEAUTOMATION )); } | KWLCID { $$ = (new battr( ATTR_FLCID )); } | KWNONCREATABLE { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[noncreatable]"); } $$ = (new node_type_attr( TATTR_NONCREATABLE )); } | KWAGGREGATABLE { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[aggregatable]"); } $$ = (new node_type_attr( TATTR_AGGREGATABLE )); } | KWUIDEFAULT { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[uidefault]"); } $$ = (new node_member_attr( MATTR_UIDEFAULT )); } | KWNONBROWSABLE { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[nonbrowsable]"); } $$ = (new node_member_attr( MATTR_NONBROWSABLE )); } | KWDEFAULTCOLLELEM { if (!FNewTypeLib()) { ParseError( INVALID_NEWTLB_ATTRIBUTE, "[defaultcollem]"); } $$ = (new node_member_attr( MATTR_DEFAULTCOLLELEM )); } ; OptShape: '(' KWSHAPE ')' { ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[shape]"); $$ = ATTR_NONE; } | /* Empty */ { $$ = ATTR_NONE; } ; /*************** DANGER: EXPRESSIONS FOLLOW: ***************/ Initializer: AssignmentExpr { $$ = $1; #ifdef gajdebug3 printf("\t...init list has constant=%d, from %d\n", $$->IsConstant(),$1->IsConstant() ); #endif } | '{' InitializerList OptionalComma '}' { ParseError( COMPOUND_INITS_NOT_SUPPORTED, (char *)0 ); $$ = NULL; // $$ = new expr_init_list( (expr_node *)NULL ); // $$->LinkChild( $2 ); } /** ** known bug : we need to figure out a way to simulate this hanging list ** maybe by creating a special expr_list node, such that it meets ** all semantic requirements also **/ ; OptionalComma: ',' { } | /** Empty **/ { } ; InitializerList: Initializer { // $$ = $1; } | InitializerList ',' Initializer { // $$->LinkSibling( $3 ); } ; /*** *** VibhasC:WHERE IS THE production expr ',' AssignmentExpr valid ? ***/ Expr: AssignmentExpr | Expr ',' AssignmentExpr { $$ = $3; } ; VariableExpr: ConditionalExpr ; ConstantExpr: ConditionalExpr { /** ** The expression must be a constant, if not report error **/ #ifdef gajdebug3 printf("constant expr is: %d\n",$1->IsConstant()); #endif if( ! $1->IsConstant() ) ParseError( EXPR_NOT_CONSTANT, (char *)NULL ); $$ = $1; } ; AssignmentExpr: ConditionalExpr | UnaryExpr AssignOps AssignmentExpr { /** ** we do not permit assignment in expressions **/ ParseError( SYNTAX_ERROR, (char *)NULL ); $$ = new expr_error; } ; ConditionalExpr: LogicalOrExpr { $$ = $1; #if 0 printf("\n************** expression dump start ***************\n"); BufferManager * pOutput = new BufferManager( 10 ); $$->PrintExpr( (BufferManager *)NULL, (BufferManager *)NULL, pOutput ); pOutput->Print( stdout ); printf("\n****************************************************\n"); #endif // 0 } | LogicalOrExpr '?' Expr ':' ConditionalExpr { /** ** This is a ternary operator. **/ $$ = new expr_ternary( OP_QM, $1, $3, $5 ); } ; LogicalOrExpr: LogicalAndExpr | LogicalOrExpr OROR LogicalAndExpr { $$ = new expr_b_logical( OP_LOGICAL_OR, $1, $3 ); } ; LogicalAndExpr: InclusiveOrExpr | LogicalAndExpr ANDAND InclusiveOrExpr { $$ = new expr_b_logical( OP_LOGICAL_AND, $1, $3 ); } ; InclusiveOrExpr: ExclusiveOrExpr | InclusiveOrExpr '|' ExclusiveOrExpr { $$ = new expr_bitwise( OP_OR, $1, $3 ); } ; ExclusiveOrExpr: AndExpr | ExclusiveOrExpr '^' AndExpr { $$ = new expr_bitwise( OP_XOR, $1, $3 ); } ; AndExpr: EqualityExpr | AndExpr '&' EqualityExpr { $$ = new expr_bitwise( OP_AND, $1, $3 ); } ; EqualityExpr: RelationalExpr | EqualityExpr EQUALS RelationalExpr { $$ = new expr_relational( OP_EQUAL, $1, $3 ); } | EqualityExpr NOTEQ RelationalExpr { $$ = new expr_relational( OP_NOT_EQUAL, $1, $3 ); } ; RelationalExpr: ShiftExpr | RelationalExpr '<' ShiftExpr { $$ = new expr_relational( OP_LESS, $1, $3 ); } | RelationalExpr '>' ShiftExpr { $$ = new expr_relational( OP_GREATER, $1, $3 ); } | RelationalExpr LTEQ ShiftExpr { $$ = new expr_relational( OP_LESS_EQUAL, $1, $3 ); } | RelationalExpr GTEQ ShiftExpr { $$ = new expr_relational( OP_GREATER_EQUAL, $1, $3 ); } ; ShiftExpr: AdditiveExpr | ShiftExpr LSHIFT AdditiveExpr { $$ = new expr_shift( OP_LEFT_SHIFT, $1, $3 ); } | ShiftExpr RSHIFT AdditiveExpr { $$ = new expr_shift( OP_RIGHT_SHIFT, $1, $3 ); } ; AdditiveExpr: MultExpr | AdditiveExpr AddOp MultExpr { $$ = new expr_b_arithmetic( $2, $1, $3 ); } ; MultExpr: CastExpr | MultExpr MultOp CastExpr { $$ = new expr_b_arithmetic( $2, $1, $3 ); } ; CastExpr: UnaryExpr | '(' DeclarationSpecifiers OptionalDeclarator ')' CastExpr { node_skl * pNode = pErrorTypeNode; if( $2.pNode ) { if( $3.pHighest ) { $3.pLowest->SetChild( $2.pNode ); pNode = $3.pHighest; if( $2.modifiers ) { ( (named_node *) $3.pLowest)->SetModifiers( $2.modifiers ); } } else pNode = $2.pNode; } $$ = new expr_cast( pNode, $5 ); } ; UnaryExpr: PostfixExpr | UnaryOp CastExpr { ( (expr_op_unary *) ($$ = $1) )->SetLeft( $2 ); if ( $2 ) ( (expr_op_unary *) $$)->SetConstant( $2->IsConstant() ); } | KWSIZEOF '(' DeclarationSpecifiers OptionalDeclarator ')' { /** ** The sizeof construct looks like a declaration and a possible ** declarator. All we really do, is to contruct the type ( graph ) ** and hand it over to the sizeof expression node. If there was an ** error, just construct the size of with an error node **/ node_skl * pNode = pErrorTypeNode; node_skl * pLow; if( $3.pNode ) { if( $4.pHighest ) { pNode = $4.pHighest; pLow = $4.pLowest; pLow->SetChild( $3.pNode ); pLow->SetModifiers( $3.modifiers ); } else { pNode = $3.pNode; } } $$ = new expr_sizeof( pNode ); } | KWSIZEOF UnaryExpr { $$ = new expr_sizeof( $2 ); } ; PostfixExpr: PrimaryExpr | PostfixExpr '[' Expr ']' { $$ = new expr_index( $1, $3 ); } | PostfixExpr '(' ArgExprList ')' { /** ** not implemented **/ ParseError( EXPR_NOT_IMPLEMENTED, (char *)NULL ); $$ = new expr_error; } | PostfixExpr POINTSTO IDENTIFIER { expr_variable * pIDExpr = new expr_variable( $3 ); $$ = new expr_pointsto( $1, pIDExpr ); } | PostfixExpr '.' IDENTIFIER { expr_variable * pIDExpr = new expr_variable( $3 ); $$ = new expr_dot( $1, pIDExpr ); } ; PrimaryExpr: IDENTIFIER { // true if the identifier represents a constant BOOL ConstVar = FALSE; named_node * pNode = NULL; SymKey SKey( $1, NAME_MEMBER ); pNode = pCurSymTbl->SymSearch( SKey ); // look for a global ID matching the id if ( ! pNode ) { SymKey SKey2( $1, NAME_ID ); pNode = pBaseSymTbl->SymSearch( SKey2 ); ConstVar = (pNode) ? ((node_id_fe *) pNode)->IsConstant() : FALSE; } // look for a global enum label matching the id if ( !pNode ) { SymKey SKey2( $1, NAME_LABEL ); pNode = pBaseSymTbl->SymSearch( SKey2 ); ConstVar = (pNode != NULL); } if ( !pNode ) pNode = new node_forward( SKey, pCurSymTbl ); if (ConstVar) { $$ = new expr_named_constant( $1, pNode ); } else { $$ = new expr_variable( $1, pNode ); } } | NUMERICCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_NUMERIC ); } | NUMERICUCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_NUMERIC_U); node_skl * pType; GetBaseTypeNode( &pType, SIGN_UNSIGNED,SIZE_UNDEF,TYPE_INT ); $$->SetType( pType ); } | NUMERICLONGCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_NUMERIC_LONG); node_skl * pType; GetBaseTypeNode( &pType, SIGN_SIGNED,SIZE_LONG,TYPE_INT ); $$->SetType( pType ); } | NUMERICULONGCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_NUMERIC_ULONG); node_skl * pType; GetBaseTypeNode( &pType, SIGN_UNSIGNED,SIZE_LONG,TYPE_INT ); $$->SetType( pType ); } | HEXCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_HEX ); } | HEXUCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_HEX_U); node_skl * pType; GetBaseTypeNode( &pType, SIGN_UNSIGNED,SIZE_UNDEF,TYPE_INT ); $$->SetType( pType ); } | HEXLONGCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_HEX_LONG); node_skl * pType; GetBaseTypeNode( &pType, SIGN_SIGNED,SIZE_LONG,TYPE_INT ); $$->SetType( pType ); } | HEXULONGCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_HEX_ULONG); node_skl * pType; GetBaseTypeNode( &pType, SIGN_UNSIGNED,SIZE_LONG,TYPE_INT ); $$->SetType( pType ); } | OCTALCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_OCTAL ); } | OCTALUCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_OCTAL_U); node_skl * pType; GetBaseTypeNode( &pType, SIGN_UNSIGNED,SIZE_UNDEF,TYPE_INT ); $$->SetType( pType ); } | OCTALLONGCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_OCTAL_LONG); node_skl * pType; GetBaseTypeNode( &pType, SIGN_SIGNED,SIZE_LONG,TYPE_INT ); $$->SetType( pType ); } | OCTALULONGCONSTANT { $$ = new expr_constant( (long) $1.Val, VALUE_TYPE_OCTAL_ULONG); node_skl * pType; GetBaseTypeNode( &pType, SIGN_UNSIGNED,SIZE_LONG,TYPE_INT ); $$->SetType( pType ); } | TOKENTRUE { $$ = new expr_constant( (long)TRUE, VALUE_TYPE_BOOL ); } | TOKENFALSE { $$ = new expr_constant( (long)FALSE, VALUE_TYPE_BOOL ); } | KWTOKENNULL { $$ = new expr_constant( (char *)NULL, VALUE_TYPE_STRING ); } | STRING { $$ = new expr_constant( (char *)$1, VALUE_TYPE_STRING ); } | WIDECHARACTERSTRING { ParseError( WCHAR_STRING_NOT_OSF, (char *)NULL ); $$ = new expr_constant( (wchar_t *)$1, VALUE_TYPE_WSTRING ); } | CHARACTERCONSTANT { $$ = new expr_constant( (long)( ((long)$1.Val) & 0xff ) , VALUE_TYPE_CHAR ); } | WIDECHARACTERCONSTANT { $$ = new expr_constant( (long)( ((long)$1.Val ) & 0xffff ), VALUE_TYPE_WCHAR ); ParseError( WCHAR_CONSTANT_NOT_OSF, (char *)NULL ); } | '(' Expr ')' { $$ = $2; } ; UnaryOp: AddOp { $$ = new expr_u_arithmetic( ($1 == OP_PLUS) ? OP_UNARY_PLUS : OP_UNARY_MINUS, NULL ); } | '!' { $$ = new expr_u_not( NULL ); } | '&' { $$ = new expr_u_deref( OP_UNARY_AND, NULL ); } | '*' { $$ = new expr_u_deref( OP_UNARY_INDIRECTION, NULL ); } | '~' { $$ = new expr_u_complement( NULL); } ; AddOp: '+' { $$ = OP_PLUS; } | '-' { $$ = OP_MINUS; } ; MultOp: '*' { $$ = OP_STAR; } | '/' { $$ = OP_SLASH; } | '%' { $$ = OP_MOD; } ; ArgExprList: AssignmentExpr { ParseError( EXPR_NOT_IMPLEMENTED, (char *)NULL ); $$ = new expr_error; } | ArgExprList ',' AssignmentExpr { /* UNIMPLEMENTED YET */ $$ = $1; } ; AssignOps: MULASSIGN | DIVASSIGN | MODASSIGN | ADDASSIGN | SUBASSIGN | LEFTASSIGN | RIGHTASSIGN | ANDASSIGN | XORASSIGN | ORASSIGN ; %% /*************************************************************************** * utility routines **************************************************************************/ YYSTATIC VOID FARCODE PASCAL yyerror(char *szError) { // this routine should really never be called now, since I // modified yypars.c to report errors thru the ParseError // mechanism fprintf(stderr, szError); } void NTDBG( char * p ) { printf("VC_DBG: %s\n", p ); }