mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5700 lines
115 KiB
5700 lines
115 KiB
/* SCCSWHAT( "@(#)grammar.y 1.4 89/05/09 21:22:03 " ) */
|
|
|
|
/*****************************************************************************/
|
|
/** 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
|
|
*****************************************************************************/
|
|
%{
|
|
|
|
/****************************************************************************
|
|
*** 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 YYLEX yylex
|
|
#define YYPARSER yyparse
|
|
|
|
|
|
#define IS_CUR_INTERFACE_LOCAL() ( \
|
|
(BOOL) (pInterfaceInfoDict->IsInterfaceLocal()) || \
|
|
((ImportLevel == 0 ) && ( pCommand->IsSwitchDefined( SWITCH_HPP ) ) ) \
|
|
)
|
|
|
|
/****************************************************************************
|
|
*** include files
|
|
***************************************************************************/
|
|
|
|
#include "nulldefs.h"
|
|
|
|
extern "C" {
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
int yyparse();
|
|
}
|
|
#include "nodeskl.hxx"
|
|
#include "lexutils.hxx"
|
|
#include "gramutil.hxx"
|
|
#include "ptrarray.hxx"
|
|
#include "miscnode.hxx"
|
|
#include "procnode.hxx"
|
|
#include "compnode.hxx"
|
|
#include "typedef.hxx"
|
|
#include "attrnode.hxx"
|
|
#include "acfattr.hxx"
|
|
#include "newexpr.hxx"
|
|
#include "idict.hxx"
|
|
#include "ctxt.hxx"
|
|
#include "filehndl.hxx"
|
|
#include "cmdana.hxx"
|
|
#include "control.hxx"
|
|
#include "textsub.hxx"
|
|
|
|
extern "C"
|
|
{
|
|
#include "lex.h"
|
|
|
|
extern char * KeywordToString( token_t );
|
|
}
|
|
|
|
void yyunlex( token_t );
|
|
|
|
/***************************************************************************
|
|
* local data
|
|
**************************************************************************/
|
|
|
|
type_node_list * pHppPreDefinedTypes = (type_node_list *)0;
|
|
BOOL fObject = 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 short CompileMode;
|
|
extern BOOL fPragmaImportOn;
|
|
extern CCONTROL * pCompiler;
|
|
extern node_source * pSourceNode;
|
|
extern CTXTMGR * pGlobalContext;
|
|
extern NFA_INFO * pImportCntrl;
|
|
extern PASS_1 * pPass1;
|
|
extern BOOL fAbandonNumberLengthLimits;
|
|
extern ATTR_T PtrDefaultAttr;
|
|
extern IINFODICT * pInterfaceInfoDict;
|
|
extern BOOL fGuidContext;
|
|
extern BOOL fVersionContext;
|
|
extern BOOL fRedundantImport;
|
|
extern node_skl * pBaseImplicitHandle;
|
|
|
|
/***************************************************************************
|
|
* external functions
|
|
**************************************************************************/
|
|
|
|
extern BOOL IsTempName( char * );
|
|
extern node_skl * SetHppPredefinedTypes( char * );
|
|
extern char * GenTempName();
|
|
extern char * GenCompName();
|
|
extern void SetAttributeVector( PATTR_SUMMARY, ATTR_T );
|
|
extern void ApplyAttributes( node_skl *, type_node_list *);
|
|
extern void ApplySummaryAttributes( node_skl *,
|
|
ATTR_SUMMARY * );
|
|
extern void CopyNode( node_skl *, node_skl * );
|
|
extern STATUS_T GetBaseTypeNode( node_skl**, short, short, short);
|
|
extern type_node_list * GenerateFieldAttribute( NODE_T, expr_list *);
|
|
extern node_skl * SearchTag( char *, NAME_T );
|
|
extern void SelectiveSemanticsAndEnGraph(type_node_list **,
|
|
type_node_list *,
|
|
type_node_list *,
|
|
BOOL,
|
|
BOOL );
|
|
extern node_skl * CopyBaseType( node_skl * );
|
|
extern battr * GetPreAllocatedBitAttr( ATTR_T );
|
|
extern void SyntaxError( STATUS_T, short );
|
|
extern int PossibleMissingToken( short, short );
|
|
extern char * MakeNewStringWithProperQuoting( char * );
|
|
extern BOOL IsValidSizeOfType( node_skl * );
|
|
extern void CheckGlobalNamesClash( SymKey );
|
|
extern void CheckSpecialForwardTypedef( node_skl *,
|
|
node_skl *,
|
|
type_node_list *);
|
|
|
|
/***************************************************************************
|
|
* local data
|
|
**************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* local defines
|
|
**************************************************************************/
|
|
#define YY_CATCH(x)
|
|
#define DEFINE_STRING "#define"
|
|
#define LEN_DEFINE (7)
|
|
|
|
%}
|
|
|
|
/****************************************************************************/
|
|
|
|
|
|
%start RpcProg
|
|
|
|
|
|
//WARNING: The following token list must be identical in both grammar.y and acfgram.y
|
|
%token POINTSTO
|
|
|
|
|
|
%token KWINTERFACE
|
|
%token KWIMPORT
|
|
%token KWUUID
|
|
%token KWVERSION
|
|
%token KWCONST
|
|
%token KWCHAR
|
|
%token KWVOID
|
|
%token KWSTRING
|
|
%token KWBSTRING
|
|
%token STRING
|
|
%token WIDECHARACTERSTRING
|
|
%token SDEFINE
|
|
%token PDEFINE
|
|
%token KWTYPEDEF
|
|
%token KWFLOAT
|
|
%token KWDOUBLE
|
|
%token KWINT
|
|
%token KWUNSIGNED
|
|
%token KWSIGNED
|
|
|
|
%token KWLONG
|
|
%token KWSHORT
|
|
%token KWSTRUCT
|
|
%token KWUNION
|
|
%token KWCASE
|
|
%token KWDEFAULT
|
|
%token KWENUM
|
|
%token KWSHORTENUM
|
|
%token KWLONGENUM
|
|
%token KWIN
|
|
%token KWOUT
|
|
%token KWFIRSTIS
|
|
%token KWLASTIS
|
|
%token KWMAXIS
|
|
%token KWLENGTHIS
|
|
%token KWSIZEIS
|
|
%token KWHANDLET /* Formerly RPCHNDL */
|
|
%token KWHANDLE /* Formerly GEN_HNDL */
|
|
%token KWCONTEXTHANDLE /* Aka LRPC_CTXT_HNDL */
|
|
%token KWBYTECOUNT
|
|
|
|
%token KWSHAPE
|
|
%token KWENDPOINT
|
|
%token KWDEFAULTPOINTER
|
|
%token KWLOCAL
|
|
%token KWBYTE
|
|
%token KWSWITCH
|
|
%token KWSWITCHTYPE
|
|
%token KWSWITCHIS
|
|
%token KWTRANSMITAS
|
|
%token KWIGNORE
|
|
%token KWREF
|
|
%token KWUNIQUE
|
|
%token KWPTR
|
|
%token KWEXTERN
|
|
%token KW_C_INLINE
|
|
%token KWSTATIC
|
|
%token KWAUTO
|
|
%token KWREGISTER
|
|
%token KWABNORMAL
|
|
|
|
%token KWTOKENNULL
|
|
%token NUMERICCONSTANT
|
|
%token NUMERICLONGCONSTANT
|
|
%token NUMERICULONGCONSTANT
|
|
%token HEXCONSTANT
|
|
%token HEXLONGCONSTANT
|
|
%token HEXULONGCONSTANT
|
|
%token OCTALCONSTANT
|
|
%token OCTALLONGCONSTANT
|
|
%token OCTALULONGCONSTANT
|
|
%token KWSIZEOF
|
|
%token CHARACTERCONSTANT
|
|
%token WIDECHARACTERCONSTANT
|
|
%token IDENTIFIER
|
|
|
|
/*****
|
|
These are internal-only pcode-compiler keywords
|
|
|
|
%token PCODENATIVE
|
|
%token PCODECSCONST
|
|
%token PCODESYS
|
|
%token PCODENSYS
|
|
%token PCODEUOP
|
|
%token PCODENUOP
|
|
%token PCODETLBX
|
|
******/
|
|
|
|
/* These are Microsoft C abominations */
|
|
|
|
%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 MSCFAR16
|
|
%token MSCUNALIGNED
|
|
%token MSCHUGE
|
|
%token MSCPASCAL
|
|
%token MSCBASE
|
|
%token MSCSEGNAME
|
|
%token MSCEMIT
|
|
%token MSCABNORMAL
|
|
%token MSCASM
|
|
|
|
/* Microsoft proposed extentions to NIDL */
|
|
|
|
%token KWCALLBACK
|
|
%token KWNOLISTEN
|
|
%token KWNOCODE /* Allowed in .IDL in addition to .ACF */
|
|
%token KWOPAQUE32
|
|
|
|
|
|
/* Microsoft extensions for internal use only */
|
|
|
|
%token INTERNALMANUAL
|
|
%token INTERNALLINEAR
|
|
|
|
/* These are residual C tokens I'm not sure we should even allow */
|
|
|
|
%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 TYPE
|
|
%token KWVOLATILE /* Do we have to be able to handle this as
|
|
a TYPE? (as they did in the old lexer) */
|
|
|
|
%token LTEQ
|
|
%token GTEQ
|
|
%token NOTEQ
|
|
%token NOTOKEN /* This is actually not a "real" token,
|
|
merely a symbolic value that is
|
|
used to mean "I have no real token
|
|
value yet."
|
|
*/
|
|
%token LSHIFT
|
|
%token RSHIFT
|
|
%token ANDAND
|
|
%token EQUALS
|
|
%token OROR
|
|
%token AUTO
|
|
%token STATIC
|
|
%token EXTERN
|
|
%token REGISTER
|
|
|
|
%token TYPEDEF
|
|
%token TYPENAME
|
|
|
|
//CairOle extensions to MIDL
|
|
%token KWIIDIS
|
|
%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 KWIMPLICITHANDLE
|
|
%token KWAUTOHANDLE
|
|
%token KWEXPLICITHANDLE
|
|
%token KWREPRESENTAS
|
|
%token KWCODE
|
|
%token KWINLINE
|
|
%token KWOUTOFLINE
|
|
%token KWINTERPRET
|
|
%token KWNOINTERPRET
|
|
%token KWENCODE
|
|
%token KWDECODE
|
|
%token KWCOMMSTATUS
|
|
%token KWFAULTSTATUS
|
|
%token KWHEAP
|
|
%token KWINCLUDE
|
|
%token KWPOINTERSIZE
|
|
%token KWCALLQUOTA
|
|
%token KWCALLBACKQUOTA
|
|
%token KWCLIENTQUOTA
|
|
%token KWSERVERQUOTA
|
|
%token KWOFFLINE
|
|
%token KWALLOCATE
|
|
%token KWMANUAL
|
|
%token KWNOTIFY
|
|
%token KWENABLEALLOCATE
|
|
%token KWUSRMARSHALL
|
|
|
|
/* Currently Unsupported Tokens */
|
|
|
|
%token TOKENTRUE
|
|
%token TOKENFALSE
|
|
%token KWBOOLEAN
|
|
%token KWBITSET
|
|
%token KWSMALL
|
|
|
|
%token KWALIGN
|
|
%token KWUNALIGNED
|
|
%token KWERRORSTATUST
|
|
%token KWECHOSTRING
|
|
%token KWCPPQUOTE
|
|
%token KWISOLATIN1
|
|
%token KWPRIVATECHAR8
|
|
%token KWISOMULTILINGUAL
|
|
%token KWPRIVATECHAR16
|
|
%token KWISOUCS
|
|
%token KWV1ARRAY
|
|
%token KWV1STRUCT
|
|
%token KWV1ENUM
|
|
%token KWPIPE
|
|
%token KWDATAGRAM
|
|
%token KWIDEMPOTENT
|
|
%token KWBROADCAST
|
|
%token KWMAYBE
|
|
%token KWCPRAGMA
|
|
%token KWMPRAGMAIMPORT
|
|
%token KWMPRAGMAECHO
|
|
%token KWMPRAGMAIMPORTCLNTAUX
|
|
%token KWMPRAGMAIMPORTSRVRAUX
|
|
%token KWMPRAGMAIUNKNOWN
|
|
%token UUIDTOKEN
|
|
%token VERSIONTOKEN
|
|
|
|
|
|
/* Adjudged to be bad: */
|
|
|
|
%token KWV1STRING
|
|
%token KWHYPER
|
|
%token KWMINIS
|
|
%token KWCSTRING
|
|
|
|
%token ELIPSIS
|
|
|
|
/* Dov: Are these really bad? */
|
|
|
|
%token EOI
|
|
%token LASTTOKEN
|
|
|
|
/* moved to ACF... */
|
|
|
|
/*****************************************************************************
|
|
* %types of various non terminals and terminals
|
|
*****************************************************************************/
|
|
%type <yy_graph> AcfAutoHdlAttr
|
|
%type <yy_graph> AcfInterfaceAttribute
|
|
%type <yy_graph> AcfImpHdlAttr
|
|
%type <yy_graph> AcfImpHdlTypeSpec
|
|
%type <yy_ptrdecl> ActualDeclarationSpecifiers
|
|
%type <yy_short> AddOp
|
|
%type <yy_expr> AdditiveExpr
|
|
%type <yy_expr> AndExpr
|
|
%type <yy_expr> ArgExprList
|
|
%type <yy_abounds> ArrayBoundsPair
|
|
%type <yy_graph> ArrayDecl
|
|
%type <yy_abounds> ArrayDecl2
|
|
%type <yy_short> AssignOps
|
|
%type <yy_expr> AssignmentExpr
|
|
%type <yy_expr> AttrVar
|
|
%type <yy_exprlist> AttrVarList
|
|
%type <yy_pSymName> BaseInterfaceSpec
|
|
%type <yy_type> BaseTypeSpec
|
|
%type <yy_graph> BitSetType
|
|
%type <yy_graph> CPragmaSet
|
|
%type <yy_expr> CastExpr
|
|
%type <yy_numeric> CHARACTERCONSTANT
|
|
%type <yy_numeric> WIDECHARACTERCONSTANT
|
|
%type <yy_type> CharSpecs
|
|
%type <yy_expr> ConditionalExpr
|
|
%type <yy_expr> ConstantExpr
|
|
%type <yy_exprlist> ConstantExprs
|
|
%type <yy_tnlist> Declaration
|
|
%type <yy_ptrdecl> DeclarationSpecifiers
|
|
%type <yy_tnlist> DeclarationSpecifiersPostFix
|
|
%type <yy_graph> Declarator
|
|
%type <yy_graph> Declarator2
|
|
%type <yy_tnlist> DefaultCase
|
|
%type <yy_tnlist> DirectionalAttribute
|
|
%type <yy_string> EndPtSpec
|
|
%type <yy_endpt> EndPtSpecs
|
|
%type <yy_graph> EnumerationType
|
|
%type <yy_enlab> Enumerator
|
|
%type <yy_enlist> EnumeratorList
|
|
%type <yy_graph> EnumSpecifier
|
|
%type <yy_expr> EqualityExpr
|
|
%type <yy_expr> ExclusiveOrExpr
|
|
%type <yy_expr> Expr
|
|
%type <yy_tnlist> FieldAttrSet
|
|
%type <yy_tnlist> FieldAttribute
|
|
%type <yy_tnlist> FieldAttributeList
|
|
%type <yy_tnlist> FieldAttributes
|
|
/***
|
|
%type <yy_string> GuidNumber
|
|
%type <yy_graph> GuidRep
|
|
***/
|
|
%type <yy_graph> Guid
|
|
%type <yy_numeric> HEXCONSTANT
|
|
%type <yy_numeric> HEXLONGCONSTANT
|
|
%type <yy_numeric> HEXULONGCONSTANT
|
|
%type <yy_pSymName> IDENTIFIER
|
|
%type <yy_tnlist> Import
|
|
%type <yy_tnlist> ImportName
|
|
%type <yy_tnlist> ImportList
|
|
%type <yy_expr> InclusiveOrExpr
|
|
%type <yy_declarator> InitDeclarator
|
|
%type <yy_declarator_set> InitDeclaratorList
|
|
%type <yy_short> InternationalCharacterType
|
|
%type <yy_type> IntModifier
|
|
%type <yy_type> IntModifiers
|
|
%type <yy_short> IntSize
|
|
%type <yy_type> IntSpec
|
|
%type <yy_initlist> Initializer
|
|
%type <yy_initlist> InitializerList
|
|
%type <yy_tnlist> Interface
|
|
%type <yy_tnlist> InterfaceAttrList
|
|
%type <yy_tnlist> InterfaceAttrSet
|
|
%type <yy_graph> InterfaceAttribute
|
|
%type <yy_tnlist> InterfaceAttributes
|
|
%type <yy_intbody> InterfaceBody
|
|
%type <yy_graph> InterfaceComp
|
|
%type <yy_tnlist> InterfaceComponent
|
|
%type <yy_tnlist> InterfaceComponents
|
|
%type <yy_inthead> InterfaceHeader
|
|
%type <yy_string> KWCPRAGMA
|
|
%type <yy_expr> LogicalAndExpr
|
|
%type <yy_expr> LogicalOrExpr
|
|
%type <yy_tnlist> MemberDeclaration
|
|
%type <yy_declarator> MemberDeclarator
|
|
%type <yy_declarator_set> MemberDeclaratorList
|
|
%type <yy_graph> MidlPragmaSet
|
|
%type <yy_graph> Modifier
|
|
%type <yy_attrenum> ModifierAllowed
|
|
%type <yy_short> MultOp
|
|
%type <yy_tnlist> MultipleImport
|
|
%type <yy_expr> MultExpr
|
|
%type <yy_tnlist> NidlMemberDeclaration
|
|
%type <yy_tnlist> NidlUnionBody
|
|
%type <yy_nucase> NidlUnionCase
|
|
%type <yy_nucaselabel> NidlUnionCaseLabel
|
|
%type <yy_nucllist> NidlUnionCaseLabelList
|
|
%type <yy_nucases> NidlUnionCases
|
|
%type <yy_en_switch> NidlUnionSwitch
|
|
%type <yy_attrenum> NV1OperationAttribute
|
|
%type <yy_numeric> NUMERICCONSTANT
|
|
%type <yy_numeric> NUMERICLONGCONSTANT
|
|
%type <yy_numeric> NUMERICULONGCONSTANT
|
|
/*******
|
|
%type <yy_numeric> Number
|
|
********/
|
|
%type <yy_numeric> OCTALCONSTANT
|
|
%type <yy_numeric> OCTALLONGCONSTANT
|
|
%type <yy_numeric> OCTALULONGCONSTANT
|
|
%type <yy_tnlist> OneFieldAttrList
|
|
%type <yy_baseattr> OneInterfaceAttribute
|
|
%type <yy_tnlist> OneOpOrSwTypeAttr
|
|
%type <yy_tnlist> OneParamAttrList
|
|
%type <yy_tnlist> OneTypeAttrList
|
|
%type <yy_graph> OperationAttribute
|
|
%type <yy_tnlist> OperationAttributes
|
|
%type <yy_tnlist> OperationAttributeList
|
|
%type <yy_tnlist> OpOrSwTypeAttrSet
|
|
%type <yy_tnlist> OpOrSwTypeAttributes
|
|
%type <yy_attrenum> OptShape
|
|
%type <yy_short> OptionalComma
|
|
%type <yy_tnlist> OptionalConst
|
|
%type <yy_graph> OptionalDeclarator
|
|
%type <yy_declarator_set> OptionalInitDeclaratorList
|
|
%type <yy_tnlist> OptionalInterfaceAttrList
|
|
%type <yy_string> OptionalEnumTag
|
|
%type <yy_string> OptionalTag
|
|
%type <yy_tnlist> OptionalTypeQualifiers
|
|
%type <yy_graph> OtherFieldAttribute
|
|
%type <yy_attrenum> OtherOperationAttribute
|
|
%type <yy_tnlist> ParamAttrSet
|
|
%type <yy_tnlist> ParamAttribute
|
|
%type <yy_tnlist> ParamAttributeList
|
|
%type <yy_tnlist> ParamAttributes
|
|
%type <yy_graph> ParameterDeclaration
|
|
%type <yy_tnlist> ParameterList
|
|
%type <yy_graph> ParameterTypeDeclaration
|
|
%type <yy_tnlist> ParameterTypeList
|
|
%type <yy_tnlist> ParamsDecl2
|
|
%type <yy_define> PDEFINE
|
|
%type <yy_tnlist> PhantomInterface
|
|
%type <yy_ptrdecl> Pointer
|
|
%type <yy_ptrdecl2> Pointer2
|
|
%type <yy_expr> PostfixExpr
|
|
%type <yy_graph> PredefinedTypeSpec
|
|
%type <yy_expr> PrimaryExpr
|
|
%type <yy_graph> PtrAttr
|
|
%type <yy_expr> RelationalExpr
|
|
%type <yy_define> SDEFINE
|
|
%type <yy_expr> ShiftExpr
|
|
%type <yy_type> SignSpecs
|
|
%type <yy_graph> SimpleTypeSpec
|
|
%type <yy_attrenum> StorageClassSpecifier
|
|
%type <yy_string> STRING
|
|
%type <yy_string> WIDECHARACTERSTRING
|
|
%type <yy_tnlist> StructDeclarationList
|
|
%type <yy_en_switch> SwitchSpec
|
|
%type <yy_graph> SwitchTypeSpec
|
|
%type <yy_string> Tag
|
|
%type <yy_graph> TaggedSpec
|
|
%type <yy_graph> TaggedStructSpec
|
|
%type <yy_graph> TaggedUnionSpec
|
|
%type <yy_tnlist> TypeAttrSet
|
|
%type <yy_graph> TypeAttribute
|
|
%type <yy_tnlist> TypeAttributes
|
|
%type <yy_tnlist> TypeAttributeList
|
|
%type <yy_ptrdecl> TypeDeclarationSpecifiers
|
|
%type <yy_attrenum> TypeQualifier
|
|
%type <yy_attrenum> TypeQualifier2
|
|
%type <yy_pSymName> TYPENAME
|
|
%type <yy_graph> TypeSpecifier
|
|
%type <yy_string> UUIDTOKEN
|
|
%type <yy_expr> UnaryExpr
|
|
%type <yy_short> UnaryOp
|
|
%type <yy_graph> UnimplementedTypeAttribute
|
|
%type <yy_graph> UnimplementedV1Attributes
|
|
%type <yy_tnlist> UnionBody
|
|
%type <yy_tnlist> UnionCase
|
|
%type <yy_graph> UnionCaseLabel
|
|
%type <yy_tnlist> UnionCases
|
|
%type <yy_graph> UnionInstanceSwitchAttr
|
|
%type <yy_pSymName> UnionName
|
|
%type <yy_graph> UnionTypeSwitchAttr
|
|
%type <yy_graph> UsageAttribute
|
|
%type <yy_expr> VariableExpr
|
|
%type <yy_string> VERSIONTOKEN
|
|
%type <yy_graph> VersionSpec
|
|
%type <yy_graph> XmitType
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
|
|
%%
|
|
RpcProg:
|
|
Interface
|
|
{
|
|
YY_CATCH("RpcProg: Interface");
|
|
node_skl * pNode = (node_skl *)new node_source;
|
|
BadUseInfo BU;
|
|
|
|
|
|
pNode->SetMembers( $1 );
|
|
pSourceNode = (node_source *)pNode;
|
|
|
|
pNode->SCheck( &BU );
|
|
|
|
/**
|
|
** If there were errors detected in the 1st pass, the dont do
|
|
** anything.
|
|
**/
|
|
|
|
if( !pCompiler->GetErrorCount() )
|
|
{
|
|
/**
|
|
** if forward declarations were present, resolve them
|
|
** and go to do semantics again
|
|
**/
|
|
|
|
pPass1->ResolveFDecl();
|
|
|
|
if( !pCompiler->GetErrorCount() )
|
|
{
|
|
pGlobalContext->SetSecondPass();
|
|
pNode->SCheck( &BU );
|
|
|
|
/**
|
|
** If we found no errors, the first compiler phase is over
|
|
**/
|
|
|
|
if( !pCompiler->GetErrorCount() )
|
|
{
|
|
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
|
|
|
|
if( pNode->AreForwardDeclarationsPresent() )
|
|
{
|
|
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;
|
|
|
|
}
|
|
;
|
|
|
|
Interface:
|
|
InterfaceHeader '{' InterfaceBody '}' EOI
|
|
{
|
|
YY_CATCH("Interface: InterfaceHeader '{' InterfaceBody '}' EOI ");
|
|
|
|
/**
|
|
** This is the place where the complete interface construct
|
|
** has been reduced. We need to introduce an interface node, and a
|
|
** file node from which the interface node will hang.
|
|
**/
|
|
|
|
node_file * pFile;
|
|
char * pInputFileName;
|
|
|
|
/**
|
|
** Prepare the interface node by applying the interface name and
|
|
** the interface attributes to it.
|
|
**/
|
|
|
|
$3.pNode->SetSymName( $1.pInterfaceName );
|
|
ApplyAttributes( $3.pNode, $1.pInterfaceAttrList );
|
|
((node_interface *) $3.pNode)->SetBaseInterfaceName($1.pBaseInterfaceName);
|
|
|
|
/**
|
|
** 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 node as a member of the file node.
|
|
**/
|
|
|
|
pFile->SetBasicType( $3.pNode );
|
|
|
|
/**
|
|
** 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( $3.pImports )
|
|
$$ = $3.pImports;
|
|
else
|
|
$$ = new type_node_list;
|
|
|
|
$$->SetPeer( pFile );
|
|
|
|
// dont try to delete pHppPreDefinedList. This has already been
|
|
// deleted.
|
|
|
|
pHppPreDefinedTypes = (type_node_list *) 0;
|
|
}
|
|
;
|
|
|
|
InterfaceHeader:
|
|
OptionalInterfaceAttrList KWINTERFACE Tag BaseInterfaceSpec
|
|
{
|
|
YY_CATCH("InterfaceHeader: InterfaceAttrList KWINTERFACE Tag BaseInterfaceSpec");
|
|
$$.pInterfaceAttrList = $1;
|
|
$$.pInterfaceName = $3;
|
|
$$.pBaseInterfaceName = $4;
|
|
//Is this an object oriented interface?
|
|
if( fObject || pCommand->IsSwitchDefined( SWITCH_HPP ) )
|
|
{
|
|
//Add the interface name to the symbol table.
|
|
//This enables the use of interface pointers.
|
|
pHppPreDefinedTypes = new type_node_list(
|
|
SetHppPredefinedTypes( $3 ));
|
|
}
|
|
|
|
// start the new interface
|
|
|
|
pInterfaceInfoDict->SetInterfaceName( $3 );
|
|
}
|
|
|
|
;
|
|
|
|
BaseInterfaceSpec:
|
|
':' Tag
|
|
{
|
|
$$ = $2;
|
|
}
|
|
| //empty
|
|
{
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
OptionalInterfaceAttrList:
|
|
InterfaceAttrList
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| /* Empty */
|
|
{
|
|
$$ = (type_node_list *)0;
|
|
}
|
|
;
|
|
|
|
InterfaceAttrList:
|
|
InterfaceAttrList InterfaceAttrSet
|
|
{
|
|
YY_CATCH("InterfaceAttrList: InterfaceAttrList InterfaceAttrSet");
|
|
$$->Merge( $2 );
|
|
}
|
|
| InterfaceAttrSet
|
|
{
|
|
YY_CATCH("InterfaceAttrList: InterfaceAttrSet");
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
InterfaceAttrSet:
|
|
'[' InterfaceAttributes ']'
|
|
{
|
|
YY_CATCH("InterfaceAttrSet: '[' InterfaceAttributes ']'");
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
InterfaceAttributes:
|
|
InterfaceAttributes ',' OneInterfaceAttribute
|
|
{
|
|
YY_CATCH("| InterfaceAttributes ',' OneInterfaceAttribute");
|
|
if($3)
|
|
$$->SetPeer( (node_skl *) $3 );
|
|
}
|
|
| OneInterfaceAttribute
|
|
{
|
|
YY_CATCH("InterfaceAttributes: OneInterfaceAttribute");
|
|
if($1)
|
|
$$ = new type_node_list( (node_skl *) $1 );
|
|
else
|
|
$$ = new type_node_list;
|
|
}
|
|
;
|
|
|
|
OneInterfaceAttribute:
|
|
InterfaceAttribute
|
|
{
|
|
YY_CATCH("OneInterfaceAttribute: InterfaceAttribute");
|
|
|
|
/**
|
|
** Why is this production here ? Interesting question. This production
|
|
** unifies semantic check message code for one interface attr.
|
|
** We semantically analyse here and not when the complete interface
|
|
** production has been reduced . Because the interface production is
|
|
** reduced when all of the file has been read and if there are any
|
|
** errors in attributes, they will get reported at the wrong line
|
|
** number (line number near to the end of file ) To prevent that we
|
|
** semantically analyse when the attribute gets defined
|
|
**
|
|
** The exception to this rule are acf attributes under the app config
|
|
** switch. SCheck() of acf attributes currently relies on the interface
|
|
** node to be physically present, because it needs to get at the
|
|
** current interface node to check for conflicting attributes etc. Also
|
|
** at least one acf attribute - implicit_handle, can define a handle
|
|
** type which is not yet defined in the idl (remember we are parsing
|
|
** the interface header), so we cant semnatically analyse anyway !!
|
|
**/
|
|
|
|
$$ = (node_base_attr *) $1;
|
|
|
|
|
|
if( $$ && ( ! ((node_base_attr *)$$)->IsAcfAttr() ) )
|
|
$$->SCheck();
|
|
|
|
}
|
|
;
|
|
|
|
InterfaceAttribute:
|
|
KWENDPOINT '(' EndPtSpecs ')'
|
|
{
|
|
$$ = (node_skl *) $3;
|
|
}
|
|
| KWUUID '('
|
|
{
|
|
fGuidContext = TRUE; /* set false by the lexer */
|
|
}
|
|
Guid ')'
|
|
{
|
|
$$ = $4;
|
|
}
|
|
| KWLOCAL
|
|
{
|
|
$$ = (node_skl *)GetPreAllocatedBitAttr( ATTR_LOCAL );
|
|
|
|
/**
|
|
** Set this interface to local
|
|
**/
|
|
|
|
pInterfaceInfoDict->SetInterfaceLocal();
|
|
|
|
}
|
|
| VersionSpec
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| KWDEFAULTPOINTER '(' PtrAttr ')'
|
|
{
|
|
$$ = $3;
|
|
/****
|
|
if( ImportLevel == 0 )
|
|
{
|
|
PtrDefaultAttr = ((node_base_attr *)$3)->GetAttrID();
|
|
}
|
|
pInterfaceInfoDict->SetInterfacePtrAttribute( PtrDefaultAttr );
|
|
****/
|
|
pInterfaceInfoDict->SetInterfacePtrAttribute(
|
|
((node_base_attr *)$3)->GetAttrID() );
|
|
}
|
|
|
|
| AcfInterfaceAttribute
|
|
{
|
|
if( !pCommand->IsSwitchDefined( SWITCH_APP_CONFIG ) )
|
|
{
|
|
ParseError( ACF_IN_IDL_NEEDS_APP_CONFIG,
|
|
((node_base_attr *)$1)->GetNodeNameString() );
|
|
}
|
|
$$ = $1;
|
|
}
|
|
| KWOBJECT
|
|
{
|
|
$$ = (node_skl *)GetPreAllocatedBitAttr( ATTR_OBJECT );
|
|
//Set a flag indicating this is an object-oriented interface.
|
|
fObject = TRUE;
|
|
}
|
|
;
|
|
|
|
/*******************
|
|
VersionSpec:
|
|
KWVERSION '(' Number ')'
|
|
{
|
|
YY_CATCH("VersionSpec: KWVERSION '(' Number ')'");
|
|
$$ = (node_skl *)new node_version( (unsigned long)$3.Val, 0 );
|
|
}
|
|
| KWVERSION '(' Number '.' Number ')'
|
|
{
|
|
YY_CATCH(" | KWVERSION '(' Number '.' Number ')'");
|
|
$$ = (node_skl *)new node_version( (unsigned long)$3.Val, (unsigned long)$5.Val );
|
|
}
|
|
;
|
|
|
|
********************/
|
|
|
|
VersionSpec:
|
|
KWVERSION '('
|
|
{
|
|
fVersionContext = TRUE;
|
|
/* fVersionContext is reset by lexer */
|
|
}
|
|
VERSIONTOKEN ')'
|
|
{
|
|
$$ = (node_skl *)new node_version( $4 );
|
|
}
|
|
;
|
|
|
|
Guid:
|
|
UUIDTOKEN
|
|
{
|
|
$$ = (node_skl *)new node_guid( $1 );
|
|
}
|
|
;
|
|
/*************************************************************************
|
|
Guid:
|
|
GuidRep
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| STRING
|
|
{
|
|
$$ = (node_skl *) new node_guid( $1 );
|
|
}
|
|
;
|
|
|
|
GuidRep:
|
|
GuidNumber '-' GuidNumber '-' GuidNumber '-' GuidNumber '-' GuidNumber
|
|
{
|
|
YY_CATCH("GuidRep: GuidNumber '-' GuidNumber '-' GuidNumber '-' GuidNumber '-' GuidNumber");
|
|
$$ = (node_skl *)new node_guid( $1, $3, $5, $7, $9 );
|
|
}
|
|
;
|
|
|
|
GuidNumber:
|
|
Number IDENTIFIER
|
|
{
|
|
YY_CATCH("GuidNumber: Number IDENTIFIER");
|
|
|
|
**
|
|
** This is an example where the parser takes up the slack left by the
|
|
** lexer. The lexer cannot recognize a hexadecimal number not preceded
|
|
** by a 0x. And the guid is not. So we write the production such that
|
|
** the parser will get 2 tokens for a hex number which is a nmeric
|
|
** followed by a letters, and we concatenate the token. The semantics
|
|
** will check whether the number is hex or not !
|
|
**
|
|
|
|
$$ = new char [ strlen( $1.pValStr ) + strlen( $2 ) + 1 ];
|
|
strcpy( $$, $1.pValStr );
|
|
strcat( $$, $2 );
|
|
|
|
}
|
|
| IDENTIFIER
|
|
{
|
|
YY_CATCH(" | IDENTIFIER");
|
|
$$ = $1;
|
|
}
|
|
| Number
|
|
{
|
|
YY_CATCH(" | Number");
|
|
$$ = new char [ strlen( $1.pValStr ) + 1 ];
|
|
strcpy( $$, $1.pValStr );
|
|
}
|
|
;
|
|
|
|
*********************************************************************/
|
|
EndPtSpecs:
|
|
EndPtSpec
|
|
{
|
|
YY_CATCH("EndPtSpecs: EndPtSpec");
|
|
$$ = new node_endpoint( $1 );
|
|
}
|
|
| EndPtSpecs ',' EndPtSpec
|
|
{
|
|
YY_CATCH(" | EndPtSpecs ',' EndPtSpec");
|
|
$$->SetEndPointString( $3 );
|
|
}
|
|
;
|
|
|
|
EndPtSpec:
|
|
STRING
|
|
{
|
|
YY_CATCH("EndPtSpec: STRING");
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
/*****************
|
|
Number:
|
|
NUMERICCONSTANT
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| HEXCONSTANT
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
******************/
|
|
|
|
InterfaceBody:
|
|
MultipleImport InterfaceComp
|
|
{
|
|
YY_CATCH("InterfaceBody: MultipleImport InterfaceComp");
|
|
|
|
/**
|
|
** This production is reduced when there is at least 1 imported
|
|
** file
|
|
**/
|
|
|
|
$$.pImports = $1;
|
|
$$.pNode = $2;
|
|
|
|
}
|
|
| InterfaceComp
|
|
{
|
|
YY_CATCH("InterfaceBody: InterfaceComp");
|
|
|
|
/**
|
|
** This production is reduced when there is NO import in the file
|
|
**/
|
|
|
|
$$.pImports = (type_node_list *)NULL;
|
|
$$.pNode = $1;
|
|
}
|
|
;
|
|
|
|
InterfaceComp:
|
|
InterfaceComponents
|
|
{
|
|
YY_CATCH("InterfaceComp: InterfaceComponents");
|
|
|
|
/**
|
|
** All the interface components have been reduced. Generate an
|
|
** interface node and attach all the components to it. If the lsit
|
|
** of members is empty, then just attach an error terminator node
|
|
** for uniformity.
|
|
**/
|
|
|
|
$$ = (node_skl *)new node_interface();
|
|
|
|
if( $1 && $1->GetCount() )
|
|
{
|
|
$$->SetMembers( $1 );
|
|
delete $1;
|
|
}
|
|
else
|
|
$$->SetOneMember( pErrorTypeNode );
|
|
|
|
|
|
/**
|
|
** Force a def edge from interface node to all components
|
|
** below
|
|
**/
|
|
|
|
$$->SetEdgeType( EDGE_DEF );
|
|
|
|
}
|
|
| /* Nothing */
|
|
{
|
|
$$ = (node_skl *)new node_interface();
|
|
$$->SetOneMember( pErrorTypeNode );
|
|
$$->SetEdgeType( EDGE_DEF );
|
|
}
|
|
;
|
|
|
|
MultipleImport:
|
|
MultipleImport Import
|
|
{
|
|
YY_CATCH("MultipleImport: MultipleImport Import");
|
|
if( $$ )
|
|
$$->Merge( $2 );
|
|
else
|
|
$$ = $2;
|
|
}
|
|
| Import
|
|
{
|
|
YY_CATCH("MultipleImport: Import");
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
Import:
|
|
KWIMPORT ImportList ';'
|
|
{
|
|
YY_CATCH("Import: KWIMPORT ImportList ';'");
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
ImportList:
|
|
ImportName
|
|
{
|
|
YY_CATCH("ImportList: ImportName");
|
|
$$ = $1;
|
|
}
|
|
| ImportList ',' ImportName
|
|
{
|
|
YY_CATCH(" | ImportList ',' ImportName");
|
|
if( $$ )
|
|
$$->Merge( $3 );
|
|
else
|
|
$$ = $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 "Interface" 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
|
|
{
|
|
YY_CATCH("ImportName: STRING");
|
|
|
|
/**
|
|
** we just obtained the import file name as a string. Immediately
|
|
** following, we must switch the input from the imported file.
|
|
**/
|
|
|
|
pImportCntrl->PushLexLevel();
|
|
|
|
if( pImportCntrl->SetNewInputFile( $1 ) != STATUS_OK )
|
|
{
|
|
$$ = (type_node_list *)NULL;
|
|
returnflag = 1;
|
|
return;
|
|
}
|
|
|
|
/**
|
|
** update the quick reference import level indicator
|
|
**/
|
|
|
|
ImportLevel++;
|
|
|
|
pInterfaceInfoDict->StartNewInterface();
|
|
|
|
}
|
|
PhantomInterface
|
|
{
|
|
|
|
/**
|
|
** 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 ) == (type_node_list *)0);
|
|
|
|
/**
|
|
** Restore the lexical level of the import controller.
|
|
**/
|
|
|
|
pImportCntrl->PopLexLevel();
|
|
pInterfaceInfoDict->EndNewInterface();
|
|
|
|
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;
|
|
}
|
|
;
|
|
|
|
PhantomInterface:
|
|
Interface
|
|
{
|
|
|
|
/**
|
|
** Interface is a list of file nodes
|
|
**/
|
|
$$ = $1;
|
|
|
|
}
|
|
| EOI
|
|
{
|
|
$$ = (type_node_list *)NULL;
|
|
}
|
|
;
|
|
|
|
InterfaceComponents:
|
|
InterfaceComponents InterfaceComponent
|
|
{
|
|
YY_CATCH("InterfaceComponents: InterfaceComponents InterfaceComponent");
|
|
if( $$)
|
|
$$->Merge( $2 );
|
|
else
|
|
$$ = $2;
|
|
}
|
|
| InterfaceComponent
|
|
{
|
|
YY_CATCH("InterfaceComponents: InterfaceComponent");
|
|
|
|
/**
|
|
** This is the first interface component. To ensure that predefined
|
|
** types get into the type graph so that the whole operation is
|
|
** transparent to the back end, we introduce them here.
|
|
**/
|
|
|
|
type_node_list * pInitList = (type_node_list *)NULL;
|
|
|
|
if( pHppPreDefinedTypes )
|
|
pInitList = pHppPreDefinedTypes;
|
|
|
|
if( (fTypeGraphInited == FALSE) && (ImportLevel == 0 ) )
|
|
{
|
|
|
|
/**
|
|
** define error_status_t
|
|
**/
|
|
|
|
SymKey SKey( "error_status_t", NAME_DEF );
|
|
|
|
if( !pInitList )
|
|
pInitList = new type_node_list;
|
|
|
|
pInitList->SetPeer( (node_skl *)pBaseSymTbl->SymSearch( SKey ) );
|
|
|
|
/**
|
|
** if mode is not osf, then we define wchar_t also
|
|
**/
|
|
|
|
if( pCommand->IsSwitchDefined( SWITCH_MS_EXT ) )
|
|
{
|
|
SKey.SetString( "wchar_t" );
|
|
pInitList->SetPeer(
|
|
(node_skl *)pBaseSymTbl->SymSearch( SKey ) );
|
|
}
|
|
|
|
/**
|
|
** we have inited the type graph.
|
|
**/
|
|
fTypeGraphInited = TRUE;
|
|
|
|
}
|
|
|
|
/**
|
|
** shove the type graph up.
|
|
**/
|
|
|
|
if( !( $$ = pInitList ) )
|
|
{
|
|
$$ = $1;
|
|
}
|
|
else
|
|
$$->Merge( $1 );
|
|
}
|
|
;
|
|
|
|
|
|
/* Note that we have to semantically verify that the declaration
|
|
which has operation attributes is indeed a function prototype. */
|
|
|
|
InterfaceComponent:
|
|
CPragmaSet
|
|
{
|
|
YY_CATCH("InterfaceComponent: CPragmaSet");
|
|
$$ = new type_node_list;
|
|
$$->SetPeer( $1 );
|
|
}
|
|
| MidlPragmaSet
|
|
{
|
|
YY_CATCH("InterfaceComponent: MidlPragmaSet");
|
|
$$ = new type_node_list;
|
|
$$->SetPeer( $1 );
|
|
}
|
|
| KWECHOSTRING STRING
|
|
{
|
|
YY_CATCH("InterfaceComponent: KWECHOSTRING STRING");
|
|
$$ = new type_node_list;
|
|
|
|
$2 = MakeNewStringWithProperQuoting( $2 );
|
|
|
|
$$->SetPeer( (node_skl *)new node_echo_string( $2 ) );
|
|
}
|
|
| KWCPPQUOTE '(' STRING ')'
|
|
{
|
|
ParseError( CPP_QUOTE_NOT_OSF, (char *)0 );
|
|
|
|
$$ = new type_node_list;
|
|
|
|
$3 = MakeNewStringWithProperQuoting( $3 );
|
|
|
|
$$->SetPeer( (node_skl *)new node_echo_string( $3 ) );
|
|
}
|
|
| SDEFINE
|
|
{
|
|
|
|
// #define FOO abracadabra
|
|
|
|
char *p = new char[ LEN_DEFINE +
|
|
1 +
|
|
(($1.pName ) ? strlen($1.pName) : 0 ) +
|
|
(($1.pParamList) ? strlen( $1.pParamList ) : 0 ) +
|
|
1 +
|
|
(($1.pSubsString) ? strlen($1.pSubsString) : 0 ) +
|
|
1
|
|
];
|
|
|
|
// emit #define
|
|
|
|
strcpy(p, DEFINE_STRING );
|
|
strcat(p, " " );
|
|
|
|
// emit the name
|
|
|
|
if( $1.pName )
|
|
strcat(p, $1.pName );
|
|
|
|
// emit paramlist
|
|
|
|
if( $1.pParamList )
|
|
strcat(p, $1.pParamList);
|
|
|
|
// emit a space
|
|
|
|
strcat(p, " ");
|
|
|
|
// emit the substituion string
|
|
|
|
if( $1.pSubsString )
|
|
strcat(p, $1.pSubsString);
|
|
|
|
$$ = new type_node_list;
|
|
$$->SetPeer( (node_skl *) new node_echo_string( p ));
|
|
|
|
// check for macro redefinition
|
|
|
|
SymKey SKey( $1.pName, NAME_SDEFINE );
|
|
|
|
if( pBaseSymTbl->SymSearch( SKey ) )
|
|
{
|
|
ParseError( MACRO_REDEFINITION, $1.pName );
|
|
pBaseSymTbl->SymDelete( SKey );
|
|
}
|
|
|
|
TEXT_SUB * pT = new TEXT_SUB( $1.pSubsString );
|
|
pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, (node_skl *)pT );
|
|
|
|
}
|
|
| PDEFINE
|
|
{
|
|
|
|
ParseError( PARAM_MACRO_UNIMPLEMENTED, $1.pName );
|
|
|
|
// #define FOO abracadabra
|
|
|
|
char *p = new char[ LEN_DEFINE +
|
|
1 +
|
|
(($1.pName ) ? strlen($1.pName) : 0 ) +
|
|
(($1.pParamList) ? strlen( $1.pParamList ) : 0 ) +
|
|
1 +
|
|
(($1.pSubsString) ? strlen($1.pSubsString) : 0 ) +
|
|
1
|
|
];
|
|
|
|
// emit #define
|
|
|
|
strcpy(p, DEFINE_STRING );
|
|
strcat(p, " " );
|
|
|
|
// emit the name
|
|
|
|
if( $1.pName )
|
|
strcat(p, $1.pName );
|
|
|
|
// emit paramlist
|
|
|
|
if( $1.pParamList )
|
|
strcat(p, $1.pParamList);
|
|
|
|
// emit a space
|
|
|
|
strcat(p, " ");
|
|
|
|
// emit the substituion string
|
|
|
|
if( $1.pSubsString )
|
|
strcat(p, $1.pSubsString);
|
|
|
|
$$ = new type_node_list;
|
|
$$->SetPeer( (node_skl *) new node_echo_string( p ));
|
|
|
|
// check for macro redefinition
|
|
|
|
SymKey SKey( $1.pName, NAME_SDEFINE );
|
|
|
|
if( pBaseSymTbl->SymSearch( SKey ) )
|
|
{
|
|
ParseError( MACRO_REDEFINITION, $1.pName );
|
|
pBaseSymTbl->SymDelete( SKey );
|
|
}
|
|
|
|
TEXT_SUB * pT = new TEXT_SUB( $1.pSubsString );
|
|
pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, (node_skl *)pT );
|
|
|
|
}
|
|
| OpOrSwTypeAttributes Declaration
|
|
{
|
|
YY_CATCH( "InterfaceComponent: OpOrSwTypeAttributes Declaration" );
|
|
|
|
/**
|
|
** The attributes here can be applied only to a proc or union,
|
|
** everything else is a syntax error.
|
|
**/
|
|
|
|
BOOL fIsSyntaxError = FALSE;
|
|
|
|
if( $1 )
|
|
{
|
|
node_skl * pNode;
|
|
|
|
$2->Init();
|
|
while( $2->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
NODE_T NT = pNode->NodeKind();
|
|
|
|
if( NT == NODE_DEF )
|
|
NT = pNode->GetBasicType()->NodeKind();
|
|
|
|
if( ( NT != NODE_UNION ) &&
|
|
( NT != NODE_PROC ) )
|
|
fIsSyntaxError = TRUE;
|
|
}
|
|
}
|
|
|
|
if( fIsSyntaxError )
|
|
ParseError( BENIGN_SYNTAX_ERROR, "expecting a procedure or a non-encapulated union declaration");
|
|
|
|
{
|
|
BOOL fInterfaceLocal = IS_CUR_INTERFACE_LOCAL();
|
|
|
|
SelectiveSemanticsAndEnGraph( &$$,
|
|
$1,
|
|
$2,
|
|
fInterfaceLocal,
|
|
fPragmaImportOn );
|
|
}
|
|
|
|
}
|
|
;
|
|
|
|
CPragmaSet:
|
|
KWCPRAGMA
|
|
{
|
|
YY_CATCH("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_STRING ("#pragma ")
|
|
|
|
char * p = new char [ strlen( $1 ) + strlen( PRAGMA_STRING ) + 1 ];
|
|
strcpy( p, PRAGMA_STRING );
|
|
strcat( p, $1 );
|
|
$$ = (node_skl *)new node_echo_string( p );
|
|
}
|
|
;
|
|
|
|
MidlPragmaSet:
|
|
KWMPRAGMAIMPORT '(' IDENTIFIER ')'
|
|
{
|
|
YY_CATCH("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 ')'
|
|
{
|
|
|
|
node_file * pFile;
|
|
SymKey SKey( $3, NAME_FILE );
|
|
|
|
if( pFile = (node_file *) pBaseSymTbl->SymSearch( SKey ) )
|
|
pFile->SetClientAuxillaryFileName( $5 );
|
|
$$ = new node_echo_string( "/* import clnt_aux */" );
|
|
|
|
}
|
|
| KWMPRAGMAIMPORTSRVRAUX '(' STRING ',' STRING ')'
|
|
{
|
|
|
|
node_file * pFile;
|
|
SymKey SKey( $3, NAME_FILE );
|
|
|
|
if( pFile = (node_file *) pBaseSymTbl->SymSearch( SKey ) )
|
|
pFile->SetServerAuxillaryFileName( $5 );
|
|
$$ = new node_echo_string( "/* import srvr_aux */" );
|
|
|
|
}
|
|
| KWMPRAGMAIUNKNOWN '(' STRING ')'
|
|
{
|
|
|
|
if( strcmp( $3, "inherit" ) == 0)
|
|
{
|
|
pCommand->SetInheritIUnknown( TRUE );
|
|
}
|
|
else if( strcmp( $3, "noinherit") == 0 )
|
|
{
|
|
pCommand->SetInheritIUnknown( FALSE );
|
|
}
|
|
else
|
|
{
|
|
ParseError( UNKNOWN_PRAGMA_OPTION, $3 );
|
|
}
|
|
$$ = new node_echo_string( "\n" );
|
|
}
|
|
;
|
|
|
|
Declaration:
|
|
KWTYPEDEF TypeAttributeList TypeDeclarationSpecifiers InitDeclaratorList ';'
|
|
{
|
|
YY_CATCH("Declaration: KWTYPEDEF TypeAttributeList DeclarationSpecifiers InitDeclaratorList ';' ");
|
|
|
|
/**
|
|
** 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.
|
|
**/
|
|
|
|
struct _decl_element * pDec;
|
|
char * pName;
|
|
node_skl * pType;
|
|
BOOL fInitListPresent = FALSE;
|
|
decl_list_mgr * pNonPtrList = new decl_list_mgr;
|
|
decl_list_mgr * pPtrList = new decl_list_mgr;
|
|
|
|
//
|
|
// make all pointer declarators come last. This is because the backend
|
|
// spits out declarations separately and generates aux routines with
|
|
// references to the non-pointer type before the pointer types. This
|
|
// requires us to modify the type graph to make the non-pointer
|
|
// declarations come first. What a hack !
|
|
//
|
|
|
|
while( pDec = $4->GetNextDecl() )
|
|
{
|
|
node_skl * pN = pDec->pNode;
|
|
|
|
if( pN &&
|
|
pN->GetBasicType() &&
|
|
pN->GetBasicType()->NodeKind() == NODE_POINTER )
|
|
pPtrList->AddElement( pDec );
|
|
else
|
|
pNonPtrList->AddElement( pDec );
|
|
}
|
|
|
|
//
|
|
// now merge the lists with the non-pointer stuff first.
|
|
//
|
|
|
|
delete $4;
|
|
$4 = new decl_list_mgr;
|
|
$4->Merge( pNonPtrList );
|
|
$4->Merge( pPtrList );
|
|
|
|
|
|
/**
|
|
** prepare for a list of typedefs to be made into interface
|
|
** components
|
|
**/
|
|
|
|
$$ = new type_node_list;
|
|
|
|
$4->Init();
|
|
while( pDec = $4->GetNextDecl() )
|
|
{
|
|
|
|
node_def * pDef;
|
|
node_skl * pDecNode = pDec->pNode;
|
|
|
|
if( pDec->pInit )
|
|
fInitListPresent = TRUE;
|
|
|
|
/**
|
|
** set the basic type of the declarator.
|
|
**/
|
|
|
|
pType = ($3.pNode->NodeKind() == NODE_FORWARD) ? $3.pNode->Clone()
|
|
: $3.pNode;
|
|
pDecNode->SetBasicType( pType );
|
|
|
|
/**
|
|
** The type declarator can come up as an ID node or as a
|
|
** procedure node. These nodes must be transformed into typedef
|
|
** nodes. In case of ID nodes, copy the node details and in
|
|
** case of procedure nodes, delete the proc fom the symbol table.
|
|
**/
|
|
|
|
pDef = new node_def;
|
|
|
|
if( pDecNode->NodeKind() == NODE_ID )
|
|
{
|
|
CopyNode( pDef, pDecNode );
|
|
pName = pDef->GetSymName();
|
|
}
|
|
else
|
|
{
|
|
if( pDecNode->NodeKind() == NODE_PROC )
|
|
{
|
|
|
|
pDef->SetBasicType( pDecNode );
|
|
pDef->SetSymName( pName = pDecNode->GetSymName());
|
|
|
|
SymKey SKey( pName, NAME_PROC );
|
|
pBaseSymTbl->SymDelete( SKey );
|
|
}
|
|
else
|
|
{
|
|
ParseError( BENIGN_SYNTAX_ERROR, "expecting a declarator");
|
|
pDef->SetSymName( pName = GenTempName());
|
|
pDef->SetBasicType( pErrorTypeNode );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// 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
|
|
//
|
|
|
|
CheckSpecialForwardTypedef( pDecNode, pType, $2);
|
|
|
|
|
|
/**
|
|
** The typedef node graph is all set up,
|
|
** apply attributes and enter into symbol table
|
|
**/
|
|
|
|
|
|
SymKey SKey( pName, NAME_DEF );
|
|
|
|
if(!pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, pDef ))
|
|
{
|
|
|
|
//
|
|
// allow benign redef of wchar_t.
|
|
//
|
|
|
|
if( strcmp( pName, "wchar_t" ) == 0 )
|
|
{
|
|
node_skl * pN = pDef->GetBasicType();
|
|
if( !((pN->NodeKind() == NODE_SHORT) &&
|
|
pN->FInSummary( ATTR_UNSIGNED) ) )
|
|
{
|
|
ParseError( WCHAR_T_ILLEGAL, (char *)0 );
|
|
$$->SetPeer( pErrorTypeNode );
|
|
}
|
|
else
|
|
{
|
|
$$->SetPeer( pDef );
|
|
}
|
|
}
|
|
else if( strcmp( pName, "error_status_t" ) == 0 )
|
|
{
|
|
node_skl * pN = pDef->GetBasicType();
|
|
if( !((pN->NodeKind() == NODE_LONG) &&
|
|
pN->FInSummary( ATTR_UNSIGNED) ) )
|
|
{
|
|
ParseError( ERROR_STATUS_T_ILLEGAL, (char *)0 );
|
|
$$->SetPeer( pErrorTypeNode );
|
|
}
|
|
else
|
|
{
|
|
$$->SetPeer( pDef );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ParseError( DUPLICATE_DEFINITION, pName );
|
|
$$->SetPeer( pErrorTypeNode );
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
CheckGlobalNamesClash( SKey );
|
|
$$->SetPeer( 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)
|
|
{
|
|
|
|
type_node_list * pAttrList = new type_node_list;
|
|
|
|
pAttrList->Clone( $2);
|
|
ApplyAttributes( pDef, pAttrList );
|
|
|
|
delete pAttrList;
|
|
|
|
}
|
|
|
|
/**
|
|
** similarly, apply the remnant attributes collected from
|
|
** declaration specifiers, to the declarator
|
|
**/
|
|
|
|
if( $3.pTNList )
|
|
{
|
|
type_node_list * pAttrList = new type_node_list;
|
|
|
|
pAttrList->Clone( $3.pTNList);
|
|
ApplyAttributes( pDef, pAttrList );
|
|
|
|
delete pAttrList;
|
|
}
|
|
}
|
|
|
|
if( fInitListPresent )
|
|
ParseError( BENIGN_SYNTAX_ERROR, (char *) 0 );
|
|
|
|
/**
|
|
** All type attributes have been applied, so delete the
|
|
** attribute lists
|
|
**/
|
|
|
|
if( $2 )
|
|
delete $2;
|
|
|
|
if( $3.pTNList )
|
|
delete $3.pTNList;
|
|
|
|
delete $4;
|
|
}
|
|
| DeclarationSpecifiers OptionalInitDeclaratorList ';'
|
|
{
|
|
/**
|
|
** All declarations other than typedefs are collected here.
|
|
** They are collected and passed up to the interface component
|
|
** production
|
|
**/
|
|
node_skl * pDecNode;
|
|
node_skl * pType;
|
|
|
|
$$ = new type_node_list;
|
|
|
|
/**
|
|
** It is possible that there are no declarators, only a type decla-
|
|
** ration. eg, the definition of a structure.
|
|
**/
|
|
|
|
if( $2 && $2->GetCount() )
|
|
{
|
|
struct _decl_element * pDec;
|
|
|
|
$2->Init();
|
|
|
|
/**
|
|
** for each declarator, set the basic type, set the attributes
|
|
** if any
|
|
**/
|
|
|
|
while( pDec = $2->GetNextDecl() )
|
|
{
|
|
|
|
pDecNode = pDec->pNode;
|
|
|
|
pType = ($1.pNode->NodeKind() == NODE_FORWARD ) ?
|
|
$1.pNode->Clone() :
|
|
$1.pNode;
|
|
|
|
pDecNode->SetBasicType( pType );
|
|
|
|
/**
|
|
** Apply the remnant attributes from the declaration specifier
|
|
** prodn to this declarator;
|
|
**/
|
|
|
|
if( $1.pTNList )
|
|
{
|
|
type_node_list * pAttrList = new type_node_list;
|
|
|
|
pAttrList->Clone( $1.pTNList);
|
|
ApplyAttributes( pDecNode, pAttrList );
|
|
|
|
delete pAttrList;
|
|
}
|
|
/**
|
|
** if the type node was an id node, see its initializer list
|
|
**/
|
|
|
|
if( pDecNode->NodeKind() == NODE_ID )
|
|
{
|
|
if( pDec->pInit )
|
|
((node_id *)pDecNode)->SetInitList( pDec->pInit );
|
|
}
|
|
|
|
/**
|
|
** shove the type node up.
|
|
**/
|
|
|
|
$$->SetPeer( pDecNode );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
/**
|
|
** 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.
|
|
**/
|
|
|
|
pDecNode = $1.pNode;
|
|
|
|
/****
|
|
if( pDecNode->NodeKind() == NODE_FORWARD )
|
|
{
|
|
****/
|
|
node_def * pDef = new node_def( GenTempName() );
|
|
pDef->SetBasicType( pDecNode );
|
|
$1.pNode = pDef;
|
|
/****
|
|
}
|
|
****/
|
|
/**
|
|
** Apply the remnant attributes from the declaration specifier
|
|
** prodn to this declarator;
|
|
**/
|
|
|
|
if( $1.pTNList )
|
|
{
|
|
type_node_list * pAttrList = new type_node_list;
|
|
|
|
pAttrList->Clone( $1.pTNList);
|
|
ApplyAttributes( $1.pNode, pAttrList );
|
|
|
|
delete pAttrList;
|
|
}
|
|
|
|
/**
|
|
** shove the type node up.
|
|
**/
|
|
|
|
$$->SetPeer( $1.pNode );
|
|
|
|
}
|
|
}
|
|
|
|
;
|
|
TypeDeclarationSpecifiers:
|
|
DeclarationSpecifiers
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| IDENTIFIER
|
|
{
|
|
SymKey SKey( $1, NAME_DEF );
|
|
$$.pNode = new node_forward( SKey );
|
|
$$.pTNList = (type_node_list *)0;
|
|
}
|
|
;
|
|
|
|
OptionalInitDeclaratorList:
|
|
InitDeclaratorList
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| /* Empty */
|
|
{
|
|
$$ = (decl_list_mgr *)NULL;
|
|
}
|
|
;
|
|
|
|
TypeAttributeList:
|
|
OneTypeAttrList
|
|
{
|
|
YY_CATCH("TypeAttributeList: OneTypeAttrList");
|
|
$$ = $1;
|
|
}
|
|
| /** Empty **/
|
|
{
|
|
YY_CATCH("TypeAttributeList: Empty");
|
|
$$ = (type_node_list *)NULL;
|
|
}
|
|
;
|
|
|
|
OneTypeAttrList:
|
|
OneTypeAttrList TypeAttrSet
|
|
{
|
|
YY_CATCH("OneTypeAttrList: OneTypeAttrList TypeAttrSet");
|
|
$$->Merge( $2);
|
|
}
|
|
| TypeAttrSet
|
|
{
|
|
YY_CATCH("OneTypeAttrList: TypeAttrSet");
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
TypeAttrSet:
|
|
'[' TypeAttributes ']'
|
|
{
|
|
YY_CATCH("TypeAttrSet: '[' TypeAttributes ']'" );
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
|
|
TypeAttributes:
|
|
TypeAttributes ',' TypeAttribute
|
|
{
|
|
YY_CATCH("TypeAttributes: TypeAttributes ',' TypeAttribute");
|
|
$$->SetPeer( $3);
|
|
}
|
|
| TypeAttribute
|
|
{
|
|
YY_CATCH("TypeAttributes: TypeAttribute");
|
|
$$ = new type_node_list( $1 );
|
|
}
|
|
;
|
|
|
|
TypeAttribute:
|
|
UnimplementedTypeAttribute
|
|
{
|
|
YY_CATCH("TypeAttribute: UnimplementedTypeAttribute");
|
|
$$ = (node_skl *) pErrorAttrNode;
|
|
}
|
|
| KWHANDLE
|
|
{
|
|
YY_CATCH("TypeAttribute: KW_HANDLE");
|
|
$$ = (node_skl *) new node_handle();
|
|
}
|
|
| UsageAttribute
|
|
{
|
|
YY_CATCH("TypeAttribute: UsageAttribute");
|
|
$$ = $1;
|
|
}
|
|
| PtrAttr
|
|
{
|
|
YY_CATCH("TypeAttribute: PtrAttr");
|
|
$$ = $1;
|
|
}
|
|
| UnionTypeSwitchAttr
|
|
{
|
|
YY_CATCH("TypeAttribute: UnionTypeSwitchAttr");
|
|
$$ = $1;
|
|
}
|
|
| KWTRANSMITAS '(' XmitType ')'
|
|
{
|
|
YY_CATCH("TypeAttribute: KWTRANSMITAS ( XmitType ) ");
|
|
$$ = (node_skl *) new node_transmit( $3 );
|
|
}
|
|
;
|
|
|
|
UnimplementedTypeAttribute:
|
|
KWALIGN '(' IntSize ')'
|
|
{
|
|
ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[align]");
|
|
}
|
|
| KWUNALIGNED
|
|
{
|
|
ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[unaligned]");
|
|
}
|
|
| UnimplementedV1Attributes
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
UnimplementedV1Attributes:
|
|
KWV1ARRAY
|
|
{
|
|
ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[v1_array]");
|
|
$$ = (node_skl *) pErrorAttrNode;
|
|
}
|
|
| KWV1STRING
|
|
{
|
|
ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[v1_string]");
|
|
$$ = (node_skl *) pErrorAttrNode;
|
|
}
|
|
| KWV1ENUM
|
|
{
|
|
ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[v1_enum]");
|
|
$$ = (node_skl *) pErrorAttrNode;
|
|
}
|
|
| KWV1STRUCT
|
|
{
|
|
ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[v1_struct]");
|
|
$$ = (node_skl *) pErrorAttrNode;
|
|
}
|
|
;
|
|
|
|
|
|
XmitType:
|
|
SimpleTypeSpec
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
SimpleTypeSpec:
|
|
BaseTypeSpec
|
|
{
|
|
GetBaseTypeNode( &($$), $1.TypeSign, $1.TypeSize, $1.BaseType);
|
|
}
|
|
| PredefinedTypeSpec
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| TYPENAME /* TYPENAME */
|
|
{
|
|
|
|
/**
|
|
** the symbol exists in the symbol table, thats why we got this
|
|
** token. Just return the graph
|
|
**/
|
|
|
|
SymKey SKey( $1, NAME_DEF );
|
|
if( ! ($$ = pBaseSymTbl->SymSearch( SKey ) ) )
|
|
{
|
|
ParseError( UNDEFINED_SYMBOL, $1 );
|
|
$$ = new node_error;
|
|
}
|
|
else
|
|
$$ = $$->Clone();
|
|
}
|
|
;
|
|
|
|
UsageAttribute:
|
|
KWSTRING
|
|
{
|
|
$$ = (node_skl *)new node_string();
|
|
}
|
|
| KWCONTEXTHANDLE
|
|
{
|
|
$$ = (node_skl *)new node_context();
|
|
}
|
|
| KWBSTRING
|
|
{
|
|
$$ = (node_skl *)new node_bstring();
|
|
}
|
|
;
|
|
|
|
PtrAttr:
|
|
KWREF
|
|
{
|
|
$$ = (node_skl *)GetPreAllocatedBitAttr( ATTR_REF );
|
|
}
|
|
| KWUNIQUE
|
|
{
|
|
$$ = (node_skl *)GetPreAllocatedBitAttr( ATTR_UNIQUE );
|
|
}
|
|
| KWPTR
|
|
{
|
|
$$ = (node_skl *)GetPreAllocatedBitAttr( ATTR_PTR );
|
|
}
|
|
| KWIGNORE
|
|
{
|
|
$$ = (node_skl *)GetPreAllocatedBitAttr( ATTR_IGNORE );
|
|
}
|
|
;
|
|
|
|
UnionTypeSwitchAttr:
|
|
KWSWITCHTYPE '(' SwitchTypeSpec ')'
|
|
{
|
|
$$ = (node_skl *)new node_switch_type( $3 );
|
|
}
|
|
;
|
|
|
|
|
|
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 */
|
|
{
|
|
SymKey SKey( $1, NAME_DEF );
|
|
|
|
if( ! ($$ = pBaseSymTbl->SymSearch( SKey ) ) )
|
|
{
|
|
ParseError( UNDEFINED_SYMBOL, $1 );
|
|
$$ = new node_error;
|
|
}
|
|
else
|
|
$$ = $$->Clone();
|
|
}
|
|
;
|
|
|
|
DeclarationSpecifiers:
|
|
ActualDeclarationSpecifiers
|
|
{
|
|
/**
|
|
** this production exists to provide a single place where the
|
|
** attributes collected can be applied. Note that it is possible to
|
|
** have attributes like const/volatile applied to base types. Since
|
|
** base types are preallocated, we cannot apply attibutes there.
|
|
** So we need to make copies of the base type and apply attributes
|
|
** to the clones.
|
|
**/
|
|
|
|
$$.pNode = $1.pNode;
|
|
$$.pTNList = $1.pTNList;
|
|
|
|
}
|
|
;
|
|
|
|
ActualDeclarationSpecifiers:
|
|
StorageClassSpecifier ActualDeclarationSpecifiers
|
|
{
|
|
YY_CATCH("ActualDeclarationSpecifiers: StorageClassSpecifier ActualDeclarationSpecifiers");
|
|
|
|
$$.pNode = $2.pNode;
|
|
$$.pTNList = new type_node_list( (node_skl *)
|
|
GetPreAllocatedBitAttr( $1 ) );
|
|
$$.pTNList->Merge( $2.pTNList );
|
|
|
|
}
|
|
| TypeQualifier ActualDeclarationSpecifiers
|
|
{
|
|
YY_CATCH("ActualDeclarationSpecifiers: TypeQualifier ActualDeclarationSpecifiers");
|
|
|
|
$$.pNode = $2.pNode;
|
|
$$.pTNList = new type_node_list( (node_skl *)
|
|
GetPreAllocatedBitAttr( $1 ) );
|
|
$$.pTNList->Merge( $2.pTNList );
|
|
|
|
|
|
}
|
|
| TypeSpecifier DeclarationSpecifiersPostFix
|
|
{
|
|
YY_CATCH("ActualDeclarationSpecifiers: TypeSpecifier DeclarationSpecifiersPostFix");
|
|
|
|
$$.pNode = $1;
|
|
$$.pTNList = $2;
|
|
|
|
}
|
|
| TypeSpecifier
|
|
{
|
|
YY_CATCH("ActualDeclarationSpecifiers: TypeSpecifier ");
|
|
$$.pNode = $1;
|
|
$$.pTNList = (type_node_list *)NULL;
|
|
}
|
|
;
|
|
|
|
DeclarationSpecifiersPostFix:
|
|
StorageClassSpecifier DeclarationSpecifiersPostFix
|
|
{
|
|
YY_CATCH("DeclarationSpecifiersPostFix: StorageClassSpecifier DeclarationSpecifiersPostFix ");
|
|
$$ = $2;
|
|
$$->SetPeer( (node_skl *)GetPreAllocatedBitAttr( $1 ) );
|
|
}
|
|
| TypeQualifier DeclarationSpecifiersPostFix
|
|
{
|
|
YY_CATCH("DeclarationSpecifiersPostFix: TypeQualifier DeclarationSpecifiersPostFix ");
|
|
$$ = $2;
|
|
$$ = $2;
|
|
$$->SetPeer( (node_skl *)GetPreAllocatedBitAttr( $1 ) );
|
|
}
|
|
| StorageClassSpecifier
|
|
{
|
|
YY_CATCH("DeclarationSpecifiersPostFix: StorageClassSpeicifier ");
|
|
$$ = new type_node_list( (node_skl *)
|
|
GetPreAllocatedBitAttr( $1 ));
|
|
}
|
|
| TypeQualifier
|
|
{
|
|
YY_CATCH("DeclarationSpecifiersPostFix: TypeQualifier ");
|
|
$$ = new type_node_list( (node_skl *)
|
|
GetPreAllocatedBitAttr( $1 ));
|
|
}
|
|
;
|
|
|
|
|
|
StorageClassSpecifier:
|
|
KWEXTERN
|
|
{
|
|
$$ = ATTR_EXTERN;
|
|
}
|
|
| KWSTATIC
|
|
{
|
|
$$ = ATTR_STATIC;
|
|
}
|
|
| KWAUTO
|
|
{
|
|
$$ = ATTR_AUTO;
|
|
}
|
|
| KWREGISTER
|
|
{
|
|
$$ = ATTR_REGISTER;
|
|
}
|
|
/*******************************************
|
|
| PCODENATIVE
|
|
{
|
|
$$ = ATTR_PCODE_NATIVE;
|
|
}
|
|
| PCODECSCONST
|
|
{
|
|
$$ = ATTR_PCODE_CSCONST;
|
|
}
|
|
| PCODESYS
|
|
{
|
|
$$ = ATTR_PCODE_SYS;
|
|
}
|
|
| PCODENSYS
|
|
{
|
|
$$ = ATTR_PCODE_NSYS;
|
|
}
|
|
| PCODEUOP
|
|
{
|
|
$$ = ATTR_PCODE_UOP;
|
|
}
|
|
| PCODENUOP
|
|
{
|
|
$$ = ATTR_PCODE_NUOP;
|
|
}
|
|
| PCODETLBX
|
|
{
|
|
$$ = ATTR_PCODE_TLBX;
|
|
}
|
|
*********************************************/
|
|
;
|
|
|
|
/* KWSTRING Is "string" a keyword in MS C? if not than
|
|
it should be permanently omitted from the
|
|
above list.
|
|
*/
|
|
|
|
TypeSpecifier:
|
|
BaseTypeSpec
|
|
{
|
|
GetBaseTypeNode( &($$), $1.TypeSign, $1.TypeSize, $1.BaseType );
|
|
}
|
|
| PredefinedTypeSpec
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| TaggedSpec
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| BitSetType
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| EnumerationType
|
|
{
|
|
$$ = $1;
|
|
}
|
|
/**************************
|
|
| NV1PipeType
|
|
{
|
|
$$ = $1;
|
|
}
|
|
***************************/
|
|
| 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. Always use the clone of the typedef, because it
|
|
** may have attributes which can be applied to it later.
|
|
**/
|
|
|
|
SymKey SKey( $1, NAME_DEF );
|
|
if( ! ($$ = pBaseSymTbl->SymSearch( SKey ) ) )
|
|
{
|
|
ParseError( UNDEFINED_SYMBOL, $1 );
|
|
$$ = new node_error;
|
|
}
|
|
else
|
|
$$ = $$->Clone();
|
|
}
|
|
;
|
|
|
|
BitSetType:
|
|
IntSize KWBITSET '{' IdentifierList '}'
|
|
{
|
|
ParseError( UNIMPLEMENTED_FEATURE, "bitset" );
|
|
$$ = pErrorTypeNode;
|
|
}
|
|
;
|
|
|
|
IdentifierList:
|
|
IDENTIFIER
|
|
| IdentifierList ',' IDENTIFIER
|
|
;
|
|
|
|
EnumerationType:
|
|
/**
|
|
IntSize EnumSpecifier
|
|
**/
|
|
EnumSpecifier
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
EnumSpecifier:
|
|
KWENUM OptionalEnumTag '{' EnumeratorList '}'
|
|
{
|
|
/**
|
|
** We just obtained a complete enum definition. Check for
|
|
** duplicate definition.
|
|
**/
|
|
|
|
BOOL fFound = FALSE;
|
|
BOOL fEnumIsForwardDecl = FALSE;
|
|
node_skl * pNode;
|
|
SymKey SKey( $2, NAME_ENUM );
|
|
|
|
pNode = SearchTag( $2, NAME_ENUM );
|
|
|
|
if( fFound = (pNode != (node_skl *) NULL) )
|
|
fEnumIsForwardDecl = ( pNode->NodeKind() == NODE_FORWARD );
|
|
|
|
if( fFound && !fEnumIsForwardDecl )
|
|
{
|
|
ParseError( DUPLICATE_DEFINITION, $2 );
|
|
$$ = (node_skl *)pErrorTypeNode;
|
|
}
|
|
else
|
|
{
|
|
/**
|
|
** This is a new definition of enum. Enter into symbol table
|
|
** Also, pick up the label graph and attach it.
|
|
**/
|
|
|
|
$$ = new node_enum( $2 );
|
|
$$->SetMembers( $4.pEnList );
|
|
|
|
/**
|
|
** 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, $$ );
|
|
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 );
|
|
}
|
|
| 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 = ! ( $$ = pBaseSymTbl->SymSearch( SKey ) );
|
|
|
|
if( fNotFound || ($$->NodeKind() == NODE_FORWARD ) )
|
|
{
|
|
$$ = new node_forward( SKey );
|
|
}
|
|
if( fNotFound )
|
|
{
|
|
pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, $$ );
|
|
CheckGlobalNamesClash( SKey );
|
|
}
|
|
}
|
|
;
|
|
|
|
EnumeratorList:
|
|
Enumerator
|
|
{
|
|
|
|
/**
|
|
** We just reduced an enum label. Note that this IS the first
|
|
** label in the enum specification. All other labels will go to the
|
|
** EnumeratorList : EnumeratorList , Enumerator production.
|
|
|
|
** The enum labels go into the global name space. Search for
|
|
** duplicates on the base symbol table.
|
|
**/
|
|
|
|
expr_node * pExpr = (expr_node *)0;
|
|
node_label * pLabel;
|
|
SymKey SKey( $1.pName, NAME_LABEL );
|
|
|
|
if( pBaseSymTbl->SymSearch( SKey ) )
|
|
{
|
|
ParseError( DUPLICATE_DEFINITION, $1.pName );
|
|
pLabel = (node_label *)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.
|
|
**/
|
|
|
|
if( !(pExpr = $1.pExpr ) )
|
|
pExpr = new expr_constant( 0L );
|
|
|
|
pLabel = new node_label( $1.pName, pExpr );
|
|
|
|
/**
|
|
** Insert into the global table
|
|
**/
|
|
|
|
pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, (node_skl *)pLabel);
|
|
CheckGlobalNamesClash( SKey );
|
|
|
|
}
|
|
|
|
$$.pEnList = new type_node_list;
|
|
|
|
if( pLabel )
|
|
$$.pEnList->SetPeer( pLabel );
|
|
$$.pExpr = pExpr;
|
|
$$.fSparse = $1.fSparse;
|
|
|
|
}
|
|
| EnumeratorList ',' Enumerator
|
|
{
|
|
|
|
/**
|
|
** This is a new label we reduced. Check for duplicates in the
|
|
** global symbol table
|
|
**/
|
|
|
|
expr_node * pExpr = (expr_node *)0;
|
|
node_label * pLabel;
|
|
SymKey SKey( $3.pName, NAME_LABEL );
|
|
|
|
if( pBaseSymTbl->SymSearch( SKey ) )
|
|
{
|
|
ParseError( DUPLICATE_DEFINITION, $3.pName );
|
|
pLabel = (node_label *)NULL;
|
|
}
|
|
else
|
|
{
|
|
|
|
/**
|
|
** if there was an expression associated with the label, use that
|
|
** else use the already collected expression, and add 1 to it.
|
|
**/
|
|
|
|
if( !(pExpr = $3.pExpr ) )
|
|
{
|
|
pExpr = new expr_op_binary(OP_PLUS,
|
|
$$.pExpr,
|
|
(expr_node*)new expr_constant(1L));
|
|
}
|
|
|
|
pLabel = new node_label( $3.pName, pExpr );
|
|
|
|
/**
|
|
** Insert into the global table
|
|
**/
|
|
|
|
pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, (node_skl *)pLabel);
|
|
CheckGlobalNamesClash( SKey );
|
|
|
|
}
|
|
|
|
if( pLabel )
|
|
$$.pEnList->SetPeer( pLabel );
|
|
|
|
$$.pExpr = pExpr;
|
|
$$.fSparse = $1.fSparse + $3.fSparse;
|
|
}
|
|
| EnumeratorList ','
|
|
{
|
|
|
|
/**
|
|
** This is just a ',' at the end of the enum production. This does
|
|
** not mean a new enum label, thus we just return what we got
|
|
**/
|
|
|
|
$$ = $1;
|
|
|
|
}
|
|
;
|
|
|
|
Enumerator:
|
|
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
|
|
**/
|
|
|
|
$$.pName = $1;
|
|
$$.pExpr = (expr_node *)NULL;
|
|
$$.fSparse = 0;
|
|
|
|
}
|
|
| IDENTIFIER '=' ConstantExpr
|
|
{
|
|
|
|
/**
|
|
** This enum label has an expression associated with it. Use it.
|
|
** sparse enums are illegal in osf mode
|
|
**/
|
|
|
|
$$.pName = $1;
|
|
$$.pExpr = $3;
|
|
$$.fSparse = 1;
|
|
|
|
}
|
|
;
|
|
|
|
/******************************
|
|
NV1PipeType:
|
|
KWPIPE Declaration
|
|
{
|
|
ParseError( UNIMPLEMENTED_FEATURE, "pipe" );
|
|
$$ = (node_skl *)pErrorTypeNode;
|
|
}
|
|
;
|
|
******************************/
|
|
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
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| KWINT IntModifiers
|
|
{
|
|
$$ = $2;
|
|
$$.BaseType = TYPE_UNDEF;
|
|
$$.TypeSize = SIZE_UNDEF;
|
|
}
|
|
| KWINT
|
|
{
|
|
$$.BaseType = TYPE_UNDEF;
|
|
$$.TypeSign = SIGN_UNDEF;
|
|
$$.TypeSize = SIZE_UNDEF;
|
|
}
|
|
;
|
|
|
|
IntModifiers:
|
|
IntModifier
|
|
{
|
|
$$.TypeSign = $1.TypeSign;
|
|
$$.TypeSize = $1.TypeSize;
|
|
$$.BaseType = TYPE_UNDEF;
|
|
}
|
|
| IntModifiers IntModifier
|
|
{
|
|
SignSpecAnalysis( &($$), $2.TypeSign );
|
|
SizeSpecAnalysis( &($$), $2.TypeSize );
|
|
}
|
|
;
|
|
|
|
IntModifier:
|
|
SignSpecs
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| IntSize
|
|
{
|
|
$$.TypeSize = $1;
|
|
$$.BaseType = TYPE_UNDEF;
|
|
$$.TypeSign = SIGN_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;
|
|
}
|
|
| KWPIPE
|
|
{
|
|
ParseError( UNIMPLEMENTED_FEATURE, "pipe" );
|
|
$$.BaseType = TYPE_PIPE;
|
|
$$.TypeSign = SIGN_UNDEF;
|
|
$$.TypeSize = SIZE_UNDEF;
|
|
}
|
|
;
|
|
IntSize:
|
|
KWHYPER
|
|
{
|
|
// ParseError( UNIMPLEMENTED_TYPE, "hyper");
|
|
$$ = SIZE_HYPER;
|
|
}
|
|
| KWLONG
|
|
{
|
|
$$ = SIZE_LONG;
|
|
}
|
|
| KWSHORT
|
|
{
|
|
$$ = SIZE_SHORT;
|
|
}
|
|
| KWSMALL
|
|
{
|
|
$$ = SIZE_SMALL;
|
|
}
|
|
;
|
|
|
|
/* START TAGGED SPEC */
|
|
|
|
TaggedSpec:
|
|
TaggedStructSpec
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| TaggedUnionSpec
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
/* START TAGGED STRUCT */
|
|
|
|
TaggedStructSpec:
|
|
KWSTRUCT OptionalTag '{'
|
|
{
|
|
/**
|
|
** We just obtained a starter for the struct definition. Push the
|
|
** symbol table, so that we obtain a symbol table for the fields of
|
|
** the struct.
|
|
**/
|
|
pSymTblMgr->PushSymLevel( &pCurSymTbl );
|
|
|
|
}
|
|
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 );
|
|
|
|
/**
|
|
** 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. We therefore call a special routine which
|
|
** checks the tag for name clash.
|
|
**/
|
|
|
|
pStruct = (node_struct *)SearchTag( $2, NAME_TAG );
|
|
|
|
if( fFound = ( pStruct != (node_struct *)NULL ) )
|
|
fStructIsForwardDecl = (pStruct->NodeKind() == NODE_FORWARD);
|
|
|
|
if( fFound && !fStructIsForwardDecl )
|
|
{
|
|
ParseError( DUPLICATE_DEFINITION, $2 );
|
|
delete $5;
|
|
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 );
|
|
|
|
pBaseSymTbl->SymInsert( SKey, pSymLowerScope, pStruct );
|
|
CheckGlobalNamesClash( SKey );
|
|
}
|
|
$$ = pStruct;
|
|
|
|
}
|
|
| 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 );
|
|
BOOL fNotFound = !($$ = pBaseSymTbl->SymSearch( SKey ) );
|
|
|
|
if( fNotFound || ( $$->NodeKind() == NODE_FORWARD ) )
|
|
$$ = new node_forward( SKey );
|
|
if( fNotFound )
|
|
{
|
|
pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, $$ );
|
|
CheckGlobalNamesClash( SKey );
|
|
}
|
|
}
|
|
;
|
|
|
|
OptionalTag:
|
|
Tag
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| /* Empty */
|
|
{
|
|
/******
|
|
ParseError( TEMP_TAG_USED, (char *)0 );
|
|
******/
|
|
$$ = GenCompName();
|
|
}
|
|
;
|
|
|
|
OptionalEnumTag:
|
|
Tag
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| /* Empty */
|
|
{
|
|
$$ = GenCompName();
|
|
}
|
|
;
|
|
|
|
Tag:
|
|
IDENTIFIER
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| TYPENAME
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
StructDeclarationList:
|
|
StructDeclarationList MemberDeclaration
|
|
{
|
|
YY_CATCH("StructDeclarationList: StructDeclarationList MemberDeclaration");
|
|
$$->Merge( $2 );
|
|
}
|
|
| MemberDeclaration
|
|
{
|
|
YY_CATCH("StructDeclarationList: MemberDeclaration");
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
|
|
MemberDeclaration:
|
|
FieldAttributeList DeclarationSpecifiers MemberDeclaratorList ';'
|
|
{
|
|
|
|
YY_CATCH( "MemberDeclaration: FieldAttributeList 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
|
|
**/
|
|
|
|
struct _decl_element * pDec;
|
|
node_skl * pDecNode;
|
|
node_skl * pType;
|
|
|
|
$$ = new type_node_list;
|
|
|
|
while( pDec = $3->GetNextDecl() )
|
|
{
|
|
|
|
char * pName;
|
|
node_field * pField;
|
|
type_node_list * pAttrList;
|
|
|
|
/**
|
|
** if the field was a bit field, we need to set up some additional
|
|
** info.
|
|
**/
|
|
|
|
if( pDec->fBitField )
|
|
{
|
|
pField = new node_bitfield( pDec->fBitField );
|
|
}
|
|
else
|
|
pField = new node_field();
|
|
|
|
|
|
pType = ($2.pNode->NodeKind() == NODE_FORWARD) ?
|
|
$2.pNode->Clone() :
|
|
$2.pNode;
|
|
|
|
if( pDecNode = pDec->pNode)
|
|
pDecNode->SetBasicType( pType );
|
|
else
|
|
pDecNode = pType;
|
|
|
|
/**
|
|
** if the declarator was a simple identifier, the just copy
|
|
** the details into the field node( also setting the basic type
|
|
** in the process ), else set the basic type as the declarator
|
|
**
|
|
**/
|
|
|
|
if( pDecNode->NodeKind() == NODE_ID )
|
|
CopyNode( pField, pDecNode );
|
|
else
|
|
pField->SetBasicType( pDecNode );
|
|
|
|
if( !( pName = pField->GetSymName() ) )
|
|
{
|
|
pName = GenTempName();
|
|
pField->SetSymName( pName );
|
|
}
|
|
|
|
SymKey SKey( pName, NAME_MEMBER );
|
|
|
|
if( !pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pField ) )
|
|
{
|
|
ParseError( DUPLICATE_DEFINITION, pName );
|
|
}
|
|
else
|
|
CheckGlobalNamesClash( SKey );
|
|
|
|
/**
|
|
** Apply the field attributes and set the field as part of the
|
|
** list of fields of the struct/union
|
|
**/
|
|
|
|
if( $1 )
|
|
{
|
|
pAttrList = new type_node_list;
|
|
pAttrList->Clone( $1 );
|
|
|
|
ApplyAttributes( pField, pAttrList );
|
|
delete pAttrList;
|
|
}
|
|
|
|
/**
|
|
** apply any attributes from the declaration specifiers prodn
|
|
**/
|
|
|
|
if( $2.pTNList )
|
|
{
|
|
pAttrList = new type_node_list;
|
|
pAttrList->Clone( $2.pTNList );
|
|
|
|
ApplyAttributes( pField, pAttrList );
|
|
delete pAttrList;
|
|
}
|
|
|
|
/**
|
|
** shove the type graph up
|
|
**/
|
|
|
|
$$->SetPeer( pField );
|
|
|
|
}
|
|
|
|
/**
|
|
** we are done with the attributes
|
|
**/
|
|
|
|
if( $1 )
|
|
delete $1;
|
|
|
|
if( $2.pTNList )
|
|
delete $2.pTNList;
|
|
|
|
delete $3;
|
|
}
|
|
;
|
|
|
|
FieldAttributeList:
|
|
OneFieldAttrList
|
|
{
|
|
YY_CATCH("FieldAttributeList: OneFieldAttrList");
|
|
$$ = $1;
|
|
}
|
|
| /** Empty **/
|
|
{
|
|
YY_CATCH("| Empty ");
|
|
$$ = (type_node_list *)NULL;
|
|
}
|
|
;
|
|
|
|
OneFieldAttrList:
|
|
OneFieldAttrList FieldAttrSet
|
|
{
|
|
YY_CATCH( "OneFieldAttrList: OneFieldAttrList FieldAttrSet");
|
|
$$->Merge( $2 );
|
|
}
|
|
| FieldAttrSet
|
|
{
|
|
YY_CATCH( "OneFieldAttrList: FieldAttrSet");
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
FieldAttrSet:
|
|
'[' FieldAttributes ']'
|
|
{
|
|
YY_CATCH("FieldAttrSet: [ FieldAttributes ]");
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
FieldAttributes:
|
|
FieldAttributes ',' FieldAttribute
|
|
{
|
|
YY_CATCH("FieldAttributes: FieldAttributes ',' FieldAttribute");
|
|
$$->Merge( $3 );
|
|
}
|
|
| FieldAttribute
|
|
{
|
|
YY_CATCH("FieldAttributes: FieldAttribute");
|
|
|
|
$$ = $1;
|
|
|
|
}
|
|
;
|
|
|
|
FieldAttribute:
|
|
KWFIRSTIS '(' AttrVarList ')'
|
|
{
|
|
$$ = GenerateFieldAttribute( NODE_FIRST, $3 );
|
|
}
|
|
| KWLASTIS '(' AttrVarList ')'
|
|
{
|
|
$$ = GenerateFieldAttribute( NODE_LAST, $3 );
|
|
}
|
|
| KWLENGTHIS '(' AttrVarList ')'
|
|
{
|
|
$$ = GenerateFieldAttribute( NODE_LENGTH, $3 );
|
|
}
|
|
| KWMINIS '(' AttrVarList ')'
|
|
{
|
|
$$ = GenerateFieldAttribute( NODE_MIN, $3 );
|
|
}
|
|
| KWMAXIS '(' AttrVarList ')'
|
|
{
|
|
$$ = GenerateFieldAttribute( NODE_MAX, $3 );
|
|
}
|
|
| KWSIZEIS '(' AttrVarList ')'
|
|
{
|
|
$$ = GenerateFieldAttribute( NODE_SIZE, $3 );
|
|
}
|
|
| KWIIDIS '(' AttrVarList ')'
|
|
{
|
|
$$ = GenerateFieldAttribute( NODE_IID, $3);
|
|
}
|
|
| OtherFieldAttribute
|
|
{
|
|
$$ = new type_node_list( $1 );
|
|
}
|
|
;
|
|
|
|
OtherFieldAttribute:
|
|
UsageAttribute
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| PtrAttr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| UnionInstanceSwitchAttr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| UnionTypeSwitchAttr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| UnimplementedV1Attributes
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
AttrVarList:
|
|
AttrVarList ',' AttrVar
|
|
{
|
|
$$->SetPeer( $3 );
|
|
}
|
|
| AttrVar
|
|
{
|
|
$$ = new expr_list;
|
|
$$->SetPeer( $1 );
|
|
}
|
|
;
|
|
|
|
AttrVar:
|
|
|
|
VariableExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
;
|
|
|
|
|
|
MemberDeclaratorList:
|
|
MemberDeclarator
|
|
{
|
|
|
|
/**
|
|
** Create a new declarator list and add this declarator to it
|
|
**/
|
|
|
|
struct _decl_element * pDeclarator;
|
|
|
|
$$ = new decl_list_mgr;
|
|
$$->AddElement( &pDeclarator );
|
|
pDeclarator->pNode = $1.pNode;
|
|
pDeclarator->fBitField = $1.fBitField;
|
|
|
|
}
|
|
| MemberDeclaratorList ',' MemberDeclarator
|
|
{
|
|
struct _decl_element * pDeclarator;
|
|
|
|
$$->AddElement( &pDeclarator );
|
|
|
|
pDeclarator->pNode = $3.pNode;
|
|
pDeclarator->fBitField = $3.fBitField;
|
|
}
|
|
;
|
|
|
|
MemberDeclarator:
|
|
Declarator
|
|
{
|
|
YY_CATCH( "MemberDeclarator: Declarator");
|
|
|
|
/**
|
|
** a declarator without bit fields specified.
|
|
**/
|
|
|
|
$$.pNode = $1;
|
|
$$.fBitField = 0;
|
|
|
|
}
|
|
| ':' ConstantExpr
|
|
{
|
|
YY_CATCH("| ':' ConstantExpr");
|
|
|
|
/**
|
|
** This is a declarator specified without the type
|
|
**/
|
|
|
|
$$.pNode = (node_skl *)NULL;
|
|
$$.fBitField = (short)$2->Evaluate();
|
|
|
|
}
|
|
| Declarator ':' ConstantExpr
|
|
{
|
|
YY_CATCH("| Declarator ':' ConstantExpr");
|
|
|
|
/**
|
|
** The complete bit field specification.
|
|
**/
|
|
$$.pNode = $1;
|
|
$$.fBitField = (short) $3->Evaluate();
|
|
|
|
}
|
|
| /** Empty **/
|
|
{
|
|
$$.pNode = (node_skl *)NULL;
|
|
$$.fBitField = 0;
|
|
}
|
|
;
|
|
|
|
|
|
|
|
/* START UNION */
|
|
TaggedUnionSpec:
|
|
KWUNION OptionalTag '{'
|
|
{
|
|
|
|
/**
|
|
** We just obtained a starter for the union definition. Push the
|
|
** symbol table to the next level for fields of the union
|
|
**/
|
|
pSymTblMgr->PushSymLevel( &pCurSymTbl );
|
|
|
|
}
|
|
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 );
|
|
|
|
/**
|
|
** 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 *)SearchTag( $2, NAME_UNION );
|
|
|
|
if( fFound = (pUnion != (node_union *) NULL ) )
|
|
fUnionIsForwardDecl = ( pUnion->NodeKind() == NODE_FORWARD );
|
|
|
|
if( fFound && !fUnionIsForwardDecl )
|
|
{
|
|
ParseError( DUPLICATE_DEFINITION, $2 );
|
|
pUnion = (node_union *)pErrorTypeNode;
|
|
delete $5;
|
|
}
|
|
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;
|
|
|
|
}
|
|
| 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 );
|
|
BOOL fNotFound = !( $$ = pBaseSymTbl->SymSearch( SKey ) );
|
|
|
|
if( fNotFound || ($$->NodeKind() == NODE_FORWARD ) )
|
|
{
|
|
$$ = new node_forward( SKey );
|
|
}
|
|
if( fNotFound )
|
|
{
|
|
pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, $$ );
|
|
CheckGlobalNamesClash( SKey );
|
|
}
|
|
}
|
|
|
|
| KWUNION OptionalTag NidlUnionSwitch '{'
|
|
{
|
|
pSymTblMgr->PushSymLevel( &pCurSymTbl );
|
|
}
|
|
|
|
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_union * pUnion;
|
|
SymTable * pSymLowerScope = pCurSymTbl;
|
|
SymKey SKey;
|
|
|
|
/**
|
|
** restore the symbol table level
|
|
**/
|
|
|
|
pSymTblMgr->PopSymLevel( &pCurSymTbl );
|
|
|
|
pUnion = new node_en_union( GenCompName() );
|
|
pUnion->SetMembers( $6 );
|
|
SKey.SetKind( NAME_UNION );
|
|
SKey.SetString( pUnion->GetSymName() );
|
|
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 );
|
|
|
|
type_node_list * pTNList = new type_node_list;
|
|
|
|
node_field * pSwitchField = (node_field *) $3.pNode;
|
|
node_field * pUnionField = new node_field;
|
|
|
|
if( IsTempName( $3.pName ) )
|
|
$3.pName = "tagged_union";
|
|
pUnionField->SetSymName( $3.pName );
|
|
pUnionField->SetBasicType( pUnion );
|
|
|
|
pTNList->SetPeer( pSwitchField );
|
|
pTNList->SetPeer( pUnionField );
|
|
|
|
//
|
|
// apply the switch_is attribute to the union field.
|
|
//
|
|
|
|
type_node_list * pAttrList = new type_node_list;
|
|
|
|
pAttrList->SetPeer( (node_skl *) $3.pSwitch );
|
|
ApplyAttributes( pUnionField, pAttrList );
|
|
delete pAttrList;
|
|
|
|
//
|
|
// 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;
|
|
|
|
pStruct = (node_struct *)SearchTag( $2, NAME_UNION );
|
|
|
|
if( fFound = ( pStruct != (node_struct *)NULL ) )
|
|
fStructIsForwardDecl = (pStruct->NodeKind() == NODE_FORWARD);
|
|
|
|
if( fFound && !fStructIsForwardDecl )
|
|
{
|
|
ParseError( DUPLICATE_DEFINITION, $2 );
|
|
delete $6;
|
|
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( pTNList );
|
|
|
|
pBaseSymTbl->SymInsert( SKey, pSymLowerScope, pStruct );
|
|
CheckGlobalNamesClash( SKey );
|
|
|
|
/***********************
|
|
//
|
|
// enter the struct as a struct too, just in case there is
|
|
// an attempt to redefine.
|
|
//
|
|
|
|
SKey.SetKind( NAME_TAG );
|
|
|
|
pBaseSymTbl->SymInsert( SKey, pSymLowerScope, pStruct );
|
|
CheckGlobalNamesClash( SKey );
|
|
***********************/
|
|
}
|
|
|
|
delete pTNList;
|
|
$$ = pStruct;
|
|
|
|
}
|
|
;
|
|
|
|
UnionBody:
|
|
UnionCases DefaultCase
|
|
{
|
|
YY_CATCH("UnionBody: UnionCases DefaultCase");
|
|
($$ = $1)->Merge( $2 );
|
|
}
|
|
| UnionCases
|
|
{
|
|
YY_CATCH("UnionBody: UnionCases");
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
|
|
UnionCases:
|
|
UnionCases UnionCase
|
|
{
|
|
YY_CATCH("UnionCases: UnionCases UnionCase");
|
|
$$->Merge( $2 );
|
|
}
|
|
| UnionCase
|
|
{
|
|
YY_CATCH("UnionCases: UnionCase");
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
UnionCase:
|
|
UnionCaseLabel MemberDeclaration
|
|
{
|
|
YY_CATCH("UnionCase: UnionCaseLabel MemberDeclaration");
|
|
|
|
/**
|
|
** for each of the fields, attach the case label attribute.
|
|
**/
|
|
|
|
node_skl * pNode;
|
|
|
|
($$ = $2)->Init();
|
|
|
|
while( $$->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
pNode->SetAttribute( (node_base_attr *) $1 );
|
|
}
|
|
}
|
|
| UnionCaseLabel ';'
|
|
{
|
|
YY_CATCH("UnionCase: 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->SetBasicType( (node_skl *)pErrorTypeNode );
|
|
pField->node_skl::SetAttribute( (node_base_attr *) $1 );
|
|
|
|
/**
|
|
** Generate a list of union fields and add this to the list of
|
|
** union fields
|
|
**/
|
|
|
|
$$ = new type_node_list;
|
|
$$->SetPeer( (node_skl *)pField );
|
|
|
|
}
|
|
| MemberDeclaration
|
|
{
|
|
YY_CATCH("UnionCase: MemberDeclaration");
|
|
/**
|
|
** A member declaration without a case label
|
|
**/
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
UnionCaseLabel:
|
|
'[' KWCASE '(' ConstantExprs ')' ']'
|
|
{
|
|
YY_CATCH("UnionCaseLabel: '[' KWCASE '(' ConstantExprs ')' ']'");
|
|
$$ = (node_skl *)new node_case( $4 );
|
|
}
|
|
;
|
|
|
|
DefaultCase:
|
|
'[' KWDEFAULT ']' MemberDeclaration
|
|
{
|
|
YY_CATCH("DefaultCase: '[' KWDEFAULT ']' MemberDeclaration");
|
|
node_skl * pNode;
|
|
|
|
($$ = $4)->Init();
|
|
|
|
while( $$->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
pNode->SetAttribute( GetPreAllocatedBitAttr( ATTR_DEFAULT ) );
|
|
}
|
|
}
|
|
| '[' KWDEFAULT ']' ';'
|
|
{
|
|
YY_CATCH("DefaultCase: '[' 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() );
|
|
|
|
$$ = new type_node_list;
|
|
|
|
pField->node_skl::SetAttribute( GetPreAllocatedBitAttr( ATTR_DEFAULT ) );
|
|
pField->SetBasicType( (node_skl *)pErrorTypeNode );
|
|
$$->SetPeer( pField );
|
|
|
|
}
|
|
;
|
|
|
|
|
|
NidlUnionSwitch:
|
|
SwitchSpec
|
|
{
|
|
YY_CATCH( "NidlUnionSwitch : SwitchSpec" );
|
|
$$ = $1;
|
|
$$.pName = GenCompName();
|
|
}
|
|
| SwitchSpec UnionName
|
|
{
|
|
YY_CATCH( "NidlUnionSwitch : SwithSpec UnionName" );
|
|
$$ = $1;
|
|
$$.pName = $2;
|
|
}
|
|
;
|
|
|
|
NidlUnionBody:
|
|
NidlUnionCases
|
|
{
|
|
YY_CATCH( "NidlUnionBody : NidlUnionCases" );
|
|
$$ = $1.pCaseList;
|
|
if( $1.DefCount > 1 )
|
|
ParseError( TWO_DEFAULT_CASES, (char *)0 );
|
|
}
|
|
;
|
|
|
|
NidlUnionCases:
|
|
NidlUnionCases NidlUnionCase
|
|
{
|
|
YY_CATCH( "NidlUnionCases : NidlUnionCases NidlUnionCase" );
|
|
$$.DefCount += $2.DefCount;
|
|
$$.pCaseList->Merge( $2.pCaseList );
|
|
}
|
|
| NidlUnionCase
|
|
{
|
|
YY_CATCH( "NidlUnionCases : NidlUnionCase" );
|
|
$$.pCaseList = $1.pCaseList;
|
|
$$.DefCount = $1.DefCount;
|
|
}
|
|
;
|
|
|
|
NidlUnionCase:
|
|
NidlUnionCaseLabelList NidlMemberDeclaration
|
|
{
|
|
YY_CATCH( "NidlUnionCase : NidlUnionCaseLabelList NidlMemberDeclaration" );
|
|
node_skl * pNode;
|
|
|
|
//
|
|
// set the case and default attributes.
|
|
//
|
|
|
|
$$.pCaseList = $2;
|
|
|
|
if( $1.pExprList && $1.pExprList->GetCount() )
|
|
{
|
|
$$.pCaseList->Init();
|
|
while( $$.pCaseList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
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 ) )
|
|
{
|
|
$$.pCaseList->Init();
|
|
while( $$.pCaseList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
pNode->SetAttribute( $1.pDefault );
|
|
}
|
|
}
|
|
}
|
|
;
|
|
|
|
NidlMemberDeclaration:
|
|
MemberDeclaration
|
|
{
|
|
YY_CATCH( "NidlMemberDeclaration : MemberDeclaration" );
|
|
$$ = $1;
|
|
}
|
|
| ';'
|
|
{
|
|
YY_CATCH( "NidlMemberDeclaration : ;" );
|
|
|
|
node_field * pNode = new node_field( GenTempName() );
|
|
pNode->SetBasicType( (node_skl *) pErrorTypeNode );
|
|
$$ = new type_node_list;
|
|
|
|
$$->SetPeer( (node_skl *)pNode );
|
|
}
|
|
;
|
|
|
|
NidlUnionCaseLabelList:
|
|
NidlUnionCaseLabelList NidlUnionCaseLabel
|
|
{
|
|
YY_CATCH( "NidlUnionCaseLabelList : NidlUnionCaseLabelList NidlUnionCaseLabel" );
|
|
if( $2.pExpr )
|
|
$$.pExprList->SetPeer( $2.pExpr );
|
|
|
|
if( !($$.pDefault) )
|
|
$$.pDefault = $2.pDefault;
|
|
if( $2.pDefault )
|
|
$$.DefCount++;
|
|
}
|
|
| NidlUnionCaseLabel
|
|
{
|
|
YY_CATCH( "NidlUnionCaseLabelList : NidlUnionCaseLabel" );
|
|
$$.pExprList = new expr_list;
|
|
|
|
if( $1.pExpr )
|
|
$$.pExprList->SetPeer( $1.pExpr );
|
|
if( $$.pDefault = $1.pDefault)
|
|
{
|
|
$$.DefCount = 1;
|
|
}
|
|
}
|
|
;
|
|
|
|
NidlUnionCaseLabel:
|
|
KWCASE ConstantExpr ':'
|
|
{
|
|
YY_CATCH( "NidlUnionCaseLabel : KWCASE ConstantExpr :" );
|
|
$$.pExpr = $2;
|
|
$$.pDefault = 0;
|
|
}
|
|
| KWDEFAULT ':'
|
|
{
|
|
YY_CATCH( "NidlUnionCaseLabel : KWDEFAULT" );
|
|
$$.pExpr = 0;
|
|
$$.pDefault = GetPreAllocatedBitAttr( ATTR_DEFAULT );
|
|
}
|
|
;
|
|
|
|
SwitchSpec:
|
|
KWSWITCH '(' SwitchTypeSpec IDENTIFIER ')'
|
|
{
|
|
YY_CATCH( "SwitchSpec : KWSWITCH ( SwitchTypeSpec ) IDENTIFIER" );
|
|
$$.pSwitch = (node_base_attr *)
|
|
new node_switch_is( new expr_variable( $4 ));
|
|
$$.pNode = new node_field();
|
|
$$.pNode->SetSymName( $4 );
|
|
$$.pNode->SetBasicType( $3 );
|
|
}
|
|
;
|
|
|
|
UnionName:
|
|
IDENTIFIER
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
/**
|
|
** NIDL UNION END
|
|
**/
|
|
|
|
ConstantExprs:
|
|
ConstantExprs ',' ConstantExpr
|
|
{
|
|
$$->SetPeer( $3 );
|
|
}
|
|
| ConstantExpr
|
|
{
|
|
$$ = new expr_list;
|
|
$$->SetPeer( $1 );
|
|
}
|
|
;
|
|
|
|
|
|
UnionInstanceSwitchAttr:
|
|
KWSWITCHIS '(' AttrVar ')'
|
|
{
|
|
$$ = (node_skl *)new node_switch_is( $3 );
|
|
}
|
|
;
|
|
/* END UNION */
|
|
|
|
/* Semantically only KWCONST is valid, and only as part of an
|
|
Initializer list */
|
|
|
|
TypeQualifier:
|
|
KWVOLATILE
|
|
{
|
|
// ParseError( TYPE_QUALIFIER, (char *)NULL );
|
|
$$ = ATTR_VOLATILE;
|
|
}
|
|
| KWCONST
|
|
{
|
|
$$ = ATTR_CONST;
|
|
}
|
|
| KW_C_INLINE
|
|
{
|
|
$$ = ATTR_C_INLINE;
|
|
}
|
|
;
|
|
|
|
InitDeclaratorList:
|
|
InitDeclarator
|
|
{
|
|
YY_CATCH( "InitDeclaratorList : InitDeclarator" );
|
|
|
|
/**
|
|
** pass on the declarator just collected
|
|
**/
|
|
|
|
struct _decl_element * pDeclarator;
|
|
|
|
$$ = new decl_list_mgr;
|
|
$$->AddElement( &pDeclarator );
|
|
pDeclarator->pNode = $1.pNode;
|
|
pDeclarator->pInit = $1.pInit;
|
|
pDeclarator->fBitField = $1.fBitField;
|
|
|
|
}
|
|
| InitDeclaratorList ',' InitDeclarator
|
|
{
|
|
YY_CATCH( "InitDeclaratorList : InitDeclaratorList , InitDeclarator" );
|
|
|
|
|
|
struct _decl_element * pDeclarator;
|
|
|
|
$$->AddElement( &pDeclarator );
|
|
pDeclarator->pNode = $3.pNode;
|
|
pDeclarator->pInit = $3.pInit;
|
|
pDeclarator->fBitField = $3.fBitField;
|
|
|
|
}
|
|
;
|
|
|
|
InitDeclarator:
|
|
Declarator
|
|
{
|
|
YY_CATCH( "InitDeclarator : Declarator");
|
|
$$.pNode = $1;
|
|
$$.pInit = (expr_init_list *)NULL;
|
|
}
|
|
| Declarator '=' Initializer
|
|
{
|
|
YY_CATCH( "InitDeclarator : Declarator = Initializer");
|
|
$$.pNode = $1;
|
|
$$.pInit = $3;
|
|
}
|
|
;
|
|
|
|
OptionalDeclarator:
|
|
Declarator
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| /* Empty */
|
|
{
|
|
$$ = (node_skl *)NULL;
|
|
}
|
|
;
|
|
|
|
Declarator:
|
|
Pointer
|
|
{
|
|
YY_CATCH( "Declarator : Pointer");
|
|
$$ = $1.pNode;
|
|
}
|
|
| Declarator2
|
|
{
|
|
YY_CATCH( "Declarator : Declarator2");
|
|
$$ = $1;
|
|
}
|
|
| Pointer Declarator2
|
|
{
|
|
YY_CATCH( "Declarator : Pointer Declarator2");
|
|
|
|
/**
|
|
** Declarator2 is a pointer to some type, so the basic type of
|
|
** the declarator is pointer. The pointer production can also
|
|
** result in only attributes being set. If so, they are applied to
|
|
** the declarator
|
|
**/
|
|
|
|
$$ = $2;
|
|
$$->SetBasicType( $1.pNode );
|
|
ApplyAttributes($$,$1.pTNList );
|
|
delete $1.pTNList;
|
|
$1.pTNList = (type_node_list *)NULL;
|
|
}
|
|
;
|
|
|
|
Pointer:
|
|
Modifier
|
|
{
|
|
YY_CATCH( "Pointer : Modifier ");
|
|
$$.pNode = (node_skl *)0;
|
|
$$.pTNList = new type_node_list( (node_skl *)$1 );
|
|
}
|
|
| Modifier Pointer2
|
|
{
|
|
|
|
YY_CATCH( "Pointer : Modifier Pointer2 ");
|
|
$$.pTNList = new type_node_list( (node_skl *)$1 );
|
|
$$.pNode = $2.pNode;
|
|
node_skl *pPtr = $2.pNode;
|
|
node_skl *pPtrSave = pPtr;
|
|
|
|
while( pPtr )
|
|
{
|
|
pPtrSave = pPtr;
|
|
pPtr = pPtr->GetChild();
|
|
}
|
|
|
|
if( pPtrSave )
|
|
{
|
|
ApplyAttributes( pPtrSave, $$.pTNList );
|
|
delete $$.pTNList;
|
|
$$.pTNList = $2.pTNList;
|
|
}
|
|
else
|
|
$$.pTNList->Merge( $2.pTNList );
|
|
|
|
}
|
|
| '*' OptionalTypeQualifiers
|
|
{
|
|
YY_CATCH( "Pointer : * OptionalTypeQualifiers ");
|
|
$$.pNode = new node_pointer;
|
|
$$.pTNList = (type_node_list *)0;
|
|
if( $2 )
|
|
{
|
|
ApplyAttributes( $$.pNode, $2 );
|
|
delete $2;
|
|
}
|
|
}
|
|
| '*' OptionalTypeQualifiers Pointer2
|
|
{
|
|
YY_CATCH( "Pointer : * OptionalTypeQualifiers Pointer2 ");
|
|
$$.pNode = new node_pointer;
|
|
|
|
if( $2 )
|
|
{
|
|
ApplyAttributes( $$.pNode, $2 );
|
|
delete $2;
|
|
}
|
|
|
|
if( $3.pTNListQ )
|
|
{
|
|
ApplyAttributes( $$.pNode, $3.pTNListQ );
|
|
delete $3.pTNListQ;
|
|
$3.pTNListQ = (type_node_list *)0;
|
|
}
|
|
|
|
if( $3.pNode )
|
|
{
|
|
$3.pNode->SetBasicType( $$.pNode );
|
|
$$.pNode = $3.pNode;
|
|
}
|
|
|
|
$$.pTNList = $3.pTNList;
|
|
|
|
}
|
|
;
|
|
|
|
Pointer2:
|
|
Modifier
|
|
{
|
|
YY_CATCH( "Pointer2 : Modifier ");
|
|
$$.pNode = (node_skl *)0;
|
|
$$.pTNList = new type_node_list( (node_skl *)$1 );
|
|
$$.pTNListQ = (type_node_list *)0;
|
|
}
|
|
| Modifier Pointer2
|
|
{
|
|
YY_CATCH( "Pointer2 : Modifier Pointer2");
|
|
|
|
$$.pTNList = new type_node_list( (node_skl *)$1 );
|
|
$$.pNode = $2.pNode;
|
|
node_skl *pPtr = $2.pNode;
|
|
node_skl *pPtrSave = pPtr;
|
|
|
|
while( pPtr )
|
|
{
|
|
pPtrSave = pPtr;
|
|
pPtr = pPtr->GetChild();
|
|
}
|
|
|
|
if( pPtrSave ) /* ie. indirectly, if $$.pNode */
|
|
{
|
|
ApplyAttributes( pPtrSave, $$.pTNList );
|
|
delete $$.pTNList;
|
|
$$.pTNList = $2.pTNList;
|
|
}
|
|
else
|
|
{
|
|
$$.pTNList->Merge( $2.pTNList );
|
|
}
|
|
|
|
$$.pTNListQ = $2.pTNListQ; /** necessary ?? **/
|
|
|
|
}
|
|
| '*' OptionalTypeQualifiers
|
|
{
|
|
YY_CATCH( "Pointer2 : * OptionalTypeQualifiers ");
|
|
$$.pNode = new node_pointer;
|
|
$$.pTNList = (type_node_list *)0;
|
|
if( $2 )
|
|
{
|
|
ApplyAttributes( $$.pNode, $2 );
|
|
delete $2;
|
|
}
|
|
$$.pTNListQ = (type_node_list *)0;
|
|
}
|
|
|
|
| '*' OptionalTypeQualifiers Pointer2
|
|
{
|
|
YY_CATCH( "Pointer2 : * OptionalTypeQualifiers Pointer2");
|
|
|
|
node_pointer *pPtr = new node_pointer;
|
|
if( $2 )
|
|
{
|
|
ApplyAttributes( (node_skl *)pPtr, $2 );
|
|
delete $2;
|
|
}
|
|
|
|
$$.pNode = pPtr;
|
|
if( $3.pNode )
|
|
{
|
|
$3.pNode->SetBasicType( pPtr );
|
|
$$.pNode = $3.pNode;
|
|
}
|
|
|
|
$$.pTNList = $3.pTNList;
|
|
$$.pTNListQ = $3.pTNListQ;
|
|
|
|
}
|
|
/**
|
|
| TypeQualifier2
|
|
{
|
|
}
|
|
| TypeQualifier2 Pointer2
|
|
{
|
|
}
|
|
**/
|
|
;
|
|
|
|
OptionalTypeQualifiers:
|
|
TypeQualifier2
|
|
{
|
|
$$ = new type_node_list( (node_skl *)new battr( $1 ));
|
|
}
|
|
| /* Empty */
|
|
{
|
|
$$ = (type_node_list *)0;
|
|
}
|
|
;
|
|
Modifier:
|
|
ModifierAllowed
|
|
{
|
|
|
|
/**
|
|
** some of the type modifiers are not allowed in osf compatibility
|
|
** mode. In that case, the error will automatically be reported.
|
|
** create an attribute summary and pass it on.
|
|
**/
|
|
|
|
// ParseError( TYPE_MODIFIER, (char *)NULL );
|
|
$$ = (node_skl *) GetPreAllocatedBitAttr( $1 );
|
|
|
|
}
|
|
;
|
|
|
|
ModifierAllowed:
|
|
MSCFAR
|
|
{
|
|
$$ = ATTR_FAR;
|
|
}
|
|
| MSCFAR16
|
|
{
|
|
$$ = ATTR_FAR16;
|
|
}
|
|
| MSCUNALIGNED
|
|
{
|
|
$$ = ATTR_MSCUNALIGNED;
|
|
}
|
|
| MSCNEAR
|
|
{
|
|
$$ = ATTR_NEAR;
|
|
}
|
|
| MSCHUGE
|
|
{
|
|
$$ = ATTR_HUGE;
|
|
}
|
|
| MSCPASCAL
|
|
{
|
|
$$ = ATTR_PASCAL;
|
|
}
|
|
| MSCFORTRAN
|
|
{
|
|
$$ = ATTR_FORTRAN;
|
|
}
|
|
| MSCCDECL
|
|
{
|
|
$$ = ATTR_CDECL;
|
|
}
|
|
| MSCSTDCALL
|
|
{
|
|
$$ = ATTR_STDCALL;
|
|
}
|
|
| MSCLOADDS /* potentially interesting */
|
|
{
|
|
$$ = ATTR_LOADDS;
|
|
}
|
|
| MSCSAVEREGS
|
|
{
|
|
$$ = ATTR_SAVEREGS;
|
|
}
|
|
| MSCFASTCALL
|
|
{
|
|
$$ = ATTR_FASTCALL;
|
|
}
|
|
| MSCSEGMENT
|
|
{
|
|
$$ = ATTR_SEGMENT;
|
|
}
|
|
| MSCINTERRUPT
|
|
{
|
|
$$ = ATTR_INTERRUPT;
|
|
}
|
|
| MSCSELF
|
|
{
|
|
$$ = ATTR_SELF;
|
|
}
|
|
| MSCEXPORT
|
|
{
|
|
$$ = ATTR_EXPORT;
|
|
}
|
|
| base
|
|
{
|
|
$$ = ATTR_NONE;
|
|
}
|
|
| segname
|
|
{
|
|
$$ = ATTR_NONE;
|
|
}
|
|
| asmemit
|
|
{
|
|
$$ = ATTR_NONE;
|
|
}
|
|
;
|
|
|
|
|
|
base:
|
|
MSCBASE '(' segbase ')'
|
|
;
|
|
|
|
segbase:
|
|
MSCSEGNAME
|
|
| MSCSEGMENT
|
|
| MSCSELF
|
|
| KWVOID
|
|
;
|
|
|
|
asmemit:
|
|
MSCEMIT NUMERICCONSTANT
|
|
{
|
|
}
|
|
;
|
|
|
|
|
|
|
|
segname:
|
|
MSCSEGNAME '(' STRING ')'
|
|
;
|
|
|
|
TypeQualifier2:
|
|
KWVOLATILE
|
|
{
|
|
$$ = ATTR_VOLATILE;
|
|
}
|
|
| KWCONST
|
|
{
|
|
$$ = ATTR_CONST;
|
|
}
|
|
| KW_C_INLINE
|
|
{
|
|
$$ = ATTR_C_INLINE;
|
|
}
|
|
;
|
|
|
|
Declarator2:
|
|
'(' Declarator ')'
|
|
{
|
|
YY_CATCH( "Declarator : (Declarator)");
|
|
$$ = $2;
|
|
}
|
|
| Declarator2
|
|
{
|
|
|
|
YY_CATCH( "Declarator : Declarator 2");
|
|
/**
|
|
** we just entered the context of a procedure. Hide the current
|
|
** symbol table and generate a new symbol table for the params.
|
|
** Then when the whole production is reduced, attach the new symbol
|
|
** table to the procs symbol table.
|
|
**/
|
|
|
|
pSymTblMgr->PushSymLevel( &pCurSymTbl );
|
|
|
|
}
|
|
ParamsDecl2 OptionalConst
|
|
{
|
|
node_skl * pProc = new node_proc( ImportLevel,
|
|
IS_CUR_INTERFACE_LOCAL() );
|
|
char * pName;
|
|
SymTable * pProcSymTbl = pCurSymTbl;
|
|
|
|
/**
|
|
** 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).
|
|
**/
|
|
|
|
/**
|
|
** Set members of the procedure node as the parameter nodes.
|
|
**/
|
|
|
|
pProc->SetMembers( $3 );
|
|
|
|
/**
|
|
** 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.
|
|
**/
|
|
|
|
if( ($1->NodeKind() == NODE_ID ) &&
|
|
($1->GetBasicType() == (node_skl *)NULL ) )
|
|
{
|
|
CopyNode( pProc, $1 );
|
|
pName = pProc->GetSymName();
|
|
}
|
|
else
|
|
{
|
|
pName = pProc->SetSymName( GenTempName() );
|
|
$1->SetBasicType( pProc );
|
|
pProc = $1;
|
|
}
|
|
|
|
/**
|
|
** 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( ImportLevel == 0 )
|
|
{
|
|
SymKey SKey( pName , NAME_PROC );
|
|
|
|
if( !pBaseSymTbl->SymInsert( SKey, pProcSymTbl, pProc ) )
|
|
{
|
|
ParseError( DUPLICATE_DEFINITION, pName );
|
|
}
|
|
else
|
|
CheckGlobalNamesClash( SKey );
|
|
}
|
|
|
|
/**
|
|
** finally, for the hpp const support, if the optional const is true
|
|
** apply the const attribute on the proc
|
|
**/
|
|
|
|
if( $4 )
|
|
{
|
|
ApplyAttributes( pProc, $4 );
|
|
}
|
|
|
|
/**
|
|
** pass this declarator back now, oooof!
|
|
**/
|
|
|
|
$$ = pProc;
|
|
|
|
}
|
|
| '(' ')' 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 );
|
|
|
|
$$ = new node_proc( ImportLevel, IS_CUR_INTERFACE_LOCAL() );
|
|
$$->SetSymName( pName );
|
|
|
|
/**
|
|
** enter this into the symbol table , only if we are in the base idl
|
|
** file, not an imported file.
|
|
**/
|
|
|
|
if( ImportLevel == 0 )
|
|
pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, $$ );
|
|
|
|
/**
|
|
** finally, for the hpp const support, if the optional const is true
|
|
** apply the const attribute on the proc
|
|
**/
|
|
|
|
if( $3 )
|
|
{
|
|
ApplyAttributes( $$, $3 );
|
|
}
|
|
}
|
|
| Declarator2 ArrayDecl
|
|
{
|
|
|
|
/**
|
|
** The basic type of the declarator is the array
|
|
**/
|
|
$$ = $1;
|
|
$$->SetBasicType( $2 );
|
|
|
|
}
|
|
| ArrayDecl
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| IDENTIFIER
|
|
{
|
|
$$ = new node_id;
|
|
$$->SetSymName( $1 );
|
|
}
|
|
| 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.
|
|
**/
|
|
$$ = new node_id;
|
|
$$->SetSymName( $1 );
|
|
}
|
|
;
|
|
|
|
|
|
/* 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. We translate
|
|
** this to a param of type void, so that the backend can emit it
|
|
** that way.
|
|
**/
|
|
|
|
node_skl * pNode;
|
|
node_param * pParam = new node_param;
|
|
char * pName;
|
|
|
|
$$ = new type_node_list;
|
|
GetBaseTypeNode( &pNode, SIGN_UNDEF, SIZE_UNDEF, TYPE_VOID );
|
|
pParam->SetSymName( pName = "void" );
|
|
pParam->SetBasicType( pNode );
|
|
|
|
/**
|
|
** Insert the param into the current symbol table. No need to
|
|
** check duplicate, it wont be.
|
|
**/
|
|
|
|
SymKey SKey( pName, NAME_MEMBER );
|
|
pCurSymTbl->SymInsert( SKey, (SymTable *)NULL, pNode );
|
|
CheckGlobalNamesClash( SKey );
|
|
|
|
/**
|
|
** Now return it as a list of parameters
|
|
**/
|
|
|
|
$$->SetPeer( pParam );
|
|
|
|
}
|
|
| '(' ParameterTypeList ')'
|
|
{
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
ParameterTypeList:
|
|
ParameterList
|
|
{
|
|
YY_CATCH( "ParameterTypeList : Parameter List " );
|
|
$$ = $1;
|
|
}
|
|
| ParameterList ',' DOTDOT '.'
|
|
{
|
|
YY_CATCH( "ParameterTypeList : ParamaterList 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.
|
|
**/
|
|
|
|
node_param * pParam = new node_param;
|
|
|
|
pParam->SetSymName( "..." );
|
|
pParam->SetBasicType( pErrorTypeNode );
|
|
|
|
$$ = $1;
|
|
$$->SetPeer( pParam );
|
|
|
|
}
|
|
;
|
|
|
|
ParameterList:
|
|
ParameterDeclaration
|
|
{
|
|
YY_CATCH( "Parameter List : ParameterDeclaration" );
|
|
$$ = new type_node_list;
|
|
$$->SetPeer( $1 );
|
|
}
|
|
| ParameterList ',' ParameterDeclaration
|
|
{
|
|
YY_CATCH( "ParamtereList : ParameterList , ParameterDeclaration" );
|
|
$$->SetPeer( $3 );
|
|
}
|
|
;
|
|
|
|
ParameterDeclaration:
|
|
ParamAttributes ParameterTypeDeclaration
|
|
{
|
|
YY_CATCH( "ParameterDeclaration : ParameterTypeDeclaration" );
|
|
/**
|
|
** We just obtained a complete parameter declaration, along with
|
|
** param attributes. Apply attributes to the params. Some attributes
|
|
** are just plain bits, in the attribute summary.
|
|
**/
|
|
|
|
$$ = $2;
|
|
|
|
/**
|
|
** Apply all the attributes which have attribute nodes associated
|
|
** with them
|
|
**/
|
|
|
|
ApplyAttributes( $$, $1 );
|
|
delete $1;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
ParamAttributes:
|
|
OneParamAttrList
|
|
{
|
|
YY_CATCH( "ParamAttributes : OneParamAttrlist" );
|
|
$$ = $1;
|
|
}
|
|
| /** Empty **/
|
|
{
|
|
YY_CATCH( "| Empty" );
|
|
$$ = (type_node_list *)NULL;
|
|
}
|
|
;
|
|
|
|
OneParamAttrList:
|
|
OneParamAttrList ParamAttrSet
|
|
{
|
|
YY_CATCH( "OneParameterList : OneParamList ParamAttrSet" );
|
|
$$->Merge( $2 );
|
|
}
|
|
| ParamAttrSet
|
|
{
|
|
YY_CATCH( "| ParamAttrSet" );
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
ParamAttrSet:
|
|
'[' ParamAttributeList ']'
|
|
{
|
|
YY_CATCH( "paramAttrSet : [ ParamAttributeList ] " );
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
ParamAttributeList:
|
|
ParamAttributeList ',' ParamAttribute
|
|
{
|
|
YY_CATCH( "ParamAttributeList : ParamAttributeList , ParamAttribute" );
|
|
$$->Merge( $3);
|
|
}
|
|
| ParamAttribute
|
|
{
|
|
YY_CATCH( "| ParamAttribute" );
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
ParamAttribute:
|
|
DirectionalAttribute
|
|
{
|
|
YY_CATCH( "ParamAttribute : DirectionalAttribute" );
|
|
$$ = $1;
|
|
}
|
|
| FieldAttribute
|
|
{
|
|
YY_CATCH( "| FieldAttribute" );
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
|
|
DirectionalAttribute:
|
|
KWIN OptShape
|
|
{
|
|
YY_CATCH( "DirectionalAttribute : KWIN OptShape" );
|
|
$$ = new type_node_list((node_skl *)GetPreAllocatedBitAttr( ATTR_IN ));
|
|
if( $2 )
|
|
$$->SetPeer( (node_skl *)new battr( $2 ) );
|
|
}
|
|
| KWOUT OptShape
|
|
{
|
|
YY_CATCH( "| KWOUT OptShape" );
|
|
$$ = new type_node_list((node_skl *)GetPreAllocatedBitAttr( ATTR_OUT) );
|
|
if( $2 )
|
|
$$->SetPeer( (node_skl *)new battr( $2 ) );
|
|
}
|
|
;
|
|
|
|
|
|
ParameterTypeDeclaration:
|
|
DeclarationSpecifiers Declarator
|
|
{
|
|
YY_CATCH( "ParameterTypeDeclaration : DeclarationSpecifiers Declarator" );
|
|
node_param * pParam = new node_param;
|
|
char * pName;
|
|
|
|
/**
|
|
** Apply the declaration specifier to the declarator as a basic type
|
|
**/
|
|
|
|
$2->SetBasicType( $1.pNode );
|
|
|
|
/**
|
|
** 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( $2->NodeKind() == NODE_ID )
|
|
CopyNode( pParam, $2 );
|
|
else
|
|
pParam->SetBasicType( $2 );
|
|
|
|
/**
|
|
** prepare for symbol table entry.
|
|
**/
|
|
|
|
if( !(pName = pParam->GetSymName()) )
|
|
{
|
|
// ParseError( ABSTRACT_DECL, (char *)NULL );
|
|
pParam->SetSymName(pName = GenTempName() );
|
|
}
|
|
|
|
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 );
|
|
|
|
/**
|
|
** apply any attributes specified to the declaration specifiers
|
|
**/
|
|
|
|
if( $1.pTNList )
|
|
{
|
|
ApplyAttributes( pParam, $1.pTNList );
|
|
delete $1.pTNList;
|
|
}
|
|
|
|
/**
|
|
** return the node back
|
|
**/
|
|
|
|
$$ = pParam;
|
|
|
|
}
|
|
| DeclarationSpecifiers
|
|
{
|
|
YY_CATCH( "| 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 name the parameter
|
|
** void.( This is needed by the backend )
|
|
**/
|
|
|
|
node_param * pParam = new node_param;
|
|
char * pName = ($1.pNode->NodeKind() == NODE_VOID ) ?
|
|
"void" :
|
|
GenTempName();
|
|
// if( $1.pNode->NodeKind() != NODE_VOID )
|
|
// ParseError( ABSTRACT_DECL, (char *)NULL );
|
|
|
|
SymKey SKey( pName, NAME_MEMBER );
|
|
|
|
pParam->SetSymName( pName );
|
|
pParam->SetBasicType( $1.pNode );
|
|
|
|
/**
|
|
** 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
|
|
**/
|
|
|
|
if( $1.pTNList )
|
|
{
|
|
ApplyAttributes( pParam, $1.pTNList );
|
|
delete $1.pTNList;
|
|
}
|
|
|
|
$$ = pParam;
|
|
|
|
}
|
|
;
|
|
|
|
OptionalConst:
|
|
KWCONST
|
|
{
|
|
$$ = new type_node_list((node_skl *)
|
|
GetPreAllocatedBitAttr( ATTR_PROC_CONST ));
|
|
}
|
|
| /* empty */
|
|
{
|
|
$$ = (type_node_list *)0;
|
|
}
|
|
;
|
|
ArrayDecl:
|
|
ArrayDecl2
|
|
{
|
|
$$ = 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_op_binary( OP_PLUS, $3, new expr_constant( 1L ) );
|
|
|
|
}
|
|
;
|
|
|
|
OpOrSwTypeAttributes:
|
|
OneOpOrSwTypeAttr
|
|
{
|
|
YY_CATCH( "OpOrSwTypeAttributes: OneOpOrSwTypeAttr");
|
|
$$ = $1;
|
|
}
|
|
| /** Empty **/
|
|
{
|
|
YY_CATCH( "OpOrSwTypeAttributes: Empty");
|
|
$$ = (type_node_list *)NULL;
|
|
}
|
|
;
|
|
|
|
OneOpOrSwTypeAttr:
|
|
OneOpOrSwTypeAttr OpOrSwTypeAttrSet
|
|
{
|
|
YY_CATCH("OneOpOrSwTypeAttr: OneOpOrSwTypeAttr OpOrSwTypeAttrSet");
|
|
$$->Merge( $2 );
|
|
}
|
|
| OpOrSwTypeAttrSet
|
|
{
|
|
YY_CATCH("OneOpOrSwTypeAttr: OpOrSwTypeAttrSet");
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
OpOrSwTypeAttrSet:
|
|
OperationAttributes
|
|
{
|
|
YY_CATCH( "OpOrSwTypeAttrSet: OperationAttributes");
|
|
$$ = $1;
|
|
}
|
|
| '[' UnionTypeSwitchAttr ']'
|
|
{
|
|
YY_CATCH("| '[' UnionTypeSwitchAttr ']'");
|
|
$$ = new type_node_list( $2 );
|
|
}
|
|
;
|
|
|
|
OperationAttributes:
|
|
'[' OperationAttributeList ']'
|
|
{
|
|
YY_CATCH("OperationAttributes: '[' OperationAttributeList ']'");
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
OperationAttributeList:
|
|
OperationAttributeList ',' OperationAttribute
|
|
{
|
|
YY_CATCH("OperationAttributeList: OperationAttributeList OperationAttribute");
|
|
if($3)
|
|
$$->SetPeer( $3 );
|
|
}
|
|
| OperationAttribute
|
|
{
|
|
YY_CATCH("OperationAttributeList: OperationAttribute");
|
|
if($1)
|
|
$$ = new type_node_list( $1 );
|
|
else
|
|
$$ = new type_node_list;
|
|
}
|
|
;
|
|
|
|
|
|
OperationAttribute:
|
|
UsageAttribute
|
|
{
|
|
YY_CATCH("OperationAttribute: UsageAttribute");
|
|
$$ = $1;
|
|
}
|
|
| PtrAttr
|
|
{
|
|
YY_CATCH("OperationAttribute: PtrAttr");
|
|
$$ = $1;
|
|
}
|
|
| KWCALLBACK
|
|
{
|
|
$$ = (node_skl *) new node_callback();
|
|
}
|
|
| KWIDEMPOTENT
|
|
{
|
|
$$ = (node_skl *) new node_idempotent();
|
|
}
|
|
| KWBROADCAST
|
|
{
|
|
$$ = (node_skl *) new node_broadcast();
|
|
}
|
|
| KWMAYBE
|
|
{
|
|
$$ = (node_skl *) new node_maybe();
|
|
}
|
|
| OtherOperationAttribute
|
|
{
|
|
YY_CATCH("OperationAttribute: OtherOperationAttributes");
|
|
/**
|
|
** This production exists to unify code for the attributes which
|
|
** just set bits. If the attribute number of $1 is 0, dont
|
|
** set any attribute bits
|
|
**/
|
|
$$ = (node_skl *)GetPreAllocatedBitAttr( $1 );
|
|
}
|
|
;
|
|
|
|
OtherOperationAttribute:
|
|
KWNOLISTEN
|
|
{
|
|
$$ = ATTR_NO_LISTEN;
|
|
}
|
|
| KWLOCAL
|
|
{
|
|
$$ = ATTR_LOCAL;
|
|
}
|
|
| NV1OperationAttribute
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
NV1OperationAttribute:
|
|
KWDATAGRAM
|
|
{
|
|
ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[datagram]");
|
|
$$ = ATTR_DATAGRAM;
|
|
}
|
|
;
|
|
|
|
OptShape:
|
|
'(' KWSHAPE ')'
|
|
{
|
|
ParseError(IGNORE_UNIMPLEMENTED_ATTRIBUTE, "[shape]");
|
|
$$ = ATTR_SHAPE;
|
|
}
|
|
| /* Empty */
|
|
{
|
|
$$ = ATTR_NONE;
|
|
}
|
|
;
|
|
|
|
|
|
InternationalCharacterType:
|
|
KWISOLATIN1
|
|
{
|
|
$$ = KWISOLATIN1;
|
|
}
|
|
| KWPRIVATECHAR8
|
|
{
|
|
$$ = KWPRIVATECHAR8;
|
|
}
|
|
| KWISOMULTILINGUAL
|
|
{
|
|
$$ = KWISOMULTILINGUAL;
|
|
}
|
|
| KWPRIVATECHAR16
|
|
{
|
|
$$ = KWPRIVATECHAR16;
|
|
}
|
|
| KWISOUCS
|
|
{
|
|
$$ = KWISOUCS;
|
|
}
|
|
;
|
|
|
|
|
|
|
|
/*************** DANGER: EXPRESSIONS FOLLOW: ***************/
|
|
|
|
Initializer:
|
|
AssignmentExpr
|
|
{
|
|
YY_CATCH("Initializer: AssignmentExpr");
|
|
$$ = new expr_init_list( $1 );
|
|
}
|
|
|
|
| '{' InitializerList OptionalComma '}'
|
|
{
|
|
ParseError( COMPOUND_INITS_NOT_SUPPORTED, (char *)0 );
|
|
$$ = (expr_init_list *)0;
|
|
// YY_CATCH("| '{' InitializerList OptionalComma '}'");
|
|
// $$ = 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
|
|
{
|
|
// YY_CATCH("InitializerList: Initializer");
|
|
// $$ = $1;
|
|
}
|
|
| InitializerList ',' Initializer
|
|
{
|
|
// YY_CATCH("| InitializerList ',' Initializer");
|
|
// $$->LinkSibling( $3 );
|
|
}
|
|
;
|
|
|
|
|
|
/***
|
|
*** VibhasC:WHERE IS THE production expr ',' AssignmentExpr valid ?
|
|
***/
|
|
|
|
Expr:
|
|
AssignmentExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| Expr ',' AssignmentExpr
|
|
{
|
|
$$ = $3;
|
|
}
|
|
;
|
|
|
|
VariableExpr:
|
|
ConditionalExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
ConstantExpr:
|
|
ConditionalExpr
|
|
{
|
|
|
|
/**
|
|
** The expression must be a constant, if not report error
|
|
**/
|
|
|
|
if( ! $1->IsConstant() )
|
|
ParseError( EXPR_NOT_CONSTANT, (char *)NULL );
|
|
$$ = $1;
|
|
|
|
}
|
|
;
|
|
|
|
AssignmentExpr:
|
|
ConditionalExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| 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, we transform the expression into
|
|
** a normal binary expression, so that we can deal with this uniformly.
|
|
** When formed this expression has the '?' operator, whose left is
|
|
** the logical_or_expression, and right is the colon operator. The
|
|
** colon operator has the expr and COnditonalExpr as its operands
|
|
**/
|
|
|
|
$$ = new expr_op_binary( OP_COLON, $3, $5 );
|
|
$$ = new expr_op_binary( OP_QM, $1, $$ );
|
|
|
|
}
|
|
;
|
|
|
|
LogicalOrExpr:
|
|
LogicalAndExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| LogicalOrExpr OROR LogicalAndExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_LOGICAL_OR, $1, $3 );
|
|
}
|
|
;
|
|
|
|
LogicalAndExpr:
|
|
InclusiveOrExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| LogicalAndExpr ANDAND InclusiveOrExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_LOGICAL_AND, $1, $3 );
|
|
}
|
|
;
|
|
|
|
InclusiveOrExpr:
|
|
ExclusiveOrExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| InclusiveOrExpr '|' ExclusiveOrExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_OR, $1, $3 );
|
|
}
|
|
;
|
|
|
|
ExclusiveOrExpr:
|
|
AndExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| ExclusiveOrExpr '^' AndExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_XOR, $1, $3 );
|
|
}
|
|
;
|
|
|
|
AndExpr:
|
|
EqualityExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| AndExpr '&' EqualityExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_AND, $1, $3 );
|
|
}
|
|
;
|
|
|
|
EqualityExpr:
|
|
RelationalExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| EqualityExpr EQUALS RelationalExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_EQUAL, $1, $3 );
|
|
}
|
|
| EqualityExpr NOTEQ RelationalExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_NOT_EQUAL, $1, $3 );
|
|
}
|
|
;
|
|
|
|
RelationalExpr:
|
|
ShiftExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| RelationalExpr '<' ShiftExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_LESS, $1, $3 );
|
|
}
|
|
| RelationalExpr '>' ShiftExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_GREATER, $1, $3 );
|
|
}
|
|
| RelationalExpr LTEQ ShiftExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_LESS_EQUAL, $1, $3 );
|
|
}
|
|
| RelationalExpr GTEQ ShiftExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_GREATER_EQUAL, $1, $3 );
|
|
}
|
|
;
|
|
|
|
ShiftExpr:
|
|
AdditiveExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| ShiftExpr LSHIFT AdditiveExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_LEFT_SHIFT, $1, $3 );
|
|
}
|
|
| ShiftExpr RSHIFT AdditiveExpr
|
|
{
|
|
$$ = new expr_op_binary( OP_RIGHT_SHIFT, $1, $3 );
|
|
}
|
|
;
|
|
|
|
AdditiveExpr:
|
|
MultExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| AdditiveExpr AddOp MultExpr
|
|
{
|
|
$$ = new expr_op_binary( $2, $1, $3 );
|
|
}
|
|
;
|
|
|
|
MultExpr:
|
|
CastExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| MultExpr MultOp CastExpr
|
|
{
|
|
$$ = new expr_op_binary( $2, $1, $3 );
|
|
}
|
|
;
|
|
|
|
CastExpr:
|
|
UnaryExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
| '(' DeclarationSpecifiers OptionalDeclarator ')' CastExpr
|
|
{
|
|
node_skl * pNode = pErrorTypeNode;
|
|
|
|
if( $2.pNode )
|
|
{
|
|
if( $2.pTNList )
|
|
{
|
|
ApplyAttributes( $2.pNode, $2.pTNList );
|
|
delete $2.pTNList;
|
|
}
|
|
|
|
if( $3 )
|
|
{
|
|
$3->SetBasicType( $2.pNode );
|
|
pNode = $3;
|
|
}
|
|
else
|
|
pNode = $2.pNode;
|
|
}
|
|
$$ = new expr_cast( pNode, $5 );
|
|
}
|
|
;
|
|
|
|
UnaryExpr:
|
|
PostfixExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| UnaryOp CastExpr
|
|
{
|
|
$$ = new expr_op_unary( $1, $2 );
|
|
}
|
|
| 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;
|
|
|
|
if( $3.pNode )
|
|
{
|
|
|
|
if( $3.pTNList )
|
|
{
|
|
ApplyAttributes( $3.pNode, $3.pTNList );
|
|
delete $3.pTNList;
|
|
}
|
|
|
|
if( $4 )
|
|
{
|
|
$4->SetBasicType( $3.pNode );
|
|
pNode = $4;
|
|
}
|
|
else
|
|
pNode = $3.pNode;
|
|
|
|
}
|
|
|
|
$$ = new expr_sizeof( pNode );
|
|
}
|
|
| KWSIZEOF UnaryExpr
|
|
{
|
|
$$ = new expr_sizeof( $2 );
|
|
}
|
|
;
|
|
|
|
PostfixExpr:
|
|
PrimaryExpr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| PostfixExpr '[' Expr ']'
|
|
{
|
|
$$ = new expr_op_binary( OP_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_op_binary( OP_POINTSTO, $1, pIDExpr );
|
|
|
|
}
|
|
| PostfixExpr '.' IDENTIFIER
|
|
{
|
|
|
|
expr_variable * pIDExpr = new expr_variable( $3 );
|
|
$$ = new expr_op_binary( OP_DOT, $1, pIDExpr );
|
|
|
|
}
|
|
;
|
|
|
|
PrimaryExpr:
|
|
IDENTIFIER
|
|
{
|
|
$$ = new expr_variable( $1 );
|
|
}
|
|
| NUMERICCONSTANT
|
|
{
|
|
$$ = new expr_constant( (long) $1.Val );
|
|
}
|
|
| NUMERICLONGCONSTANT
|
|
{
|
|
GetBaseTypeNode( (node_skl **)(&($$)),SIGN_SIGNED,SIZE_LONG,TYPE_INT );
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_NUMERIC_LONG,
|
|
(node_skl *)$$ );
|
|
}
|
|
| NUMERICULONGCONSTANT
|
|
{
|
|
GetBaseTypeNode( (node_skl **)(&($$)),SIGN_UNSIGNED,SIZE_LONG,TYPE_INT);
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_NUMERIC_ULONG,
|
|
(node_skl *)$$ );
|
|
}
|
|
| HEXCONSTANT
|
|
{
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_HEX );
|
|
}
|
|
| HEXLONGCONSTANT
|
|
{
|
|
GetBaseTypeNode( (node_skl **)(&($$)),SIGN_SIGNED,SIZE_LONG,TYPE_INT);
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_HEX_LONG,
|
|
(node_skl *)$$ );
|
|
}
|
|
| HEXULONGCONSTANT
|
|
{
|
|
GetBaseTypeNode( (node_skl **)(&($$)),SIGN_UNSIGNED,SIZE_LONG,TYPE_INT);
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_HEX_ULONG,
|
|
(node_skl *)$$ );
|
|
}
|
|
| OCTALCONSTANT
|
|
{
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_OCTAL );
|
|
}
|
|
| OCTALLONGCONSTANT
|
|
{
|
|
GetBaseTypeNode( (node_skl **)(&($$)),SIGN_SIGNED,SIZE_LONG,TYPE_INT);
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_OCTAL_LONG,
|
|
(node_skl *)$$ );
|
|
}
|
|
| OCTALULONGCONSTANT
|
|
{
|
|
GetBaseTypeNode( (node_skl **)(&($$)),SIGN_UNSIGNED,SIZE_LONG,TYPE_INT);
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_OCTAL_ULONG,
|
|
(node_skl *)$$ );
|
|
}
|
|
| TOKENTRUE
|
|
{
|
|
$$ = new expr_constant( (long)TRUE );
|
|
}
|
|
| TOKENFALSE
|
|
{
|
|
$$ = new expr_constant( (long)FALSE );
|
|
}
|
|
| KWTOKENNULL
|
|
{
|
|
$$ = new expr_constant( (char *)NULL );
|
|
}
|
|
| STRING
|
|
{
|
|
$$ = new expr_constant( (char *)$1 );
|
|
}
|
|
| WIDECHARACTERSTRING
|
|
{
|
|
ParseError( WCHAR_STRING_NOT_OSF, (char *)NULL );
|
|
$$ = new expr_constant( (wchar_t *)$1 );
|
|
}
|
|
| CHARACTERCONSTANT
|
|
{
|
|
/***
|
|
GetBaseTypeNode( (node_skl **)(&($$)),SIGN_SIGNED,SIZE_CHAR,TYPE_INT );
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_CHAR, (node_skl *)$$);
|
|
***/
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_CHAR );
|
|
}
|
|
| WIDECHARACTERCONSTANT
|
|
{
|
|
ParseError( WCHAR_CONSTANT_NOT_OSF, (char *)NULL );
|
|
/***
|
|
GetBaseTypeNode( (node_skl **)(&($$)),SIGN_UNSIGNED,SIZE_SHORT,TYPE_INT );
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_WCHAR, (node_skl *)$$);
|
|
***/
|
|
$$ = new expr_constant( (long) $1.Val, VALUE_TYPE_WCHAR);
|
|
}
|
|
| '(' Expr ')'
|
|
{
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
|
|
|
|
UnaryOp:
|
|
AddOp
|
|
{
|
|
$$ = ($1 == OP_PLUS) ? OP_UNARY_PLUS : OP_UNARY_MINUS;
|
|
}
|
|
| '!'
|
|
{
|
|
$$ = OP_UNARY_NOT;
|
|
}
|
|
| '&'
|
|
{
|
|
$$ = OP_UNARY_AND;
|
|
}
|
|
| '*'
|
|
{
|
|
$$ = OP_UNARY_INDIRECTION;
|
|
}
|
|
| '~'
|
|
{
|
|
$$ = OP_UNARY_COMPLEMENT;
|
|
}
|
|
;
|
|
|
|
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
|
|
{
|
|
}
|
|
;
|
|
|
|
AcfInterfaceAttribute:
|
|
AcfImpHdlAttr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| AcfAutoHdlAttr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
AcfImpHdlAttr:
|
|
KWIMPLICITHANDLE '(' AcfImpHdlTypeSpec IDENTIFIER ')'
|
|
{
|
|
$$ = (node_skl *)new node_implicit( $3, $4 );
|
|
}
|
|
;
|
|
AcfImpHdlTypeSpec:
|
|
KWHANDLET
|
|
{
|
|
GetBaseTypeNode( &($$), SIGN_UNDEF, SIZE_UNDEF, TYPE_HANDLE_T );
|
|
}
|
|
| IDENTIFIER
|
|
{
|
|
SymKey SKey( $1, NAME_DEF );
|
|
$$ = new node_forward( SKey );
|
|
$$->SetSymName( $1 );
|
|
$$->SetAttribute( ATTR_HANDLE );
|
|
$$->SetAttribute( ATTR_INT_IMP_HANDLE );
|
|
|
|
//
|
|
// keep a track of this node to ensure it is not used as a
|
|
// context handle.
|
|
//
|
|
|
|
if( ImportLevel == 0 )
|
|
{
|
|
pBaseImplicitHandle = $$;
|
|
}
|
|
}
|
|
| TYPENAME
|
|
{
|
|
SymKey SKey( $1, NAME_DEF );
|
|
if( ! ($$ = pBaseSymTbl->SymSearch( SKey ) ) )
|
|
{
|
|
if( ImportLevel == 0 )
|
|
ParseError( UNDEFINED_SYMBOL, $1 );
|
|
$$ = new node_error;
|
|
}
|
|
else
|
|
$$ = $$->Clone();
|
|
}
|
|
;
|
|
AcfAutoHdlAttr:
|
|
KWAUTOHANDLE
|
|
{
|
|
$$ = (node_skl *)new node_auto;
|
|
}
|
|
;
|
|
%%
|
|
|
|
/***************************************************************************
|
|
* 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 );
|
|
}
|
|
|