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.
4277 lines
123 KiB
4277 lines
123 KiB
/*++
|
|
|
|
Copyright (c) 1996-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sortpp.c
|
|
|
|
Abstract:
|
|
|
|
This program parses the file winincs.pp and generates a .PPM file
|
|
compatible with GENTHNK.
|
|
|
|
Author:
|
|
|
|
08-Jul-1995 JonLe
|
|
|
|
Revision History:
|
|
|
|
27-Nov-1996 BarryBo -- code cleanup and documentation
|
|
20-Mar-1998 mzoran -- Added support for finding COM interfaces
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
#include "gen.h"
|
|
|
|
// string to put in front of all error messages so that BUILD can find them.
|
|
const char *ErrMsgPrefix = "NMAKE : U8604: 'SORTPP' ";
|
|
|
|
FILE *fpHeaders;
|
|
int StatementLineNumber;
|
|
char SourceFileName[MAX_PATH+1];
|
|
int SourceLineNumber;
|
|
int TypeId = 0;
|
|
|
|
void DumpLexerOutput(int FirstToken);
|
|
|
|
//
|
|
// packing size as specified by /Zp option to the CL command
|
|
//
|
|
#define DEFAULTPACKINGSIZE 8
|
|
|
|
DWORD dwPackingCurrent = DEFAULTPACKINGSIZE;
|
|
|
|
typedef struct _packholder {
|
|
struct _packholder *ppackholderNext;
|
|
DWORD dwPacking;
|
|
char sIdentifier[1];
|
|
} PACKHOLDER;
|
|
|
|
PACKHOLDER *ppackholderHead = NULL;
|
|
|
|
struct TypeInfoListElement {
|
|
struct TypeInfoListElement *pNext;
|
|
TYPESINFO *pTypeInfo;
|
|
};
|
|
|
|
typedef struct TypeInfoListElement *PTYPEINFOELEMENT;
|
|
|
|
PKNOWNTYPES NIL; // for red-black trees
|
|
PRBTREE FuncsList;
|
|
PRBTREE StructsList;
|
|
PRBTREE TypeDefsList;
|
|
RBTREE _VarsList;
|
|
PRBTREE VarsList = &_VarsList; // Used to track global variable declarations.
|
|
// Should not appear in the PPM file
|
|
|
|
char Headers[MAX_PATH+1];
|
|
char ppmName[MAX_PATH+1];
|
|
|
|
HANDLE hCvmHeap;
|
|
ULONG uBaseAddress = 0x30000000;
|
|
ULONG uReserveSize = 0x01800000;
|
|
|
|
BOOL bLine = FALSE;
|
|
char szThis[] = "This";
|
|
|
|
DWORD dwScopeLevel = 0;
|
|
|
|
void ExtractDerivedTypes(void);
|
|
BOOL LexNextStatement(void);
|
|
BOOL ParseFuncTypes(PTYPESINFO pTypesInfo, BOOL fDllImport);
|
|
BOOL ParseStructTypes(PTYPESINFO pTypesInfo);
|
|
BOOL ParseTypeDefs(PTYPESINFO pTypesInfo);
|
|
BOOL ParseVariables(VOID);
|
|
BOOL ParseGuid(GUID *pGuid);
|
|
BOOL AddDefaultDerivedTypes(void);
|
|
PKNOWNTYPES AddNewType(PTYPESINFO pTypesInfo, PRBTREE pTypesList);
|
|
BOOL CopyStructMembers(PTYPESINFO pTypesInfo, BOOL bUnion, PKNOWNTYPES pBaseType);
|
|
BOOL CopyEnumMembers(PTYPESINFO);
|
|
int CreatePseudoName(char *pDst, char *pSrc);
|
|
BOOL GetArrayIndex(DWORD *pdw);
|
|
LONGLONG expr(void);
|
|
LONGLONG expr_a1(void);
|
|
LONGLONG expr_a(void);
|
|
LONGLONG expr_b(void);
|
|
LONGLONG expr_c(void);
|
|
void CheckUpdateTypedefSizes(PTYPESINFO ptypesinfo);
|
|
PVOID SortppAllocCvm(ULONG Size);
|
|
BOOL WritePpmFile(char *PpmName);
|
|
void BumpStructUnionSize(DWORD *pdwSize, DWORD dwElemSize, BOOL bUnion);
|
|
BOOL GetExistingType(PTYPESINFO pTypesInfo, PBOOL pbFnPtr, PKNOWNTYPES *ppKnownTypes);
|
|
BOOL PrepareMappedMemory(void);
|
|
DWORD PackPaddingSize(DWORD dwCurrentSize, DWORD dwBase);
|
|
void PackPush(char *sIdentifier);
|
|
DWORD PackPop(char *sIdentifier);
|
|
BOOL ConsumeDeclSpecOpt(BOOL IsFunc, BOOL bInitReturns, BOOL *pIsDllImport, BOOL *pIsGuidDefined, GUID *pGuid);
|
|
TOKENTYPE ConsumeDirectionOpt(void);
|
|
TOKENTYPE ConsumeConstVolatileOpt(void);
|
|
PTYPEINFOELEMENT TypeInfoElementAllocateLink(PTYPEINFOELEMENT *ppHead, PTYPEINFOELEMENT pThis, TYPESINFO *pType);
|
|
VOID UpdateGuids(VOID);
|
|
BOOL AddVariable(char *Name, GUID * pGuid);
|
|
VOID GenerateProxy(char *pName, PTYPESINFO pTypesInfo);
|
|
VOID FreeTypeInfoList(PTYPEINFOELEMENT pThis);
|
|
PMEMBERINFO CatMeminfo(BUFALLOCINFO *pBufallocinfo, PMEMBERINFO pHead, PMEMBERINFO pTail, DWORD dwOffset, BOOL bStatus);
|
|
BOOL ConsumeExternC(void);
|
|
|
|
//
|
|
// PPC compiler is screwing up the Initializa list head macro !
|
|
//
|
|
#if defined (_PPC_)
|
|
#undef InitializeListHead
|
|
#define InitializeListHead(ListHead) ( (ListHead)->Flink = (ListHead), \
|
|
(ListHead)->Blink = (ListHead) \
|
|
)
|
|
#endif
|
|
|
|
|
|
_inline void
|
|
PackModify(
|
|
DWORD dw
|
|
)
|
|
{
|
|
dwPackingCurrent = dw;
|
|
DbgPrintf("new packing is %x\n", dw);
|
|
}
|
|
|
|
_inline DWORD
|
|
PackCurrentPacking(
|
|
void
|
|
)
|
|
{
|
|
return dwPackingCurrent;
|
|
}
|
|
|
|
DWORD PackPaddingSize(DWORD dwCurrentSize, DWORD dwBase)
|
|
{
|
|
DWORD dw;
|
|
|
|
if (dwCurrentSize == 0) {
|
|
return 0; // no padding for first member
|
|
}
|
|
|
|
if (dwBase == 0) {
|
|
dwBase = SIZEOFPOINTER;
|
|
} // if no base size yet then must be a ptr
|
|
|
|
// base is min(size, packing)
|
|
if (dwBase > PackCurrentPacking()) {
|
|
dwBase = PackCurrentPacking();
|
|
}
|
|
|
|
// figure out padding
|
|
return (dwBase - (dwCurrentSize % dwBase)) % dwBase;
|
|
}
|
|
|
|
_inline DWORD PackPackingSize(DWORD dwCurrentSize, DWORD dwSize,
|
|
DWORD dwBase)
|
|
{
|
|
// round up to nearest dwBase
|
|
return PackPaddingSize(dwCurrentSize, dwBase) + dwSize;
|
|
}
|
|
|
|
|
|
|
|
/* main
|
|
*
|
|
* standard win32 base windows entry point
|
|
* returns 0 for clean exit, otherwise nonzero for error
|
|
*
|
|
*
|
|
* ExitCode:
|
|
* 0 - Clean exit with no Errors
|
|
* nonzero - error ocurred
|
|
*
|
|
*/
|
|
int __cdecl main(int argc, char **argv)
|
|
{
|
|
int i;
|
|
char *pHeaders = NULL;
|
|
char *pch;
|
|
DWORD LenHeaders=0;
|
|
|
|
SetConsoleCtrlHandler(ConsoleControlHandler, TRUE);
|
|
|
|
try {
|
|
|
|
/*
|
|
* Get cmd line args.
|
|
*/
|
|
i = 0;
|
|
while (++i < argc) {
|
|
pch = argv[i];
|
|
if (*pch == '-' || *pch == '/') {
|
|
pch++;
|
|
switch (toupper(*pch)) {
|
|
case 'D': // debug forces extra check
|
|
bDebug = TRUE;
|
|
setvbuf(stderr, NULL, _IONBF, 0);
|
|
break;
|
|
|
|
case 'L':
|
|
bLine = TRUE;
|
|
break;
|
|
|
|
case 'M': // ppm output filename
|
|
strcpy(ppmName, ++pch);
|
|
DeleteFile(ppmName);
|
|
break;
|
|
|
|
case 'B': // gBaseAddress
|
|
pch++;
|
|
uBaseAddress = atoi(pch);
|
|
break;
|
|
|
|
case 'R': // Reserve size
|
|
pch++;
|
|
uReserveSize = atoi(pch);
|
|
break;
|
|
|
|
case '?': // usage
|
|
ExitErrMsg(FALSE,
|
|
"sortpp -d -l -w -m<ppm file> -b<Base addr> -r<reserved> <pp file>\n");
|
|
|
|
default:
|
|
ExitErrMsg(FALSE, "Unrecognized option %s\n", pch);
|
|
}
|
|
} else if (*pch) {
|
|
strcpy(Headers, pch);
|
|
}
|
|
}
|
|
|
|
if (!*Headers) {
|
|
ExitErrMsg(FALSE, "no Headers file name\n");
|
|
}
|
|
|
|
if (!*ppmName) {
|
|
ExitErrMsg(FALSE, "no -m<PPM filename>\n");
|
|
}
|
|
|
|
|
|
DbgPrintf("%s -> %s\n", Headers, ppmName);
|
|
|
|
|
|
if (!PrepareMappedMemory()) {
|
|
ExitErrMsg(FALSE, "Problem in PrepareMappedMemory %s, gle = %d\n",
|
|
Headers, GetLastError());
|
|
}
|
|
|
|
RBInitTree(FuncsList);
|
|
RBInitTree(StructsList);
|
|
RBInitTree(TypeDefsList);
|
|
RBInitTree(VarsList); //not in the PPM file
|
|
|
|
fpHeaders = fopen(Headers, "r");
|
|
|
|
if (fpHeaders == NULL) {
|
|
ExitErrMsg(FALSE, "Headers open '%s' errno=%d\n", Headers, errno);
|
|
}
|
|
|
|
if (!AddDefaultDerivedTypes()) {
|
|
ExitErrMsg(TRUE, "AddDefaultDerivedTypes failed\n");
|
|
}
|
|
|
|
// pull out the different types: structs, typedefs function prototypes
|
|
ExtractDerivedTypes();
|
|
|
|
// Attempt to update guids for structs that don't have them
|
|
UpdateGuids();
|
|
|
|
if (!WritePpmFile(ppmName)) {
|
|
ExitErrMsg(FALSE, "Problem in WritePpmFile gle = %d\n", GetLastError());
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
ExitErrMsg(FALSE,
|
|
"sortpp: ExceptionCode=%x\n",
|
|
GetExceptionCode()
|
|
);
|
|
}
|
|
|
|
DeleteAllocCvmHeap(hCvmHeap);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
AddDefaultDerivedTypes(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add signed, unsigned to TypeDefsList. Treated as derived types
|
|
based on int.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure (probably out-of-memory)
|
|
|
|
--*/
|
|
{
|
|
TYPESINFO TypesInfo;
|
|
PFUNCINFO funcinfo;
|
|
|
|
memset(&TypesInfo, 0, sizeof(TYPESINFO));
|
|
|
|
strcpy(TypesInfo.BasicType,szINT);
|
|
strcpy(TypesInfo.BaseName,szINT);
|
|
strcpy(TypesInfo.TypeName,szINT);
|
|
TypesInfo.Size = sizeof(int);
|
|
TypesInfo.iPackSize = sizeof(int);
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.TypeName,"unsigned int");
|
|
TypesInfo.Flags = BTI_NOTDERIVED | BTI_UNSIGNED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.TypeName,"short int");
|
|
TypesInfo.Size = sizeof(short int);
|
|
TypesInfo.iPackSize = sizeof(short int);
|
|
TypesInfo.Flags = BTI_NOTDERIVED | BTI_UNSIGNED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.TypeName,"unsigned short int");
|
|
TypesInfo.Flags = BTI_NOTDERIVED | BTI_UNSIGNED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.TypeName,"long int");
|
|
TypesInfo.Size = sizeof(long int);
|
|
TypesInfo.iPackSize = sizeof(long int);
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.TypeName,"unsigned long int");
|
|
TypesInfo.Flags = BTI_NOTDERIVED | BTI_UNSIGNED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.BasicType,szCHAR);
|
|
strcpy(TypesInfo.BaseName,szCHAR);
|
|
strcpy(TypesInfo.TypeName,szCHAR);
|
|
TypesInfo.Size = sizeof(char);
|
|
TypesInfo.iPackSize = sizeof(char);
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.TypeName,szUNSIGNEDCHAR);
|
|
TypesInfo.Flags = BTI_NOTDERIVED | BTI_UNSIGNED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.BasicType,szINT64);
|
|
strcpy(TypesInfo.BaseName,szINT64);
|
|
strcpy(TypesInfo.TypeName,szINT64);
|
|
TypesInfo.Size = sizeof(__int64);
|
|
TypesInfo.iPackSize = sizeof(__int64);
|
|
TypesInfo.Flags = BTI_NOTDERIVED | BTI_INT64DEP | BTI_POINTERDEP;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.TypeName,"unsigned _int64");
|
|
TypesInfo.Flags = BTI_NOTDERIVED | BTI_UNSIGNED | BTI_INT64DEP | BTI_POINTERDEP;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.BasicType,sz_INT64);
|
|
strcpy(TypesInfo.BaseName,sz_INT64);
|
|
strcpy(TypesInfo.TypeName,sz_INT64);
|
|
TypesInfo.Flags = BTI_NOTDERIVED | BTI_INT64DEP | BTI_POINTERDEP;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.TypeName,"unsigned __int64");
|
|
TypesInfo.Flags = BTI_NOTDERIVED | BTI_UNSIGNED | BTI_INT64DEP | BTI_POINTERDEP;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.BasicType,szDOUBLE);
|
|
strcpy(TypesInfo.BaseName,szDOUBLE);
|
|
strcpy(TypesInfo.TypeName,szDOUBLE);
|
|
TypesInfo.Size = sizeof(double);
|
|
TypesInfo.iPackSize = sizeof(double);
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.BasicType,szFLOAT);
|
|
strcpy(TypesInfo.BaseName,szFLOAT);
|
|
strcpy(TypesInfo.TypeName,szFLOAT);
|
|
TypesInfo.Size = sizeof(float);
|
|
TypesInfo.iPackSize = sizeof(float);
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.BasicType,szVOID);
|
|
strcpy(TypesInfo.BaseName,szVOID);
|
|
strcpy(TypesInfo.TypeName,szVOID);
|
|
TypesInfo.Size = 0;
|
|
TypesInfo.iPackSize = 0;
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.BasicType,szGUID);
|
|
strcpy(TypesInfo.BaseName,szGUID);
|
|
strcpy(TypesInfo.TypeName,szGUID);
|
|
TypesInfo.Size = 16;
|
|
TypesInfo.iPackSize = 16;
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(TypesInfo.BasicType,szFUNC);
|
|
strcpy(TypesInfo.BaseName,szFUNC);
|
|
strcpy(TypesInfo.TypeName,szFUNC);
|
|
TypesInfo.Flags = BTI_CONTAINSFUNCPTR | BTI_NOTDERIVED;
|
|
TypesInfo.Size = 4;
|
|
TypesInfo.iPackSize = 4;
|
|
TypesInfo.dwMemberSize = sizeof(FUNCINFO)+strlen(szVOID)+1;
|
|
TypesInfo.TypeKind = TypeKindFunc;
|
|
funcinfo = (PFUNCINFO)TypesInfo.Members;
|
|
TypesInfo.pfuncinfo = funcinfo;
|
|
funcinfo->sType = TypesInfo.Members + sizeof(FUNCINFO);
|
|
strcpy(funcinfo->sType, szVOID);
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
TypesInfo.dwMemberSize = 0;
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
TypesInfo.TypeKind = TypeKindEmpty;
|
|
TypesInfo.pfuncinfo = NULL;
|
|
memset(TypesInfo.Members, 0, sizeof(TypesInfo.Members));
|
|
|
|
strcpy(TypesInfo.BasicType,szVARGS);
|
|
strcpy(TypesInfo.BaseName,szVARGS);
|
|
strcpy(TypesInfo.TypeName,szVARGS);
|
|
TypesInfo.Size = 0; // varargs has size of 0
|
|
TypesInfo.iPackSize = 0;
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Generic pointer type. Not generated by sortpp, but used by genthnk
|
|
strcpy(TypesInfo.BasicType, "*");
|
|
strcpy(TypesInfo.BaseName, "*");
|
|
strcpy(TypesInfo.TypeName, "*");
|
|
TypesInfo.IndLevel = 1;
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Generic struct type. Not generated by sortpp, but used by genthnk
|
|
strcpy(TypesInfo.BasicType, "struct");
|
|
strcpy(TypesInfo.BaseName, "struct");
|
|
strcpy(TypesInfo.TypeName, "struct");
|
|
TypesInfo.IndLevel = 0;
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Generic union type. Not generated by sortpp, but used by genthnk
|
|
strcpy(TypesInfo.BasicType, "union");
|
|
strcpy(TypesInfo.BaseName, "union");
|
|
strcpy(TypesInfo.TypeName, "union");
|
|
TypesInfo.IndLevel = 0;
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Default type that matches all types. Not generated by sortpp, but used by genthnk
|
|
strcpy(TypesInfo.BasicType, "default");
|
|
strcpy(TypesInfo.BaseName, "default");
|
|
strcpy(TypesInfo.TypeName, "default");
|
|
TypesInfo.IndLevel = 0;
|
|
TypesInfo.Flags = BTI_NOTDERIVED;
|
|
if (!AddToTypesList(TypeDefsList, &TypesInfo)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
ConsumeExternC(
|
|
void
|
|
)
|
|
{
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Consumes an extern or an extern "C".
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE - extern or extern "C" was consumed.
|
|
|
|
--*/
|
|
|
|
PTOKEN Token;
|
|
Token = CurrentToken();
|
|
if (Token->TokenType == TK_EXTERN) {
|
|
ConsumeToken();
|
|
Token = CurrentToken();
|
|
if (Token->TokenType == TK_STRING &&
|
|
strcmp(Token->Name, "C") == 0)
|
|
ConsumeToken();
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
ExtractDerivedTypes(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes derived type definitions from headers, building the
|
|
TypesDef, Structs, and Funcs lists.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
TYPESINFO TypesInfo;
|
|
PRBTREE pListHead;
|
|
BOOL fDllImport;
|
|
|
|
//
|
|
// Lex in entire C-language statements, then parse them. Stops at EOF.
|
|
//
|
|
while (LexNextStatement()) {
|
|
|
|
int OldTokenIndex;
|
|
int c;
|
|
|
|
if (bDebug) {
|
|
DumpLexerOutput(0);
|
|
}
|
|
|
|
if (bLine) {
|
|
for(c=80; c > 0; c--)
|
|
fputc('\b', stderr);
|
|
c = fprintf(stderr, "Status: %s(%d)", SourceFileName, StatementLineNumber);
|
|
for(; c < 78; c++)
|
|
fputc(' ', stderr);
|
|
fflush(stderr);
|
|
}
|
|
|
|
pListHead = NULL;
|
|
assert(dwScopeLevel == 0);
|
|
|
|
if (CurrentToken()->TokenType == TK_EOS) {
|
|
|
|
//ddraw.h has an extra ; at the end of an extern "C" block
|
|
continue;
|
|
|
|
}
|
|
|
|
ConsumeExternC();
|
|
|
|
ConsumeDeclSpecOpt(TRUE, TRUE, &fDllImport, NULL, NULL);
|
|
|
|
ConsumeExternC();
|
|
|
|
OldTokenIndex = CurrentTokenIndex;
|
|
//
|
|
// Try to parse as a TypeDef.
|
|
//
|
|
if (ParseTypeDefs(&TypesInfo)) {
|
|
//
|
|
// Got a typedef
|
|
//
|
|
if (CurrentToken()->TokenType == TK_EOS) {
|
|
pListHead = TypeDefsList;
|
|
goto DoAddNewType;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Failed to parse as TypeDef. Try to parse as a struct/union/enum
|
|
//
|
|
CurrentTokenIndex = OldTokenIndex;
|
|
if (ParseStructTypes(&TypesInfo)) {
|
|
//
|
|
// got a struct definition
|
|
//
|
|
if (CurrentToken()->TokenType == TK_EOS) {
|
|
pListHead = StructsList;
|
|
goto DoAddNewType;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Failed to parse as struct/union/enum. Try to parse as function
|
|
//
|
|
CurrentTokenIndex = OldTokenIndex;
|
|
if (ParseFuncTypes(&TypesInfo, fDllImport)) {
|
|
//
|
|
// got a function prototype
|
|
//
|
|
if (CurrentToken()->TokenType == TK_EOS && !TypesInfo.IndLevel) {
|
|
pListHead = FuncsList;
|
|
goto DoAddNewType;
|
|
}
|
|
}
|
|
|
|
CurrentTokenIndex = OldTokenIndex;
|
|
if (ParseVariables()) continue;
|
|
|
|
CurrentTokenIndex = OldTokenIndex;
|
|
|
|
DoAddNewType:
|
|
if (pListHead && !AddNewType(&TypesInfo, pListHead)) {
|
|
ErrMsg("AddNewType fail\n");
|
|
}
|
|
|
|
if (CurrentToken()->TokenType != TK_EOS && bDebug) {
|
|
|
|
fprintf(stderr, "Warning: Rejected %s(%d)\n", SourceFileName, StatementLineNumber);
|
|
//
|
|
// Use the 8k buffer in TypesInfo.Members to unlex the source stmt
|
|
//
|
|
UnlexToText(TypesInfo.Members,
|
|
sizeof(TypesInfo.Members),
|
|
0,
|
|
MAX_TOKENS_IN_STATEMENT);
|
|
fprintf(stderr, "\t%s;\n", TypesInfo.Members);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
PKNOWNTYPES
|
|
AddNewType(
|
|
PTYPESINFO pTypesInfo,
|
|
PRBTREE pTypesList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a new type to a types list.
|
|
|
|
Arguments:
|
|
|
|
pTypesInfo -- type to add
|
|
pTypesList -- list to add the type to
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the KNOWNTYPES for the new type on success,
|
|
NULL for error.
|
|
|
|
--*/
|
|
{
|
|
PKNOWNTYPES pkt;
|
|
PKNOWNTYPES pKnownTypes = NULL;
|
|
PDEFBASICTYPES pdbt;
|
|
ULONG Flags = 0;
|
|
BOOL bRet = FALSE;
|
|
|
|
if (((pTypesList == TypeDefsList) || (pTypesList == StructsList)) &&
|
|
(((pTypesInfo->Size == 0) || (pTypesInfo->iPackSize == 0)) &&
|
|
(*pTypesInfo->Members != 0))) {
|
|
DbgPrintf("Added type with invalid size %s %s %s %d %d\n",
|
|
pTypesInfo->BasicType,
|
|
pTypesInfo->BaseName,
|
|
pTypesInfo->TypeName,
|
|
pTypesInfo->Size,
|
|
pTypesInfo->iPackSize);
|
|
}
|
|
|
|
pTypesInfo->TypeId = TypeId++;
|
|
pTypesInfo->LineNumber = SourceLineNumber;
|
|
pTypesInfo->dwScopeLevel = dwScopeLevel;
|
|
pTypesInfo->dwCurrentPacking = PackCurrentPacking();
|
|
if (strlen(SourceFileName) > sizeof(pTypesInfo->FileName) - 1)
|
|
ExitErrMsg(FALSE, "Source file name is too large.\n");
|
|
strcpy(pTypesInfo->FileName, SourceFileName);
|
|
if (IsDefinedPointerDependent(pTypesInfo->TypeName))
|
|
pTypesInfo->Flags |= BTI_POINTERDEP;
|
|
|
|
//
|
|
// Loop up the type and see if it is already in the list
|
|
//
|
|
pkt = GetNameFromTypesList(pTypesList, pTypesInfo->TypeName);
|
|
if (pkt) {
|
|
//
|
|
// Uncomment the next line and comment the following line to change the
|
|
// behavior of this function. By doing this you will allow functions to be
|
|
// redefined in the following case: First a function that has no arguments
|
|
// is encountered and entered in the list. Later the same function is
|
|
// encountered with arguments and the new definition for it would override
|
|
// the old.
|
|
// if ((pTypesList == StructsList) || (pTypesList == FuncsList)) {
|
|
if (pTypesList == StructsList) {
|
|
|
|
if (pTypesInfo->dwMemberSize == 0) {
|
|
//
|
|
// Since the struct has already been defined lets grab its
|
|
// relevant size information.
|
|
//
|
|
pTypesInfo->IndLevel = pkt->IndLevel;
|
|
pTypesInfo->Size = pkt->Size;
|
|
pTypesInfo->iPackSize = pkt->iPackSize;
|
|
pTypesInfo->TypeId = pkt->TypeId;
|
|
return pkt;
|
|
}
|
|
|
|
if (! pkt->pmeminfo) {
|
|
//
|
|
// Find any previously defined typedefs that are based upon this
|
|
// struct and fix their size.
|
|
|
|
CheckUpdateTypedefSizes(pTypesInfo);
|
|
ReplaceInTypesList(pkt, pTypesInfo);
|
|
return pkt;
|
|
}
|
|
}
|
|
else if (pkt->Flags & BTI_DISCARDABLE) {
|
|
ReplaceInTypesList(pkt, pTypesInfo);
|
|
return pkt;
|
|
}
|
|
//
|
|
// else if it already exists, assume is the same
|
|
//
|
|
DbgPrintf("typedef: %s previously defined\n", pTypesInfo->TypeName);
|
|
return pkt;
|
|
}
|
|
|
|
//
|
|
// Type is not already listed. Look up its basic type
|
|
//
|
|
pdbt = GetDefBasicType(pTypesInfo->BasicType);
|
|
if (pdbt) {
|
|
Flags = 0;
|
|
} else {
|
|
pkt = GetNameFromTypesList(pTypesList, pTypesInfo->BasicType);
|
|
if (pkt) {
|
|
Flags = pkt->Flags;
|
|
pdbt = GetDefBasicType(pkt->BasicType);
|
|
if (!pdbt) {
|
|
ErrMsg("types Table corrupt %s\n", pkt->TypeName);
|
|
}
|
|
} else {
|
|
ErrMsg("ant: unknown Basic Type %s\n", pTypesInfo->BasicType);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
pTypesInfo->Flags |= Flags;
|
|
strcpy(pTypesInfo->BasicType, pdbt->BasicType);
|
|
pKnownTypes = AddToTypesList(pTypesList, pTypesInfo);
|
|
if (pKnownTypes == NULL)
|
|
goto ErrorExit;
|
|
|
|
if (bDebug)
|
|
DumpTypesInfo(pTypesInfo, stdout);
|
|
|
|
return pKnownTypes;
|
|
|
|
ErrorExit:
|
|
if (bDebug) {
|
|
DumpTypesInfo(pTypesInfo, stdout);
|
|
}
|
|
|
|
|
|
DumpTypesInfo(pTypesInfo, stderr);
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
void
|
|
CheckUpdateTypedefSizes(
|
|
PTYPESINFO ptypesinfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We are about to replace an empty struct definition with one that has
|
|
members and thus a size. We need to look through the typedefs list and
|
|
see if any that have a size of 0 are defined from this new struct and if
|
|
so then fix its size and packing size.
|
|
|
|
Arguments:
|
|
|
|
ptypesinfo -- struc definition with members
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PKNOWNTYPES pknwntyp, pkt;
|
|
|
|
pknwntyp = TypeDefsList->pLastNodeInserted;
|
|
|
|
while (pknwntyp) {
|
|
if (pknwntyp->Size == 0) {
|
|
pkt = GetBasicType(pknwntyp->TypeName, TypeDefsList, StructsList);
|
|
if (pkt && ( ! strcmp(pkt->BasicType, szSTRUCT)) &&
|
|
( ! strcmp(pkt->TypeName, ptypesinfo->TypeName))) {
|
|
pknwntyp->Size = ptypesinfo->Size;
|
|
pknwntyp->iPackSize = ptypesinfo->iPackSize;
|
|
pknwntyp->Flags |= (ptypesinfo->Flags & BTI_CONTAINSFUNCPTR);
|
|
}
|
|
}
|
|
pknwntyp = pknwntyp->Next;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetExistingType(
|
|
PTYPESINFO pTypesInfo,
|
|
PBOOL pbFnPtr,
|
|
PKNOWNTYPES *ppKnownTypes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets an existing type from the lexer stream and returns the type
|
|
information for it.
|
|
|
|
Arguments:
|
|
|
|
pSrc -- IN ptr to start of typename to look up
|
|
pTypesInfo -- Information of
|
|
pbFnPtr -- [OPTIONAL] OUT TRUE if the type is a pointer to a function
|
|
ppKnownTypes-- [OPTIONAL] OUT KnownType infomation for this type if not a function pointer.
|
|
|
|
Return Value:
|
|
|
|
FALSE if the name is not an existing type, or TRUE if the name is an
|
|
existing type (CurrentToken ends up pointing at the token following the
|
|
type).
|
|
|
|
--*/
|
|
{
|
|
PKNOWNTYPES pKnownType;
|
|
int OldCurrentTokenIndex = CurrentTokenIndex;
|
|
|
|
if (bDebug) {
|
|
fputs("GetExisting type called with the following lexer state:\n", stderr);
|
|
DumpLexerOutput(CurrentTokenIndex);
|
|
}
|
|
memset(pTypesInfo, 0, sizeof(TYPESINFO));
|
|
if (pbFnPtr) {
|
|
*pbFnPtr = FALSE;
|
|
}
|
|
|
|
if (ParseStructTypes(pTypesInfo)) {
|
|
if ((pKnownType = AddNewType(pTypesInfo, StructsList)) != NULL) {
|
|
if (ppKnownTypes != NULL) *ppKnownTypes = pKnownType;
|
|
return TRUE;
|
|
} else {
|
|
if (ppKnownTypes != NULL) *ppKnownTypes = NULL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
CurrentTokenIndex = OldCurrentTokenIndex;
|
|
if (pbFnPtr && ParseFuncTypes(pTypesInfo, FALSE)) {
|
|
if (ppKnownTypes != NULL) *ppKnownTypes = NULL;
|
|
*pbFnPtr = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
CurrentTokenIndex = OldCurrentTokenIndex;
|
|
if (ParseTypes(TypeDefsList, pTypesInfo, &pKnownType)) {
|
|
if (ppKnownTypes != NULL) *ppKnownTypes = pKnownType;
|
|
return TRUE;
|
|
}
|
|
|
|
CurrentTokenIndex = OldCurrentTokenIndex;
|
|
if (ParseTypes(StructsList, pTypesInfo, &pKnownType)) {
|
|
if (ppKnownTypes != NULL) *ppKnownTypes = pKnownType;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ParseTypeDefs(
|
|
PTYPESINFO pTypesInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses a C-language statement if it is a 'typedef'. Accepted syntaxes are:
|
|
|
|
typedef <mod> type <indir> NewName<[]> <, <indir> NewName<[]>>
|
|
typedef <mod> struct|enum|union <name> <indir> NewName <, <indir> NewName>
|
|
typedef <mod> rtype <indir>(<modifiers * NewName ) ( <arg List>)
|
|
|
|
(Note that we don't deal with extraneous parens very well)
|
|
|
|
Arguments:
|
|
|
|
pTypesInfo -- OUT ptr to info about the type
|
|
|
|
Return Value:
|
|
|
|
TRUE if the statement is a typedef
|
|
FALSE if the statement is not a typedef or some kind of error
|
|
|
|
--*/
|
|
{
|
|
int IndLevel;
|
|
BOOL bFnPtr = FALSE;
|
|
TYPESINFO TypesInfo;
|
|
DWORD dwSize;
|
|
PKNOWNTYPES pKnownTypes = NULL;
|
|
int i;
|
|
int Flags;
|
|
|
|
memset(pTypesInfo, 0, sizeof(TYPESINFO));
|
|
|
|
if (CurrentToken()->TokenType == TK_DECLSPEC) {
|
|
ConsumeDeclSpecOpt(FALSE, FALSE, NULL, NULL, NULL);
|
|
}
|
|
|
|
if (CurrentToken()->TokenType != TK_TYPEDEF) {
|
|
//
|
|
// Line doesn't start with 'typedef'
|
|
//
|
|
return FALSE;
|
|
}
|
|
ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType == TK_STAR ||
|
|
CurrentToken()->TokenType == TK_BITWISE_AND) {
|
|
//
|
|
// We have something like: 'typedef *foo;'. This happens if a
|
|
// .IDL file has a bogus typedef. MIDL just omits the typename
|
|
// if it isn't recognized. Fake up a TypesInfo for 'int'.
|
|
//
|
|
ConsumeToken();
|
|
bFnPtr = FALSE;
|
|
memset(&TypesInfo, 0, sizeof(TypesInfo));
|
|
strcpy(TypesInfo.BasicType,szINT);
|
|
strcpy(TypesInfo.BaseName,szINT);
|
|
strcpy(TypesInfo.TypeName,szINT);
|
|
TypesInfo.Size = sizeof(int);
|
|
TypesInfo.iPackSize = sizeof(int);
|
|
} else {
|
|
if (IsTokenSeparator() && CurrentToken()->TokenType != TK_LPAREN) {
|
|
//
|
|
// Text after 'typedef' doesn't start with anything plausible.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
ConsumeDeclSpecOpt(FALSE, FALSE, NULL, NULL, NULL);
|
|
ConsumeConstVolatileOpt();
|
|
if (!GetExistingType(&TypesInfo, &bFnPtr, &pKnownTypes)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We now know the type. Parse new type names derived from that type.
|
|
//
|
|
pTypesInfo->IndLevel = TypesInfo.IndLevel;
|
|
pTypesInfo->Flags |= (TypesInfo.Flags & BTI_CONTAINSFUNCPTR);
|
|
pTypesInfo->Flags |= (TypesInfo.Flags & BTI_POINTERDEP);
|
|
pTypesInfo->Flags |= (TypesInfo.Flags & BTI_UNSIGNED);
|
|
pTypesInfo->pTypedefBase = pKnownTypes;
|
|
strcpy(pTypesInfo->BasicType, TypesInfo.BasicType);
|
|
strcpy(pTypesInfo->TypeName, TypesInfo.TypeName);
|
|
|
|
if (bFnPtr) {
|
|
//
|
|
// The type is a pointer to a function
|
|
//
|
|
pTypesInfo->Flags |= BTI_CONTAINSFUNCPTR;
|
|
strcpy(pTypesInfo->BaseName, TypesInfo.BaseName);
|
|
strcpy(pTypesInfo->FuncRet, TypesInfo.FuncRet);
|
|
strcpy(pTypesInfo->FuncMod, TypesInfo.FuncMod);
|
|
pTypesInfo->Size = SIZEOFPOINTER;
|
|
pTypesInfo->iPackSize = SIZEOFPOINTER;
|
|
pTypesInfo->dwMemberSize = TypesInfo.dwMemberSize;
|
|
pTypesInfo->TypeKind = TypesInfo.TypeKind;
|
|
memcpy(pTypesInfo->Members, TypesInfo.Members, sizeof(TypesInfo.Members));
|
|
pTypesInfo->pfuncinfo = RelocateTypesInfo(pTypesInfo->Members,
|
|
&TypesInfo);
|
|
return TRUE;
|
|
}
|
|
|
|
if (CurrentToken()->TokenType == TK_EOS) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(pTypesInfo->BaseName, TypesInfo.TypeName);
|
|
*pTypesInfo->TypeName = '\0';
|
|
|
|
// don't handle extraneous parens.
|
|
i = CurrentTokenIndex;
|
|
while (CurrentToken()->TokenType != TK_EOS) {
|
|
if (CurrentToken()->TokenType == TK_LPAREN) {
|
|
return FALSE;
|
|
}
|
|
ConsumeToken();
|
|
}
|
|
CurrentTokenIndex = i;
|
|
|
|
IndLevel = pTypesInfo->IndLevel;
|
|
Flags = pTypesInfo->Flags;
|
|
|
|
for (;;) {
|
|
pTypesInfo->IndLevel = IndLevel;
|
|
pTypesInfo->iPackSize = TypesInfo.iPackSize;
|
|
pTypesInfo->Flags = Flags;
|
|
dwSize = TypesInfo.Size;
|
|
|
|
//
|
|
// Skip 'const' keyword, if present.
|
|
//
|
|
if (CurrentToken()->TokenType == TK_CONST) {
|
|
ConsumeToken();
|
|
}
|
|
|
|
//
|
|
// Handle pointers to the base type
|
|
//
|
|
if (IsTokenSeparator() &&
|
|
CurrentToken()->TokenType != TK_STAR &&
|
|
CurrentToken()->TokenType != TK_BITWISE_AND) {
|
|
return FALSE;
|
|
}
|
|
ParseIndirection(&pTypesInfo->IndLevel,
|
|
&dwSize,
|
|
&pTypesInfo->Flags,
|
|
NULL,
|
|
NULL);
|
|
|
|
// This is a hack for the busted way that sortpp parses
|
|
// data. New types do not inherit the pointer size
|
|
// properly. We also can't inherit it at the top
|
|
// since this might be a pointer to a pointer. So what
|
|
// we do is try to parse this as a pointer, and if the IndLevel
|
|
// increases we know this is a pointer so do nothing. If the IndLevel
|
|
// doesn't increase, this is not a pointer so inherite the pointer attributes
|
|
// from the parent.
|
|
|
|
ASSERT(pTypesInfo->IndLevel >= IndLevel);
|
|
if (pTypesInfo->IndLevel == IndLevel) {
|
|
// inherite is ptr64 attribute from the base type.
|
|
pTypesInfo->Flags |= (TypesInfo.Flags & BTI_PTR64);
|
|
}
|
|
|
|
if (CurrentToken()->TokenType != TK_IDENTIFIER) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get the name of the new typedef
|
|
//
|
|
if (CopyToken(pTypesInfo->TypeName,
|
|
CurrentToken()->Name,
|
|
sizeof(pTypesInfo->TypeName)-1
|
|
)
|
|
>= sizeof(pTypesInfo->TypeName)) {
|
|
return FALSE;
|
|
}
|
|
ConsumeToken();
|
|
|
|
//
|
|
// Handle an array of the type
|
|
//
|
|
while (CurrentToken()->TokenType == TK_LSQUARE) {
|
|
DWORD dwIndex;
|
|
|
|
if (!GetArrayIndex(&dwIndex)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwIndex == 0) { // a[] is really *a
|
|
pTypesInfo->IndLevel++;
|
|
} else {
|
|
pTypesInfo->Flags |= BTI_ISARRAY;
|
|
pTypesInfo->dwArrayElements = dwIndex;
|
|
pTypesInfo->dwBaseSize = dwSize;
|
|
dwSize = dwSize * dwIndex;
|
|
}
|
|
}
|
|
|
|
if (pTypesInfo->IndLevel) {
|
|
if (pTypesInfo->Flags & BTI_PTR64) {
|
|
pTypesInfo->Size = SIZEOFPOINTER64;
|
|
pTypesInfo->iPackSize = SIZEOFPOINTER64;
|
|
} else {
|
|
pTypesInfo->Size = SIZEOFPOINTER;
|
|
pTypesInfo->iPackSize = SIZEOFPOINTER;
|
|
}
|
|
pTypesInfo->Flags |= BTI_POINTERDEP;
|
|
} else {
|
|
pTypesInfo->Size = dwSize;
|
|
}
|
|
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_EOS:
|
|
return TRUE;
|
|
|
|
case TK_COMMA:
|
|
//
|
|
// There is a list of types derived from the base type
|
|
// Add the current type in and loop to parse the next
|
|
// type.
|
|
//
|
|
if (!AddNewType(pTypesInfo, TypeDefsList)) {
|
|
return FALSE;
|
|
}
|
|
|
|
ConsumeToken(); // consume the ','
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ParseFuncTypes(
|
|
PTYPESINFO pTypesInfo,
|
|
BOOL fDllImport
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses a C-language statement if it is a function declaration:
|
|
|
|
<mod> type <*> <mod> Name ( type <arg1>, type <arg2>, type <argn> )
|
|
<mod> type <*> (<mod> * Name ) ( type <arg1>, type <arg2>, type <argn> )
|
|
(Note that we don't deal with extraneous parens very well, and don't
|
|
handle function pointers as return types.
|
|
e.g. "void (*(*foo)(void))(void);" ).
|
|
|
|
Arguments:
|
|
|
|
pTypesInfo -- OUT ptr to info about the type
|
|
fDllImport -- TRUE if __declspec(dllimport) already consumed
|
|
|
|
Return Value:
|
|
|
|
TRUE if the statement is a function declaration
|
|
FALSE if the statement is not a function declaration or some kind of error
|
|
|
|
--*/
|
|
{
|
|
char *pName;
|
|
char *ps;
|
|
char *pArgName;
|
|
BOOL bFnPtr = FALSE;
|
|
ULONG ArgNum = 0;
|
|
int IndLevel = 0;
|
|
int ArgIndLevel;
|
|
int Len;
|
|
TYPESINFO ti;
|
|
PFUNCINFO pfuncinfo;
|
|
BUFALLOCINFO bufallocinfo;
|
|
int OldTokenIndex;
|
|
char NoNameArg[32];
|
|
PKNOWNTYPES pkt;
|
|
|
|
memset(pTypesInfo, 0, sizeof(TYPESINFO));
|
|
BufAllocInit(&bufallocinfo, pTypesInfo->Members, sizeof(pTypesInfo->Members), 0);
|
|
pfuncinfo = NULL;
|
|
|
|
|
|
if (fDllImport) {
|
|
//
|
|
// Declaration has __declspec(dllimport). Genthnk should emit
|
|
// __declspec(dllexport) in the function definition.
|
|
//
|
|
pTypesInfo->Flags |= BTI_DLLEXPORT;
|
|
}
|
|
|
|
// for functions, the first token is ret type
|
|
if (IsTokenSeparator() && CurrentToken()->TokenType != TK_LPAREN) {
|
|
//
|
|
// First token isn't even an identifier - bail out.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
// There can be multiple __declspec's here - run through them all
|
|
do {
|
|
ConsumeDeclSpecOpt(TRUE, FALSE, &fDllImport, NULL, NULL);
|
|
} while (CurrentToken()->TokenType == TK_DECLSPEC);
|
|
|
|
//
|
|
// Remember the index of the first token which describes the return type.
|
|
//
|
|
OldTokenIndex = CurrentTokenIndex;
|
|
|
|
if (CurrentToken()->TokenType == TK_LPAREN) {
|
|
// This is this start of a typedef (pfn)()
|
|
// where the pfn has an implecit return type of
|
|
// int.
|
|
strcpy(pTypesInfo->FuncRet, "int");
|
|
goto ImplicitReturnType;
|
|
}
|
|
|
|
if (ConsumeDirectionOpt() != TK_NONE && bDebug) {
|
|
// A struct element had a direction on it. Ignore it and
|
|
// warn the user.
|
|
fprintf(stderr, "Warning: IN and OUT are ignored on function return types. %s line %d\n", SourceFileName, StatementLineNumber);
|
|
}
|
|
ConsumeConstVolatileOpt();
|
|
if (!GetExistingType(&ti, NULL, NULL)) {
|
|
ErrMsg("pft.rtype: unknown return type\n");
|
|
DumpLexerOutput(OldTokenIndex);
|
|
return FALSE;
|
|
}
|
|
|
|
// get indir for ret type
|
|
ParseIndirection(&pTypesInfo->RetIndLevel, NULL, NULL, NULL, NULL);
|
|
|
|
// Copy out ret type to FuncRet
|
|
if (!UnlexToText(pTypesInfo->FuncRet, sizeof(pTypesInfo->FuncRet),
|
|
OldTokenIndex, CurrentTokenIndex)) {
|
|
return FALSE;
|
|
}
|
|
|
|
ConsumeDeclSpecOpt(TRUE, FALSE, &fDllImport, NULL, NULL);
|
|
|
|
if (fDllImport) {
|
|
// Declaration has __declspec(dllimport). Genthnk should emit
|
|
// __declspec(dllexport) in the function definition.
|
|
//
|
|
pTypesInfo->Flags |= BTI_DLLEXPORT;
|
|
}
|
|
|
|
|
|
// if open paren, assume a fn pointer
|
|
ImplicitReturnType:
|
|
if (CurrentToken()->TokenType == TK_LPAREN) {
|
|
bFnPtr = TRUE;
|
|
ConsumeToken();
|
|
}
|
|
|
|
// include cdecl, stdcall, save as FuncMod
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_CDECL:
|
|
Len = CopyToken(pTypesInfo->FuncMod, szCDECL, sizeof(pTypesInfo->FuncMod) - 1);
|
|
if (Len >= sizeof(pTypesInfo->FuncMod) - 1) {
|
|
return FALSE;
|
|
}
|
|
ConsumeToken();
|
|
break;
|
|
|
|
case TK_FASTCALL:
|
|
Len = CopyToken(pTypesInfo->FuncMod, sz__FASTCALL, sizeof(pTypesInfo->FuncMod) - 1);
|
|
if (Len >= sizeof(pTypesInfo->FuncMod) - 1) {
|
|
return FALSE;
|
|
}
|
|
ConsumeToken();
|
|
break;
|
|
|
|
case TK_STDCALL:
|
|
Len = CopyToken(pTypesInfo->FuncMod, szSTDCALL, sizeof(pTypesInfo->FuncMod) - 1);
|
|
if (Len >= sizeof(pTypesInfo->FuncMod) - 1) {
|
|
return FALSE;
|
|
}
|
|
ConsumeToken();
|
|
//
|
|
// some funky ole include has:
|
|
// "BOOL (__stdcall __stdcall *pfnContinue)(DWORD)"
|
|
//
|
|
if (CurrentToken()->TokenType == TK_STDCALL) {
|
|
ConsumeToken();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
pTypesInfo->TypeKind = TypeKindFunc;
|
|
pTypesInfo->dwMemberSize = 0;
|
|
|
|
//
|
|
// count indir on function
|
|
//
|
|
if (bFnPtr) {
|
|
while (CurrentToken()->TokenType == TK_STAR ||
|
|
CurrentToken()->TokenType == TK_BITWISE_AND) {
|
|
IndLevel++;
|
|
ConsumeToken();
|
|
}
|
|
}
|
|
|
|
//
|
|
// We expect the next token to be the func name.
|
|
//
|
|
if (CurrentToken()->TokenType != TK_RPAREN &&
|
|
CurrentToken()->TokenType != TK_IDENTIFIER) {
|
|
return FALSE;
|
|
}
|
|
|
|
pName = (bFnPtr && CurrentToken()->TokenType == TK_RPAREN) ? "" : CurrentToken()->Name;
|
|
strcpy(pTypesInfo->BaseName, szFUNC);
|
|
|
|
// look for beg of ArgList
|
|
ConsumeToken();
|
|
if (bFnPtr && CurrentToken()->TokenType == TK_RPAREN) {
|
|
ConsumeToken();
|
|
}
|
|
|
|
if (CurrentToken()->TokenType != TK_LPAREN) {
|
|
return FALSE;
|
|
}
|
|
ConsumeToken(); // consume the '('
|
|
|
|
//
|
|
// copy out the ArgList
|
|
//
|
|
while (CurrentToken()->TokenType != TK_EOS) {
|
|
if (CurrentToken()->TokenType == TK_RPAREN) {
|
|
break;
|
|
}
|
|
|
|
ArgIndLevel = 0;
|
|
|
|
// ([mod] type [mod] [*] [mod] [ArgName] , ...)
|
|
bFnPtr = FALSE;
|
|
|
|
// skip register keywords all together
|
|
if (CurrentToken()->TokenType == TK_REGISTER) {
|
|
ConsumeToken();
|
|
}
|
|
|
|
//
|
|
// Remember where we are in the parse
|
|
//
|
|
OldTokenIndex = CurrentTokenIndex;
|
|
|
|
//
|
|
// Allocate a new FUNCINFO struct for this parameter
|
|
//
|
|
pfuncinfo = AllocFuncInfoAndLink(&bufallocinfo, pfuncinfo);
|
|
if (!pTypesInfo->pfuncinfo) {
|
|
pTypesInfo->pfuncinfo = pfuncinfo;
|
|
}
|
|
|
|
if (CurrentToken()->TokenType == TK_VARGS) {
|
|
ps = BufPointer(&bufallocinfo);
|
|
pfuncinfo->sType = ps;
|
|
strcpy(ps, szVARGS);
|
|
BufAllocate(&bufallocinfo, strlen(szVARGS)+1);
|
|
ConsumeToken();
|
|
break;
|
|
}
|
|
|
|
// grab the IN, OUT, or 'IN OUT', if present
|
|
pfuncinfo->tkDirection = ConsumeDirectionOpt();
|
|
|
|
pfuncinfo->tkPreMod = ConsumeConstVolatileOpt();
|
|
|
|
if (!GetExistingType(&ti, &bFnPtr, &pkt)) {
|
|
ErrMsg("pft.args: unknown argument type at %d\n", OldTokenIndex);
|
|
return FALSE;
|
|
}
|
|
pfuncinfo->pkt = pkt;
|
|
|
|
// enter fp member as a typedef to store args and rettype
|
|
if (bFnPtr) {
|
|
TYPESINFO tiTmp;
|
|
|
|
tiTmp = ti;
|
|
tiTmp.pfuncinfo = RelocateTypesInfo(tiTmp.Members, &ti);
|
|
tiTmp.Flags |= BTI_CONTAINSFUNCPTR;
|
|
|
|
Len = CreatePseudoName(tiTmp.TypeName, ti.TypeName);
|
|
if (!Len) {
|
|
return FALSE;
|
|
}
|
|
|
|
pkt = AddNewType(&tiTmp, TypeDefsList);
|
|
if (NULL == pkt) {
|
|
return FALSE;
|
|
}
|
|
|
|
ps = BufPointer(&bufallocinfo);
|
|
pfuncinfo->sType = ps;
|
|
strcpy(ps, tiTmp.TypeName);
|
|
BufAllocate(&bufallocinfo, strlen(ps)+1);
|
|
|
|
pArgName = ti.TypeName;
|
|
goto aftername;
|
|
} else {
|
|
|
|
DWORD Flags = 0;
|
|
|
|
// skip indirection
|
|
ParseIndirection(&pfuncinfo->IndLevel,
|
|
NULL,
|
|
&Flags,
|
|
&pfuncinfo->tkPrePostMod,
|
|
&pfuncinfo->tkPostMod
|
|
);
|
|
|
|
if (Flags & BTI_PTR64) {
|
|
pfuncinfo->fIsPtr64 = TRUE;
|
|
}
|
|
|
|
ps = BufPointer(&bufallocinfo);
|
|
pfuncinfo->sType = ps;
|
|
strcpy(ps, ti.TypeName);
|
|
BufAllocate(&bufallocinfo, strlen(ps)+1);
|
|
|
|
//
|
|
// If the type of the parameter has an explicit
|
|
// struct/union/enum keyword, pass that info on to
|
|
// genthnk. ie. if the parameter type is like
|
|
// 'struct typename argname', set tkSUE to TK_STRUCT.
|
|
//
|
|
if (strcmp(ti.BaseName, szSTRUCT) == 0) {
|
|
pfuncinfo->tkSUE = TK_STRUCT;
|
|
} else if (strcmp(ti.BaseName, szUNION) == 0) {
|
|
pfuncinfo->tkSUE = TK_UNION;
|
|
} else if (strcmp(ti.BaseName, szENUM) == 0) {
|
|
pfuncinfo->tkSUE = TK_ENUM;
|
|
} else {
|
|
pfuncinfo->tkSUE = TK_NONE;
|
|
}
|
|
}
|
|
|
|
// if no argument name present, create one
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_RPAREN:
|
|
case TK_LSQUARE:
|
|
case TK_COMMA:
|
|
// but null arg list doesn't have any name
|
|
if (CurrentToken()->TokenType == TK_COMMA ||
|
|
ArgNum ||
|
|
ti.IndLevel ||
|
|
pfuncinfo->IndLevel ||
|
|
strcmp(ti.BasicType, szVOID) ) {
|
|
|
|
pArgName = NoNameArg;
|
|
sprintf(NoNameArg, "_noname%x", ArgNum++);
|
|
} else {
|
|
pArgName = NULL;
|
|
}
|
|
break;
|
|
|
|
case TK_IDENTIFIER:
|
|
pArgName = CurrentToken()->Name;
|
|
if (ArgNum == 0 &&
|
|
pfuncinfo->IndLevel == 1 &&
|
|
strcmp(pArgName, "This") == 0) {
|
|
//
|
|
// This is the first arg and it is a pointer with name 'This'.
|
|
// Assume it is a MIDL-generated proxy prototype.
|
|
//
|
|
pfuncinfo->tkDirection = TK_IN;
|
|
}
|
|
ConsumeToken();
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
aftername:
|
|
if (pArgName) {
|
|
//
|
|
// Copy the argument name from pArgName into pfuncinfo->sName.
|
|
//
|
|
ps = BufPointer(&bufallocinfo);
|
|
pfuncinfo->sName = ps;
|
|
strcpy(ps, pArgName);
|
|
}
|
|
|
|
//
|
|
// Handle parameter which is a single-dimension array by copying the
|
|
// entire string from '[' to ']' (inclusive)
|
|
// ie. int foo(int i[3])
|
|
//
|
|
if (CurrentToken()->TokenType == TK_LSQUARE) {
|
|
int OldCurrentTokenIndex = CurrentTokenIndex;
|
|
int ArgNameLen = strlen(ps);
|
|
|
|
do {
|
|
ConsumeToken();
|
|
} while (CurrentToken()->TokenType != TK_RSQUARE &&
|
|
CurrentToken()->TokenType != TK_EOS);
|
|
|
|
if (CurrentToken()->TokenType == TK_EOS) {
|
|
// Reject - unmatched '[' and ']'
|
|
return FALSE;
|
|
}
|
|
// if (CurrentTokenIndex - OldCurrentTokenIndex == 1) {
|
|
//
|
|
// Found: empty array bounds '[]'. Bump IndLevel and
|
|
// don't append the '[]' to the parameter name.
|
|
//
|
|
pfuncinfo->IndLevel++;
|
|
// } else if (!UnlexToText(ps + ArgNameLen,
|
|
// BufGetFreeSpace(&bufallocinfo) - ArgNameLen,
|
|
// OldCurrentTokenIndex,
|
|
// CurrentTokenIndex+1)) {
|
|
// ErrMsg("pft: args list too long\n");
|
|
// return FALSE;
|
|
// }
|
|
ConsumeToken();
|
|
}
|
|
BufAllocate(&bufallocinfo, strlen(ps)+1);
|
|
|
|
//bug bug , hack hack, danger danger
|
|
if (CurrentToken()->TokenType == TK_ASSIGN) {
|
|
//Header is using the C++ syntax of assigning
|
|
//a default value to a argument.
|
|
//This will be skipped. Skip until a TK_COMMA, TK_EOS, TK_RPAREN
|
|
ConsumeToken();
|
|
|
|
while(CurrentToken()->TokenType != TK_COMMA &&
|
|
CurrentToken()->TokenType != TK_EOS &&
|
|
CurrentToken()->TokenType != TK_RPAREN) {
|
|
ConsumeToken();
|
|
}
|
|
}
|
|
|
|
if (CurrentToken()->TokenType == TK_RPAREN) {
|
|
break;
|
|
} else { // more args to go, add comma delimiter
|
|
ConsumeToken();
|
|
}
|
|
}
|
|
|
|
if (CurrentToken()->TokenType != TK_RPAREN) {
|
|
ErrMsg("pft: unknown syntax for fn args\n");
|
|
return FALSE;
|
|
}
|
|
|
|
ConsumeToken(); // consume the ')'
|
|
|
|
pTypesInfo->IndLevel = IndLevel;
|
|
pTypesInfo->Size = 4;
|
|
pTypesInfo->iPackSize = 4;
|
|
strcpy(pTypesInfo->BasicType, szFUNC);
|
|
if (CopyToken(pTypesInfo->TypeName,
|
|
pName,
|
|
sizeof(pTypesInfo->TypeName)-1
|
|
)
|
|
>= sizeof(pTypesInfo->TypeName) ) {
|
|
return FALSE;
|
|
}
|
|
if (pfuncinfo == NULL) {
|
|
//
|
|
// No args encountered - create VOID args now
|
|
//
|
|
pfuncinfo = AllocFuncInfoAndLink(&bufallocinfo, pfuncinfo);
|
|
ps = BufPointer(&bufallocinfo);
|
|
strcpy(ps, szVOID);
|
|
pfuncinfo->sType = ps;
|
|
BufAllocate(&bufallocinfo, strlen(ps)+1);
|
|
pTypesInfo->pfuncinfo = pfuncinfo;
|
|
}
|
|
pTypesInfo->dwMemberSize = bufallocinfo.dwLen;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
ParseStructTypes(
|
|
PTYPESINFO pTypesInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses a C-language statement if it is struct/union/enum declaration.
|
|
|
|
struct|union|enum NewName <{}>
|
|
struct NewName : <permission> BaseName <{}>
|
|
(Note that we don't deal with extraneous parens very well)
|
|
|
|
|
|
Arguments:
|
|
|
|
pTypesInfo -- OUT ptr to info about the type
|
|
|
|
Return Value:
|
|
|
|
TRUE if the statement is a struct/union/enum
|
|
FALSE if the statement is not a s/u/e, or some other error
|
|
|
|
--*/
|
|
{
|
|
TOKENTYPE FirstToken;
|
|
BOOL bEnum = FALSE;
|
|
BOOL bUnion = FALSE;
|
|
DWORD dwOldScopeLevel = dwScopeLevel;
|
|
BOOL IsGuidDefined = FALSE;
|
|
|
|
memset(pTypesInfo, 0, sizeof(TYPESINFO));
|
|
|
|
//
|
|
// Match one of: STRUCT, UNION, or ENUM
|
|
//
|
|
FirstToken = CurrentToken()->TokenType;
|
|
switch (FirstToken) {
|
|
case TK_STRUCT:
|
|
break;
|
|
|
|
case TK_UNION:
|
|
bUnion = TRUE;
|
|
break;
|
|
|
|
case TK_ENUM:
|
|
bEnum = TRUE;
|
|
break;
|
|
|
|
default:
|
|
goto retfail; // no match
|
|
}
|
|
ConsumeToken();
|
|
|
|
// BasicType is "struct", "union", or "enum"
|
|
if (CopyToken(pTypesInfo->BasicType,
|
|
TokenString[FirstToken],
|
|
sizeof(pTypesInfo->BasicType)-1
|
|
)
|
|
>= sizeof(pTypesInfo->BasicType) ) {
|
|
goto retfail;
|
|
}
|
|
strcpy(pTypesInfo->BaseName, pTypesInfo->BasicType);
|
|
|
|
//handle declspecs
|
|
if (!bUnion && !bEnum) {
|
|
while(ConsumeDeclSpecOpt(FALSE, FALSE, NULL, &IsGuidDefined, &(pTypesInfo->gGuid)));
|
|
if (IsGuidDefined) pTypesInfo->Flags |= BTI_HASGUID;
|
|
}
|
|
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_IDENTIFIER:
|
|
{
|
|
if (CopyToken(pTypesInfo->TypeName,
|
|
CurrentToken()->Name,
|
|
sizeof(pTypesInfo->BasicType)-1
|
|
)
|
|
>= sizeof(pTypesInfo->BasicType) ) {
|
|
goto retfail;
|
|
}
|
|
ConsumeToken();
|
|
break;
|
|
}
|
|
|
|
case TK_LBRACE: // anonymous struct/union/enum
|
|
if (!CreatePseudoName(pTypesInfo->TypeName, TokenString[FirstToken])) {
|
|
//
|
|
// call failed - probably buffer overflow
|
|
//
|
|
goto retfail;
|
|
}
|
|
pTypesInfo->Flags |= BTI_ANONYMOUS;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// STRUCT/UNION/ENUM followed by something other than an identifier
|
|
// or a '{'.
|
|
//
|
|
goto retfail;
|
|
}
|
|
|
|
//
|
|
// Process the contents of the curly braces, if present.
|
|
//
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_EOS:
|
|
goto retsuccess;
|
|
|
|
case TK_LBRACE:
|
|
{
|
|
if (bEnum) {
|
|
if(CopyEnumMembers(pTypesInfo)) goto retsuccess;
|
|
else goto retfail;
|
|
}
|
|
if(CopyStructMembers(pTypesInfo, bUnion, NULL)) goto retsuccess;
|
|
else goto retfail;
|
|
|
|
}
|
|
case TK_COLON: //entering a derived struct
|
|
if (bEnum || bUnion) goto retfail;
|
|
ConsumeToken();
|
|
//look for base skipping public, private, and protected
|
|
{
|
|
PTOKEN pToken;
|
|
BOOL bRetVal;
|
|
PTYPEINFOELEMENT pMemFuncs;
|
|
PKNOWNTYPES BaseType;
|
|
|
|
pToken = CurrentToken();
|
|
|
|
if (pToken->TokenType != TK_IDENTIFIER) goto retfail;
|
|
if (strcmp(pToken->Name, "public") == 0 ||
|
|
strcmp(pToken->Name, "private") == 0 ||
|
|
strcmp(pToken->Name, "protected") == 0) {
|
|
ConsumeToken();
|
|
}
|
|
//look for base
|
|
if (CopyToken(pTypesInfo->BaseType,
|
|
CurrentToken()->Name,
|
|
sizeof(pTypesInfo->BasicType)-1
|
|
)
|
|
>= sizeof(pTypesInfo->BasicType) ) {
|
|
goto retfail;
|
|
}
|
|
|
|
//lookup the base in structures
|
|
BaseType = GetNameFromTypesList(StructsList,pTypesInfo->BaseType);
|
|
if (NULL == BaseType) {
|
|
//ErrMsg("Base type is unknown or not a structure\n");
|
|
goto retfail;
|
|
}
|
|
|
|
//look for opening brace or EOS
|
|
ConsumeToken();
|
|
if (CurrentToken()->TokenType == TK_EOS) goto retsuccess;
|
|
if (CurrentToken()->TokenType != TK_LBRACE) goto retfail;
|
|
if (CopyStructMembers(pTypesInfo, FALSE, BaseType)) goto retsuccess;
|
|
else goto retfail;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
goto retsuccess;
|
|
retfail:
|
|
dwScopeLevel = dwOldScopeLevel;
|
|
return FALSE;
|
|
retsuccess:
|
|
dwScopeLevel = dwOldScopeLevel;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CopyEnumMembers(
|
|
PTYPESINFO pTypesInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scans over members of an enumeration declaration. Nobody cares
|
|
about the actual names and values, so they are simply skipped over
|
|
until the matching '}' is found.
|
|
|
|
Arguments:
|
|
|
|
pTypesInfo -- OUT ptr to info about the type
|
|
|
|
Return Value:
|
|
|
|
TRUE if the declaration is parsed OK
|
|
FALSE if the statement is mis-parsed, or some other error
|
|
|
|
--*/
|
|
{
|
|
DWORD *pdwSize = &(pTypesInfo->Size);
|
|
DWORD *pdwPackSize = &(pTypesInfo->iPackSize);
|
|
dwScopeLevel++;
|
|
|
|
if (CurrentToken()->TokenType != TK_LBRACE) {
|
|
return FALSE;
|
|
} else {
|
|
ConsumeToken();
|
|
}
|
|
|
|
//
|
|
// Find the '}' which ends the enumeration declaration
|
|
//
|
|
while (CurrentToken()->TokenType != TK_RBRACE) {
|
|
ConsumeToken();
|
|
}
|
|
ConsumeToken(); // consume the '}', too
|
|
|
|
*pdwSize = sizeof(int); // enum
|
|
*pdwPackSize = sizeof(int); // enum
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// How sortpp computes packing sizes:
|
|
//
|
|
// * Each member has a packing size which is
|
|
// - size of a appropriate pointer if member is a pointer
|
|
// - packing size of its base type
|
|
// * The packing size of struc or union is min(packing_size_of_largest_member,
|
|
// current_packing_size_when_struct_defined)
|
|
// * Each member in a struct is aligned according to min(current_packing_size,
|
|
// member_packing_size).
|
|
// * All pointers have size sizeof(void *) except __ptr64 pointers which
|
|
// have a size sizeof(PVOID64)
|
|
// * bit fields are coallessed until
|
|
// - the end of the struct
|
|
// - a non bit field member
|
|
// - a bit field member, but of different base type size
|
|
// * char s[] as the last member of a struct adds nothing to the size of the
|
|
// struct and should not be aligned.
|
|
// * each member of a union is packed at offset 0.
|
|
|
|
|
|
BOOL
|
|
pCopyStructMembers(
|
|
PTYPESINFO pTypesInfo,
|
|
BOOL bUnion,
|
|
PTYPEINFOELEMENT * ppMemberFuncs,
|
|
DWORD Size,
|
|
DWORD iPackSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copies out struct members, verifying type of each member.
|
|
|
|
{ [mod] type [*] varname; [mod] type [*] varname; ...}
|
|
{ {varname, varname, ...}
|
|
|
|
Assumes CurrentToken points at the '{' for the member list.
|
|
Also determines the size of the struct/union.
|
|
|
|
Arguments:
|
|
|
|
pTypesInfo -- OUT ptr to info about the type
|
|
bUnion -- TRUE if parsing union, FALSE if parsing STRUCT.
|
|
ppMemberFuncs -- OUT returns a list of virtual member functions or NULL.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the declaration is parsed OK
|
|
FALSE if the statement is mis-parsed, or some other error
|
|
|
|
--*/
|
|
{
|
|
char *psMemBuf = pTypesInfo->Members;
|
|
DWORD *pdwSize = &(pTypesInfo->Size);
|
|
DWORD *pdwPackSize = &(pTypesInfo->iPackSize);
|
|
int Len;
|
|
BOOL bFnPtr;
|
|
TYPESINFO ti;
|
|
DWORD dw;
|
|
DWORD dwBase; // running size of struct element
|
|
DWORD dwElemSize; // size of a particular element
|
|
DWORD dwBaseTypeSize; // size of basic type of element
|
|
DWORD dwBits; // # bits in a bitfield element
|
|
DWORD dwBitsTotal; // running # bits for string of elemnts
|
|
DWORD dwBitsTypeSize; // bit fields base type size
|
|
BOOL bForceOutBits = FALSE;
|
|
BOOL bTailPointer = FALSE;
|
|
DWORD dwLastPackSize = 0;
|
|
DWORD dwLastSize = 0;
|
|
PMEMBERINFO pmeminfo;
|
|
BUFALLOCINFO bufallocinfo;
|
|
char *ps;
|
|
DWORD Flags;
|
|
DWORD dwIndex;
|
|
int ParenDepth = 0;
|
|
|
|
PTYPEINFOELEMENT pMethods = NULL;
|
|
DWORD dwMethodNumber = 0;
|
|
|
|
PKNOWNTYPES pkt;
|
|
|
|
if (ppMemberFuncs != NULL) *ppMemberFuncs = NULL;
|
|
|
|
*pdwSize = Size; // initialize size of structure
|
|
*pdwPackSize = iPackSize; // initialize packing alignment
|
|
dwLastSize = Size;
|
|
dwLastPackSize = iPackSize;
|
|
|
|
BufAllocInit(&bufallocinfo, psMemBuf, sizeof(pTypesInfo->Members), 0);
|
|
pmeminfo = NULL;
|
|
|
|
pTypesInfo->TypeKind = TypeKindStruct;
|
|
pTypesInfo->dwMemberSize = 0;
|
|
bFnPtr = FALSE;
|
|
|
|
// loop over members of the structure or union
|
|
|
|
dwBitsTotal = 0;
|
|
dwBitsTypeSize = 0;
|
|
|
|
if (CurrentToken()->TokenType != TK_LBRACE) {
|
|
return FALSE;
|
|
}
|
|
ConsumeToken();
|
|
|
|
while (CurrentToken()->TokenType != TK_RBRACE) {
|
|
int OldCurrentTokenIndex = CurrentTokenIndex;
|
|
|
|
if (bDebug)
|
|
DumpLexerOutput(CurrentTokenIndex);
|
|
|
|
//strip off permission attributes
|
|
//{public private protected} :
|
|
while(CurrentToken()->TokenType == TK_IDENTIFIER &&
|
|
(strcmp(CurrentToken()->Name, "public") == 0 ||
|
|
strcmp(CurrentToken()->Name, "private") == 0 ||
|
|
strcmp(CurrentToken()->Name, "protected") == 0
|
|
))
|
|
{
|
|
ConsumeToken();
|
|
if (CurrentToken()->TokenType != TK_COLON) return FALSE;
|
|
ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType == TK_RBRACE) goto done;
|
|
}
|
|
|
|
if (!bUnion &&
|
|
ppMemberFuncs != NULL &&
|
|
CurrentToken()->TokenType == TK_IDENTIFIER &&
|
|
strcmp(CurrentToken()->Name, "virtual") == 0) {
|
|
|
|
PTYPESINFO pFuncInfo;
|
|
int TokenNumber = CurrentTokenIndex;
|
|
ConsumeConstVolatileOpt();
|
|
|
|
pFuncInfo = GenHeapAlloc(sizeof(TYPESINFO));
|
|
if (pFuncInfo == NULL) ExitErrMsg(FALSE, "Out of memory!\n");
|
|
ConsumeToken();
|
|
|
|
//virtual method
|
|
if (!ParseFuncTypes(pFuncInfo, FALSE)) {
|
|
ErrMsg("Unable to parse method %u of %s\n", dwMethodNumber, pTypesInfo->TypeName);
|
|
DumpLexerOutput(TokenNumber);
|
|
return FALSE;
|
|
}
|
|
|
|
pMethods = TypeInfoElementAllocateLink(ppMemberFuncs, pMethods, pFuncInfo);
|
|
|
|
//remove extra ;
|
|
if (CurrentToken()->TokenType == TK_SEMI)
|
|
ConsumeToken();
|
|
//remove extra = 0;
|
|
else if (CurrentToken()->TokenType == TK_ASSIGN) {
|
|
ConsumeToken();
|
|
//parsing 0;
|
|
if (!(CurrentToken()->TokenType == TK_NUMBER &&
|
|
CurrentToken()->Value == 0)) return FALSE;
|
|
ConsumeToken();
|
|
//parsing ;
|
|
if (CurrentToken()->TokenType != TK_SEMI) return FALSE;
|
|
ConsumeToken();
|
|
}
|
|
else return FALSE; //fail
|
|
|
|
dwMethodNumber++;
|
|
continue;
|
|
}
|
|
|
|
|
|
if (ConsumeDirectionOpt() != TK_NONE && bDebug) {
|
|
// A struct element had a direction on it. Ignore it and
|
|
// warn the user.
|
|
fprintf(stderr, "Warning: IN and OUT are ignored on struct members. %s line %d\n", SourceFileName, StatementLineNumber);
|
|
}
|
|
|
|
ConsumeConstVolatileOpt();
|
|
|
|
pmeminfo = AllocMemInfoAndLink(&bufallocinfo, pmeminfo);
|
|
if (pmeminfo == NULL) {
|
|
ErrMsg("CopyStructMembers: No memberinfo\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetExistingType(&ti, &bFnPtr, &pkt)) {
|
|
ErrMsg("csm: unknown Type %d\n", OldCurrentTokenIndex);
|
|
return FALSE;
|
|
}
|
|
pmeminfo->pkt = pkt;
|
|
|
|
// enter function pointer member as a typedef to store args, rettype
|
|
if (bFnPtr) {
|
|
TYPESINFO tiTmp;
|
|
|
|
ti.Flags |= BTI_CONTAINSFUNCPTR;
|
|
tiTmp = ti;
|
|
tiTmp.pfuncinfo = RelocateTypesInfo(tiTmp.Members, &ti);
|
|
|
|
Len = CreatePseudoName(tiTmp.TypeName, ti.TypeName);
|
|
if (!Len) {
|
|
return FALSE;
|
|
}
|
|
tiTmp.Size = ti.Size;
|
|
tiTmp.iPackSize = ti.iPackSize;
|
|
|
|
pkt = AddNewType(&tiTmp, TypeDefsList);
|
|
if (NULL == pkt) {
|
|
return FALSE;
|
|
}
|
|
ps = BufPointer(&bufallocinfo);
|
|
pmeminfo->sName = ps;
|
|
strcpy(ps, ti.TypeName);
|
|
BufAllocate(&bufallocinfo, strlen(ps)+1);
|
|
pmeminfo->pkt = pkt;
|
|
}
|
|
/*else {
|
|
////////////////////////////////////////////////////////////////
|
|
//This type has no members for it, do no process further.
|
|
/////////////////////////////////////////////////////////////////
|
|
if (CurrentToken()->TokenType == TK_SEMI) {
|
|
ConsumeToken();
|
|
continue;
|
|
}
|
|
}*/
|
|
//
|
|
// If the member contains a function pointer, then mark
|
|
// this struct has containing a function pointer
|
|
// Also mark if member is pointer dependent.
|
|
|
|
pTypesInfo->Flags |= ((ti.Flags & BTI_CONTAINSFUNCPTR) | (ti.Flags & BTI_POINTERDEP));
|
|
|
|
//
|
|
// Union arm initialization
|
|
dwBaseTypeSize = ti.iPackSize;
|
|
|
|
if ((dwBitsTotal > 0) && (dwBaseTypeSize != dwBitsTypeSize)) {
|
|
//
|
|
// Determine size of bitfields
|
|
//
|
|
dw = (dwBitsTotal + ((dwBitsTypeSize*8)-1)) / (dwBitsTypeSize*8);
|
|
*pdwSize = *pdwSize + PackPackingSize(bUnion ? 0 : *pdwSize,
|
|
dw*dwBitsTypeSize,
|
|
dwBitsTypeSize);
|
|
dwBitsTotal = 0;
|
|
}
|
|
dwBitsTypeSize = dwBaseTypeSize;
|
|
|
|
// element initialization
|
|
dwBase = ti.Size;
|
|
dwBits = 0;
|
|
|
|
bTailPointer = FALSE;
|
|
|
|
pmeminfo->dwOffset = bUnion ? 0 : *pdwSize +
|
|
PackPaddingSize(*pdwSize,
|
|
dwBaseTypeSize);
|
|
|
|
//
|
|
// Copy in the typename
|
|
//
|
|
ps = BufPointer(&bufallocinfo);
|
|
pmeminfo->sType = ps;
|
|
strcpy(ps, ti.TypeName);
|
|
BufAllocate(&bufallocinfo, strlen(ps)+1);
|
|
|
|
//
|
|
// Skip just past the terminating ';' for this member and
|
|
// figure out any size modifers to size of the base type.
|
|
//
|
|
while (CurrentToken()->TokenType != TK_SEMI) {
|
|
|
|
PMEMBERINFO pmeminfoNew;
|
|
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_CONST:
|
|
case TK_VOLATILE:
|
|
ConsumeToken();
|
|
break;
|
|
|
|
case TK_COMMA: // comma-separated list
|
|
|
|
// update structure packing value
|
|
if (dwBaseTypeSize > *pdwPackSize) {
|
|
*pdwPackSize = dwBaseTypeSize;
|
|
}
|
|
|
|
// flush out any bit fields not accounted for
|
|
if ((dwBitsTotal > 0) && (dwBits == 0)) {
|
|
dw = (dwBitsTotal + ((dwBitsTypeSize*8)-1)) /
|
|
(dwBitsTypeSize*8);
|
|
dwElemSize = PackPackingSize(bUnion ? 0 : *pdwSize,
|
|
dw*dwBitsTypeSize, dwBitsTypeSize);
|
|
BumpStructUnionSize(pdwSize, dwElemSize, bUnion);
|
|
dwBitsTotal = 0;
|
|
// recompute offset
|
|
pmeminfo->dwOffset = bUnion ? 0 : *pdwSize +
|
|
PackPaddingSize(*pdwSize,
|
|
dwBaseTypeSize);
|
|
}
|
|
|
|
// account for member just completed
|
|
if (dwBits == 0) {
|
|
dwElemSize = PackPackingSize(bUnion ? 0 : *pdwSize,
|
|
dwBase,
|
|
dwBaseTypeSize);
|
|
BumpStructUnionSize(pdwSize, dwElemSize, bUnion);
|
|
dwBase = dwBaseTypeSize;
|
|
}
|
|
|
|
// update bit field count
|
|
dwBitsTotal = dwBitsTotal + dwBits;
|
|
dwBits = 0;
|
|
|
|
// reset tail pointer flag
|
|
bTailPointer = FALSE;
|
|
|
|
// allocate space for new structure member and init it
|
|
pmeminfoNew = AllocMemInfoAndLink(&bufallocinfo, pmeminfo);
|
|
if (pmeminfoNew == NULL) {
|
|
ErrMsg("CopyStructMembers: No memberinfo\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Copy over type information from previous meminfo.
|
|
pmeminfoNew->sType = pmeminfo->sType;
|
|
pmeminfoNew->pkt = pmeminfo->pkt;
|
|
pmeminfo = pmeminfoNew;
|
|
|
|
pmeminfo->dwOffset = bUnion ? 0 : *pdwSize +
|
|
PackPaddingSize(*pdwSize,
|
|
dwBaseTypeSize);
|
|
ConsumeToken();
|
|
break;
|
|
|
|
case TK_STAR:
|
|
case TK_BITWISE_AND:
|
|
Flags = 0;
|
|
ParseIndirection(&pmeminfo->IndLevel, NULL, &Flags, NULL, NULL);
|
|
if (Flags & BTI_PTR64) {
|
|
pmeminfo->bIsPtr64 = TRUE;
|
|
dwBase = SIZEOFPOINTER64;
|
|
} else {
|
|
dwBase = SIZEOFPOINTER;
|
|
}
|
|
// If a pointer is present, mark as being pointer dependent.
|
|
if (pmeminfo->IndLevel > 0) pTypesInfo->Flags |= BTI_POINTERDEP;
|
|
dwBaseTypeSize = dwBase;
|
|
if (*pdwPackSize < dwBase) {
|
|
*pdwPackSize = dwBase;
|
|
}
|
|
pmeminfo->dwOffset = bUnion ? 0 : *pdwSize +
|
|
PackPaddingSize(*pdwSize,
|
|
dwBaseTypeSize);
|
|
break;
|
|
|
|
case TK_LSQUARE: // array declaration
|
|
|
|
if (!GetArrayIndex(&dwIndex)) {
|
|
return FALSE;
|
|
}
|
|
if (dwIndex == 0) { // a[] is really *a
|
|
bTailPointer = TRUE;
|
|
dwLastPackSize = *pdwPackSize;
|
|
dwLastSize = *pdwSize;
|
|
dwBase = SIZEOFPOINTER;
|
|
dwBaseTypeSize = SIZEOFPOINTER;
|
|
pmeminfo->dwOffset = bUnion ? 0 : *pdwSize +
|
|
PackPaddingSize(*pdwSize,
|
|
dwBaseTypeSize);
|
|
} else {
|
|
pmeminfo->bIsArray = TRUE;
|
|
pmeminfo->ArrayElements = dwIndex;
|
|
dwBase = dwBase * dwIndex;
|
|
}
|
|
break;
|
|
|
|
case TK_COLON: // bit field
|
|
ConsumeToken(); // consume the ':'
|
|
|
|
if (CurrentToken()->TokenType != TK_NUMBER) {
|
|
return FALSE;
|
|
}
|
|
|
|
dwBits = (DWORD)CurrentToken()->Value;
|
|
ConsumeToken(); // consume the TK_NUMBER
|
|
pmeminfo->bIsBitfield = TRUE;
|
|
pmeminfo->BitsRequired = (int)dwBits;
|
|
break;
|
|
|
|
case TK_IDENTIFIER:
|
|
ps = BufPointer(&bufallocinfo);
|
|
pmeminfo->sName = ps;
|
|
CopyToken(ps, CurrentToken()->Name, MAX_PATH);
|
|
|
|
if (!BufAllocate(&bufallocinfo, strlen(ps)+1)) {
|
|
ErrMsg("csm.members: BufAllocate failed\n");
|
|
return FALSE;
|
|
}
|
|
ConsumeToken();
|
|
break;
|
|
|
|
case TK_LPAREN:
|
|
//
|
|
// windows\inc\wingdip.h has a type named GDICALL, which
|
|
// has a member in it with the following declaration:
|
|
// WCHAR (*pDest)[MAX_PATH];
|
|
// We are just going to skip the parens and assume all is OK.
|
|
//
|
|
ParenDepth++;
|
|
ConsumeToken();
|
|
break;
|
|
|
|
case TK_RPAREN:
|
|
ParenDepth--;
|
|
ConsumeToken();
|
|
break;
|
|
|
|
default:
|
|
ErrMsg("csm.members: unknown type (%d)\n", (int)CurrentToken()->TokenType);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
// hit ; at end of a members list
|
|
if (ParenDepth) {
|
|
ErrMsg("csm.members: mismatched parentheses at index %d\n", CurrentTokenIndex);
|
|
return FALSE;
|
|
}
|
|
|
|
// update struct packing size to that of largest member
|
|
if (dwBaseTypeSize > *pdwPackSize) {
|
|
*pdwPackSize = dwBaseTypeSize;
|
|
}
|
|
|
|
ConsumeToken(); // consume the ';'
|
|
|
|
if ((bUnion) || (CurrentToken()->TokenType == TK_SEMI)) {
|
|
dwBitsTotal = dwBitsTotal + dwBits;
|
|
bForceOutBits = TRUE;
|
|
// always force out bits in union arm
|
|
} // or at end of structure
|
|
|
|
// flush out any bit fields not accounted for
|
|
if ( (dwBitsTotal > 0) && ( (dwBits == 0) || bForceOutBits) ) {
|
|
dw = (dwBitsTotal + ((dwBitsTypeSize*8)-1)) / (dwBitsTypeSize*8);
|
|
dwElemSize = PackPackingSize(bUnion ? 0 : *pdwSize,
|
|
dw*dwBitsTypeSize, dwBitsTypeSize);
|
|
BumpStructUnionSize(pdwSize, dwElemSize, bUnion);
|
|
dwBitsTotal = 0;
|
|
// recompute offset
|
|
pmeminfo->dwOffset = bUnion ? 0 : *pdwSize +
|
|
PackPaddingSize(*pdwSize,
|
|
dwBaseTypeSize);
|
|
}
|
|
|
|
// account for member just completed
|
|
if (dwBits == 0) { // add in last non bit fields
|
|
dwElemSize = PackPackingSize(bUnion ? 0 : *pdwSize,
|
|
dwBase, dwBaseTypeSize);
|
|
BumpStructUnionSize(pdwSize, dwElemSize, bUnion);
|
|
}
|
|
|
|
// update bit field counter
|
|
dwBitsTotal = dwBitsTotal + dwBits;
|
|
dwBits = 0;
|
|
|
|
}
|
|
|
|
done:
|
|
// Advance past the '}'
|
|
if ((CurrentToken()->TokenType == TK_RBRACE)) {
|
|
ConsumeToken();
|
|
}
|
|
|
|
// if last member was something like foo[] then we roll back the size
|
|
if ((bTailPointer) && (*pdwSize != 4)) {
|
|
*pdwSize = dwLastSize;
|
|
*pdwPackSize = dwLastPackSize;
|
|
pmeminfo->dwOffset = dwLastSize;
|
|
}
|
|
|
|
// pack overall structure on it packing size
|
|
dwBaseTypeSize = PackCurrentPacking() < *pdwPackSize ?
|
|
PackCurrentPacking() : *pdwPackSize;
|
|
if (*pdwSize != 0) { // round up to min(packing level,4)
|
|
dwBase = *pdwSize % dwBaseTypeSize;
|
|
if (dwBase != 0) {
|
|
*pdwSize = *pdwSize + (dwBaseTypeSize - dwBase);
|
|
}
|
|
}
|
|
|
|
*pdwPackSize = dwBaseTypeSize;
|
|
pTypesInfo->dwMemberSize = bufallocinfo.dwLen;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PMEMBERINFO
|
|
CatMeminfo(
|
|
BUFALLOCINFO *pBufallocinfo,
|
|
PMEMBERINFO pHead,
|
|
PMEMBERINFO pTail,
|
|
DWORD dwOffset,
|
|
BOOL bStatus
|
|
)
|
|
{
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Concatinates the member info lists pointed to by pHead and pTail and
|
|
copies them to the memory controled by the BUFALLOCINFO. dwOffset is
|
|
added to the offset for each of the members of the tail list.
|
|
|
|
Arguments:
|
|
|
|
pBufallocinfo -- [IN] ptr to buffer that represents the destination.
|
|
pHead -- [IN] ptr to the head list.
|
|
pTail -- [IN] ptr to the tail list.
|
|
dwOffset -- [IN] amount to add to the offset of elements in the tail.
|
|
bStatus -- [IN] Should be FALSE on initial call.
|
|
|
|
Return Value:
|
|
|
|
Head of the new list.
|
|
|
|
--*/
|
|
|
|
PMEMBERINFO pThis;
|
|
char *pName, *pType;
|
|
|
|
if (!bStatus && NULL == pHead) {
|
|
pHead = pTail;
|
|
bStatus = TRUE;
|
|
}
|
|
|
|
if (NULL == pHead) return NULL;
|
|
|
|
pThis = (PMEMBERINFO)BufAllocate(pBufallocinfo, sizeof(MEMBERINFO));
|
|
if (NULL == pThis) ExitErrMsg(FALSE, "Out of buffer memory! %d", __LINE__);
|
|
*pThis = *pHead;
|
|
|
|
if (pHead->sName != NULL) {
|
|
pName = (char *)BufAllocate(pBufallocinfo, strlen(pHead->sName) + 1);
|
|
if (NULL == pName) ExitErrMsg(FALSE, "Out of buffer memory! %d %s", __LINE__, pHead->sName);
|
|
pThis->sName = strcpy(pName, pHead->sName);
|
|
}
|
|
|
|
if (pHead->sType != NULL) {
|
|
pType = (char *)BufAllocate(pBufallocinfo, strlen(pHead->sType) + 1);
|
|
if (NULL == pType) ExitErrMsg(FALSE, "Out of buffer memory! %d %s", __LINE__, pHead->sType);
|
|
pThis->sType = strcpy(pType, pHead->sType);
|
|
}
|
|
|
|
if (bStatus) pThis->dwOffset += dwOffset;
|
|
pThis->pmeminfoNext = CatMeminfo(pBufallocinfo, pHead->pmeminfoNext, pTail, dwOffset, bStatus);
|
|
|
|
return pThis;
|
|
}
|
|
|
|
VOID
|
|
FreeTypeInfoList(
|
|
PTYPEINFOELEMENT pThis
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees the memory associated with a TYPEINFOELEMENT.
|
|
|
|
Arguments:
|
|
|
|
pThis -- [IN] ptr to the list to free.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
PTYPEINFOELEMENT pNext;
|
|
|
|
while(NULL != pThis) {
|
|
pNext = pThis->pNext;
|
|
if (pThis->pTypeInfo != NULL) GenHeapFree(pThis->pTypeInfo);
|
|
GenHeapFree(pThis);
|
|
pThis = pNext;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
GenerateProxy(
|
|
char *pName,
|
|
PTYPESINFO pTypesInfo
|
|
)
|
|
{
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generates proxy infomation for functions in a struct with virtual methods.
|
|
The infomation is of the form structname_functionname_Proxy.
|
|
The function is added to the functions list if not already in the list.
|
|
The discardable flag is set so that this type will be redefined in refound in the code.
|
|
|
|
Arguments:
|
|
|
|
pName -- [IN] ptr to the name of the struct that the method is in.
|
|
pTypesInfo -- [IN] Information for the function.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
TYPESINFO NewTypesInfo;
|
|
PFUNCINFO pFuncInfo;
|
|
PFUNCINFO *ppFuncInfo;
|
|
PFUNCINFO pCurrent;
|
|
BUFALLOCINFO bufallocinfo;
|
|
char *pChar;
|
|
DWORD dwSizeArgName, dwSizeTypeName;
|
|
|
|
// Bail out if not func, no struct name, or no class name
|
|
if (pName == NULL || pTypesInfo->TypeName == NULL) return;
|
|
if (pTypesInfo->TypeKind != TypeKindFunc ||
|
|
strlen(pName) == 0 ||
|
|
strlen(pTypesInfo->TypeName) == 0) return;
|
|
|
|
NewTypesInfo = *pTypesInfo;
|
|
strcpy(NewTypesInfo.TypeName, pName);
|
|
strcat(NewTypesInfo.TypeName, "_");
|
|
strcat(NewTypesInfo.TypeName, pTypesInfo->TypeName);
|
|
strcat(NewTypesInfo.TypeName, "_Proxy");
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
//Check if the function has already been added.
|
|
//If it has, no more work is needed.
|
|
/////////////////////////////////////////////////////////////////
|
|
if (GetNameFromTypesList(FuncsList, NewTypesInfo.TypeName) != NULL)
|
|
return;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//Copy function members adding a this pointer at head
|
|
//and skipping void arguments.
|
|
////////////////////////////////////////////////////////////////////
|
|
BufAllocInit(&bufallocinfo, NewTypesInfo.Members, FUNCMEMBERSIZE, 0);
|
|
dwSizeTypeName = strlen(pName) + 1;
|
|
dwSizeArgName = strlen(szThis) + 1;
|
|
pFuncInfo = (PFUNCINFO)BufAllocate(&bufallocinfo, sizeof(FUNCINFO) + dwSizeArgName + dwSizeTypeName);
|
|
if (NULL == pFuncInfo) ExitErrMsg(FALSE, "Out of buffer memory! %d", __LINE__);
|
|
|
|
pFuncInfo->fIsPtr64 = FALSE;
|
|
pFuncInfo->tkDirection = TK_IN;
|
|
pFuncInfo->tkPreMod = TK_NONE;
|
|
pFuncInfo->tkSUE = TK_NONE;
|
|
pFuncInfo->tkPrePostMod = TK_NONE;
|
|
pFuncInfo->IndLevel = 1;
|
|
pFuncInfo->tkPostMod = TK_NONE;
|
|
pChar = ((char *)pFuncInfo) + sizeof(FUNCINFO);
|
|
strcpy(pChar, pName);
|
|
pFuncInfo->sType = pChar;
|
|
pChar += dwSizeTypeName;
|
|
strcpy(pChar, szThis);
|
|
pFuncInfo->sName = pChar;
|
|
pFuncInfo->pfuncinfoNext = NULL;
|
|
NewTypesInfo.pfuncinfo = pFuncInfo;
|
|
ppFuncInfo = &(pFuncInfo->pfuncinfoNext);
|
|
|
|
//skip an argument of type void if it is at the begining.
|
|
//This is needed since ParseFuncTypes puts a void arg if the
|
|
//func does not have any arguments
|
|
pCurrent = pTypesInfo->pfuncinfo;
|
|
if (pCurrent != NULL &&
|
|
strcmp(szVOID, pCurrent->sType) == 0
|
|
&& pCurrent->IndLevel == 0) {
|
|
pCurrent = pCurrent->pfuncinfoNext;
|
|
}
|
|
|
|
for(; pCurrent != NULL; pCurrent=pCurrent->pfuncinfoNext) {
|
|
|
|
dwSizeTypeName = strlen(pCurrent->sType) + 1;
|
|
dwSizeArgName = strlen(pCurrent->sName) + 1;
|
|
pFuncInfo = (PFUNCINFO)BufAllocate(&bufallocinfo, sizeof(FUNCINFO) + dwSizeArgName + dwSizeTypeName);
|
|
if (NULL == pFuncInfo) ExitErrMsg(FALSE, "Out of buffer memory! %d", __LINE__);
|
|
|
|
*pFuncInfo = *pCurrent;
|
|
pChar = ((char *)pFuncInfo) + sizeof(FUNCINFO);
|
|
strcpy(pChar, pCurrent->sType);
|
|
pFuncInfo->sType = pChar;
|
|
pChar += dwSizeTypeName;
|
|
strcpy(pChar, pCurrent->sName);
|
|
pFuncInfo->sName = pChar;
|
|
pFuncInfo->pfuncinfoNext = NULL;
|
|
*ppFuncInfo = pFuncInfo;
|
|
ppFuncInfo = &(pFuncInfo->pfuncinfoNext);
|
|
|
|
}
|
|
|
|
NewTypesInfo.Flags |= BTI_DISCARDABLE;
|
|
NewTypesInfo.dwMemberSize = bufallocinfo.dwLen;
|
|
if (!AddNewType(&NewTypesInfo, FuncsList))
|
|
ExitErrMsg(FALSE, "Unable to add proxy information.(Type was not in list)\n");
|
|
|
|
}
|
|
|
|
BOOL
|
|
CopyStructMembers(
|
|
PTYPESINFO pTypesInfo,
|
|
BOOL bUnion,
|
|
PKNOWNTYPES pBaseType
|
|
)
|
|
{
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses the members of the structure and adds them to the pTypesInfo.
|
|
Handles merging of members and methods when the structure is derived
|
|
from another structure. Delegates actual parsing to pCopyStructMembers.
|
|
|
|
Arguments:
|
|
|
|
pTypesInfo -- [IN OUT] ptr to infomation for the type being processed.
|
|
dwElemSize -- [IN] TRUE if processing a union, FALSE if a struct.
|
|
bUnion -- [IN] ptr to KNOWNTYPE of base structure or NULL.
|
|
|
|
Return Value:
|
|
|
|
TRUE - If success.
|
|
|
|
--*/
|
|
|
|
PTYPEINFOELEMENT pMemberFuncs = NULL;
|
|
char *VTBLFakeMember;
|
|
PMEMBERINFO pHead = NULL; //Head in final merge
|
|
PMEMBERINFO pTail = NULL; //Tail in final merge
|
|
DWORD dwiPackSize; //For tail
|
|
DWORD dwSize; //For tail
|
|
DWORD dwOffset; //For tail
|
|
BUFALLOCINFO bufallocinfo;
|
|
|
|
|
|
dwScopeLevel++;
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
//Add a discardable version of this struct if one doesn't exist
|
|
/////////////////////////////////////////////////////////////////
|
|
if (GetNameFromTypesList(StructsList, pTypesInfo->TypeName) == NULL) {
|
|
TYPESINFO TTypesInfo;
|
|
TTypesInfo = *pTypesInfo;
|
|
TTypesInfo.Flags |= BTI_DISCARDABLE;
|
|
AddNewType(&TTypesInfo, StructsList); //intentionally do not check
|
|
}
|
|
|
|
if(bUnion) return pCopyStructMembers(pTypesInfo, bUnion, NULL, 0, 0);
|
|
|
|
if (pBaseType == NULL) {
|
|
if (!pCopyStructMembers(pTypesInfo, FALSE, &pMemberFuncs, 0, 0)) {
|
|
FreeTypeInfoList(pMemberFuncs);
|
|
return FALSE;
|
|
}
|
|
if (pMemberFuncs!=NULL && pTypesInfo->Size > 0) {
|
|
ErrMsg("Error: struct %s mixes data members and virtual functions(sortpp limitation).\n", pTypesInfo->TypeName);
|
|
FreeTypeInfoList(pMemberFuncs);
|
|
return FALSE;
|
|
}
|
|
|
|
pTypesInfo->dwVTBLSize = 0;
|
|
pTypesInfo->dwVTBLOffset = 0;
|
|
|
|
if (pMemberFuncs != NULL) {
|
|
|
|
|
|
PTYPEINFOELEMENT pThisElement;
|
|
DWORD dwElements = 0;
|
|
DWORD dwLength, dwVoidLen, dwVTBLLen;
|
|
PMEMBERINFO pMemberInfo;
|
|
char *pName;
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//Build the fake VTBL pointer
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Add the VTBL member
|
|
dwVoidLen = strlen(szVOID) + 1;
|
|
dwVTBLLen = strlen(szVTBL) + 1;
|
|
|
|
memset(pTypesInfo->Members, 0, FUNCMEMBERSIZE);
|
|
BufAllocInit(&bufallocinfo, pTypesInfo->Members, FUNCMEMBERSIZE, 0);
|
|
pMemberInfo = (PMEMBERINFO)BufAllocate(&bufallocinfo, sizeof(MEMBERINFO) + dwVoidLen + dwVTBLLen);
|
|
if (NULL == pMemberInfo) ExitErrMsg(FALSE, "Out of buffer memory! %d", __LINE__);
|
|
|
|
pName = ((char *)pMemberInfo) + sizeof(MEMBERINFO);
|
|
strcpy(pName, szVTBL);
|
|
pMemberInfo->sName = pName;
|
|
|
|
pName += dwVTBLLen;
|
|
strcpy(pName, szVOID);
|
|
pMemberInfo->sType = pName;
|
|
|
|
pMemberInfo->pmeminfoNext = NULL;
|
|
pMemberInfo->dwOffset = 0;
|
|
pMemberInfo->IndLevel = 1;
|
|
pMemberInfo->pktCache = 0;
|
|
|
|
pTypesInfo->iPackSize = PackCurrentPacking() < SIZEOFPOINTER ?
|
|
PackCurrentPacking() : SIZEOFPOINTER;
|
|
pTypesInfo->Size = SIZEOFPOINTER;
|
|
pTypesInfo->dwMemberSize = bufallocinfo.dwLen;
|
|
pTypesInfo->Flags |= BTI_VIRTUALONLY;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//Build the list of functions in the VTBL
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//copy methods over to Methods and IMethods
|
|
for(pThisElement = pMemberFuncs; pThisElement != NULL; pThisElement = pThisElement->pNext) {
|
|
if(pThisElement->pTypeInfo != NULL) {
|
|
if(!AppendToMultiSz(pTypesInfo->Methods, pThisElement->pTypeInfo->TypeName, MEMBERMETHODSSIZE) ||
|
|
!AppendToMultiSz(pTypesInfo->IMethods, pThisElement->pTypeInfo->TypeName, MEMBERMETHODSSIZE)) {
|
|
ExitErrMsg(FALSE,"Too many methods in %s\n", pTypesInfo->TypeName);
|
|
}
|
|
GenerateProxy(pTypesInfo->TypeName, pThisElement->pTypeInfo);
|
|
dwElements++;
|
|
}
|
|
}
|
|
|
|
pTypesInfo->dwVTBLSize = dwElements;
|
|
pTypesInfo->dwVTBLOffset = 0;
|
|
|
|
//If this is IUnknown, it is a COM object
|
|
if (strcmp("IUnknown", pTypesInfo->TypeName) == 0)
|
|
pTypesInfo->Flags |= BTI_ISCOM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(!pCopyStructMembers(pTypesInfo, FALSE, &pMemberFuncs, pBaseType->Size, pBaseType->iPackSize)) {
|
|
FreeTypeInfoList(pMemberFuncs);
|
|
return FALSE;
|
|
}
|
|
// This checks that structures with data member are not mixed with structures with virtual methods.
|
|
// This is a sortpp limitation that makes computing the packing size during inheritance easier.
|
|
// The if statement say that a valid inheritance is either.
|
|
// 1. The derived class does not add new virtual methods or data members.
|
|
// 2. The derived class does not add new virtual methods, adds no new data members, and it inherites from a class with no virtual functions.
|
|
// 3. The derived class adds virtual functions, adds no new data members, and the base class has no data members.
|
|
if (!((pMemberFuncs == NULL && pTypesInfo->dwMemberSize == 0) ||
|
|
(pMemberFuncs == NULL && pTypesInfo->dwMemberSize > 0 && pBaseType->dwVTBLSize == 0) ||
|
|
(pMemberFuncs != NULL && pTypesInfo->dwMemberSize == 0 && pBaseType->SizeMembers == 0)
|
|
)) {
|
|
ErrMsg("Error: struct %s mixes data members and virtual functions(sortpp limitation).\n", pTypesInfo->TypeName);
|
|
ErrMsg("pMemberFuncs %p\n pTypesInfo->dwMemberSize %x\n pBaseType->Flags %x\n pBaseType->pmeminfo %p\n",
|
|
pMemberFuncs,
|
|
pTypesInfo->dwMemberSize,
|
|
pBaseType->Flags,
|
|
pBaseType->pmeminfo);
|
|
FreeTypeInfoList(pMemberFuncs);
|
|
return FALSE;
|
|
}
|
|
|
|
pTypesInfo->dwVTBLSize = pTypesInfo->dwVTBLOffset = pBaseType->dwVTBLSize;
|
|
pTypesInfo->Flags |= (pBaseType->Flags & ~BTI_HASGUID);
|
|
if(pMemberFuncs == NULL) {
|
|
|
|
char *Members;
|
|
PMEMBERINFO pHead, pTail, pTemp;
|
|
|
|
if (pBaseType->pmeminfo != NULL)
|
|
pHead = (PMEMBERINFO)pBaseType->pmeminfo;
|
|
else
|
|
pHead = NULL;
|
|
|
|
if (pTypesInfo->dwMemberSize > 0)
|
|
pTail = (PMEMBERINFO)pTypesInfo->Members;
|
|
else
|
|
pTail = NULL;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//Allocate memory for the temp array
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
Members = GenHeapAlloc(FUNCMEMBERSIZE);
|
|
|
|
if (Members == NULL)
|
|
ExitErrMsg(FALSE, "Out of memory!\n");
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//merge members lists with basetype
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//copy the concatination of the two to the temp buffer
|
|
BufAllocInit(&bufallocinfo, Members, FUNCMEMBERSIZE, 0);
|
|
pTemp = CatMeminfo(&bufallocinfo, pHead, pTail, 0, FALSE);
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//copy members from temp buffers back to pTypesInfo
|
|
////////////////////////////////////////////////////////////////////////
|
|
memset( pTypesInfo->Members, 0, FUNCMEMBERSIZE );
|
|
BufAllocInit(&bufallocinfo, pTypesInfo->Members, FUNCMEMBERSIZE, 0);
|
|
if (pTemp) {
|
|
// Only call this one if the first one did anyting. Otherwise
|
|
// This one reads from uninitialized heap.
|
|
CatMeminfo(&bufallocinfo, (PMEMBERINFO)Members, NULL, 0, FALSE);
|
|
}
|
|
pTypesInfo->dwMemberSize = bufallocinfo.dwLen;
|
|
|
|
GlobalFree(Members);
|
|
}
|
|
|
|
else {
|
|
|
|
PTYPEINFOELEMENT pThisElement;
|
|
DWORD dwElements = 0;
|
|
|
|
// This struct is virtual only since methods are being added. We already checked that no
|
|
// data members will be in the structure.
|
|
pTypesInfo->Flags |= BTI_VIRTUALONLY;
|
|
|
|
////////////////////////////////////////////////////////
|
|
//Copy base members over
|
|
////////////////////////////////////////////////////////
|
|
|
|
memset( pTypesInfo->Members, 0, FUNCMEMBERSIZE );
|
|
BufAllocInit(&bufallocinfo, pTypesInfo->Members, FUNCMEMBERSIZE, 0);
|
|
CatMeminfo(&bufallocinfo, pBaseType->pmeminfo, NULL, 0, FALSE);
|
|
pTypesInfo->dwMemberSize = bufallocinfo.dwLen;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//Build the list of functions in the VTBL
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//copy unique methods over to IMethods
|
|
for(pThisElement = pMemberFuncs; pThisElement != NULL; pThisElement = pThisElement->pNext) {
|
|
if(pThisElement->pTypeInfo != NULL) {
|
|
if (!IsInMultiSz(pBaseType->Methods, pThisElement->pTypeInfo->TypeName)) {
|
|
if(!AppendToMultiSz(pTypesInfo->IMethods, pThisElement->pTypeInfo->TypeName,
|
|
MEMBERMETHODSSIZE)) {
|
|
ExitErrMsg(FALSE,"Too many methods in %s\n", pTypesInfo->TypeName);
|
|
}
|
|
GenerateProxy(pTypesInfo->TypeName, pThisElement->pTypeInfo);
|
|
dwElements++;
|
|
}
|
|
}
|
|
}
|
|
|
|
memcpy(pTypesInfo->Methods, pBaseType->Methods, SizeOfMultiSz(pBaseType->Methods));
|
|
if (!CatMultiSz(pTypesInfo->Methods, pTypesInfo->IMethods, MEMBERMETHODSSIZE))
|
|
ExitErrMsg(FALSE, "Too many methods in %s\n", pTypesInfo->TypeName);
|
|
|
|
pTypesInfo->dwVTBLSize = dwElements + pBaseType->dwVTBLSize;
|
|
pTypesInfo->dwVTBLOffset = pBaseType->dwVTBLSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FreeTypeInfoList(pMemberFuncs);
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
BumpStructUnionSize(
|
|
DWORD *pdwSize,
|
|
DWORD dwElemSize,
|
|
BOOL bUnion
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates overall size of a struct/union
|
|
|
|
Arguments:
|
|
|
|
pdwSize -- [IN OUT] overall size of struct/union
|
|
dwElemSize -- size of new element to add into the struct/union
|
|
bUnion -- TRUE if a union, FALSE if a struct
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
if (bUnion) {
|
|
//
|
|
// Size of a union is max(dwSize, dwElementSize)
|
|
//
|
|
if (dwElemSize > *pdwSize) {
|
|
*pdwSize = dwElemSize;
|
|
}
|
|
} else {
|
|
//
|
|
// Size of a struct is current size of struct plus element size
|
|
//
|
|
*pdwSize = *pdwSize + dwElemSize;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
ParseGuid(
|
|
GUID *pGuid
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses a guid of the type found in a variable declaration.
|
|
|
|
Arguments:
|
|
|
|
pGuid - [OUT] ptr to the guid.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Guid parsed.
|
|
FALSE - Parse failed.
|
|
|
|
--*/
|
|
unsigned int c;
|
|
LONGLONG value;
|
|
|
|
if (CurrentToken()->TokenType != TK_LBRACE) return FALSE;
|
|
ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType != TK_NUMBER) return FALSE;
|
|
value = expr();
|
|
if (value < 0 || value > 0xFFFFFFFF) return FALSE;
|
|
pGuid->Data1 = (unsigned long)value;
|
|
|
|
if (CurrentToken()->TokenType != TK_COMMA) return FALSE;
|
|
ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType != TK_NUMBER) return FALSE;
|
|
value = expr();
|
|
if (value < 0 || value > 0xFFFF) return FALSE;
|
|
pGuid->Data2 = (unsigned short)value;
|
|
|
|
if (CurrentToken()->TokenType != TK_COMMA) return FALSE;
|
|
ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType != TK_NUMBER) return FALSE;
|
|
value = expr();
|
|
if (value < 0 || value > 0xFFFF) return FALSE;
|
|
pGuid->Data2 = (unsigned short)value;
|
|
|
|
|
|
if (CurrentToken()->TokenType != TK_COMMA) return FALSE;
|
|
ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType != TK_LBRACE) return FALSE;
|
|
ConsumeToken();
|
|
|
|
c = 0;
|
|
while(TRUE) {
|
|
|
|
if (CurrentToken()->TokenType != TK_NUMBER) return FALSE;
|
|
value = expr();
|
|
if(value < 0 || value > 0xFF) return FALSE;
|
|
pGuid->Data4[c] = (unsigned char)value;
|
|
|
|
if (7 == c) break;
|
|
|
|
if (CurrentToken()->TokenType != TK_COMMA) return FALSE;
|
|
ConsumeToken();
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
for(c=0; c<2; c++) {
|
|
if (CurrentToken()->TokenType != TK_RBRACE) return FALSE;
|
|
ConsumeToken();
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
ParseVariables(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempts to parse a variable declaration. If successful, the variable
|
|
is added to the variable list.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
TRUE - If success.
|
|
|
|
--*/
|
|
|
|
|
|
TYPESINFO TypesInfo;
|
|
GUID Guid;
|
|
char *Name;
|
|
|
|
ConsumeConstVolatileOpt();
|
|
if (!GetExistingType(&TypesInfo, NULL, NULL)) return FALSE;
|
|
while(CurrentToken()->TokenType == TK_STAR) ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType == TK_DECLSPEC) {
|
|
ConsumeDeclSpecOpt(FALSE, FALSE, NULL, NULL, NULL);
|
|
}
|
|
|
|
//next token should be the variable name
|
|
if (CurrentToken()->TokenType != TK_IDENTIFIER) return FALSE;
|
|
Name = CurrentToken()->Name;
|
|
ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType == TK_EOS) return AddVariable(Name, NULL);
|
|
if (CurrentToken()->TokenType != TK_ASSIGN) return FALSE;
|
|
ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType == TK_NUMBER || CurrentToken()->TokenType == TK_STRING) {
|
|
ConsumeToken();
|
|
if (CurrentToken()->TokenType == TK_EOS) return AddVariable(Name, NULL);
|
|
return FALSE;
|
|
}
|
|
else if (CurrentToken()->TokenType == TK_LBRACE) {
|
|
//attempt to parse a guid definition
|
|
if (ParseGuid(&Guid) &&
|
|
CurrentToken()->TokenType == TK_EOS) return AddVariable(Name, &Guid);
|
|
else return FALSE;
|
|
}
|
|
else return FALSE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
GetArrayIndex(
|
|
DWORD *pdw
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses the size of an array index by evaluating a C-language constant
|
|
expression.
|
|
|
|
Arguments:
|
|
|
|
pdw -- [OUT] ptr to size of the array index.
|
|
|
|
Return Value:
|
|
|
|
TRUE if array index parsed (CurrentToken points after the ']')
|
|
FALSE if parse failed.
|
|
|
|
--*/
|
|
{
|
|
LONGLONG value;
|
|
|
|
*pdw = 0; // assume no size
|
|
|
|
if (CurrentToken()->TokenType != TK_LSQUARE) {
|
|
return FALSE;
|
|
}
|
|
ConsumeToken();
|
|
|
|
value = expr();
|
|
if (value < 0 || value > 0xFFFFFFFF) return FALSE;
|
|
|
|
*pdw = (DWORD)value;
|
|
|
|
if (CurrentToken()->TokenType != TK_RSQUARE) {
|
|
return FALSE;
|
|
}
|
|
ConsumeToken();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LONGLONG
|
|
expr(
|
|
void
|
|
)
|
|
|
|
{
|
|
LONGLONG val = expr_a1();
|
|
|
|
while(1) {
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_BITWISE_AND:
|
|
ConsumeToken();
|
|
val &= expr_a1();
|
|
break;
|
|
|
|
case TK_BITWISE_OR:
|
|
ConsumeToken();
|
|
val |= expr_a1();
|
|
break;
|
|
|
|
default:
|
|
return val;
|
|
}
|
|
} while (1);
|
|
|
|
}
|
|
|
|
LONGLONG
|
|
expr_a1(
|
|
void
|
|
)
|
|
{
|
|
LONGLONG val = expr_a();
|
|
|
|
while(1) {
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_LSHIFT:
|
|
ConsumeToken();
|
|
val <<= expr_a();
|
|
break;
|
|
|
|
case TK_RSHIFT:
|
|
ConsumeToken();
|
|
val >>= expr_a();
|
|
break;
|
|
|
|
default:
|
|
return val;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
LONGLONG
|
|
expr_a(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses a C-language constant expression and returns the value - handles
|
|
the operators 'plus' and 'minus'.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Value of the expression.
|
|
|
|
--*/
|
|
{
|
|
LONGLONG val = expr_b();
|
|
|
|
do
|
|
{
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_PLUS:
|
|
ConsumeToken();
|
|
val += expr_b();
|
|
break;
|
|
|
|
case TK_MINUS:
|
|
ConsumeToken();
|
|
val -= expr_b();
|
|
break;
|
|
|
|
default:
|
|
return val;
|
|
}
|
|
} while (1);
|
|
}
|
|
|
|
LONGLONG
|
|
expr_b(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Part of expression evaluator - handles the highest-precedence operators
|
|
'multiply' and 'divide'.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Value of the expression.
|
|
|
|
--*/
|
|
{
|
|
LONGLONG val = expr_c();
|
|
|
|
do
|
|
{
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_STAR:
|
|
ConsumeToken();
|
|
val *= expr_c();
|
|
break;
|
|
|
|
case TK_DIVIDE:
|
|
ConsumeToken();
|
|
val /= expr_c();
|
|
break;
|
|
|
|
case TK_MOD:
|
|
ConsumeToken();
|
|
val %= expr_c();
|
|
break;
|
|
|
|
default:
|
|
// done
|
|
return val;
|
|
}
|
|
} while (1);
|
|
|
|
}
|
|
|
|
LONGLONG
|
|
expr_c(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Part of expression evaluator - handles unary parts of the expression, like
|
|
numbers, unary minus, and parentheses.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Value of the expression.
|
|
|
|
--*/
|
|
{
|
|
LONGLONG val;
|
|
PKNOWNTYPES pkt;
|
|
|
|
switch (CurrentToken()->TokenType) {
|
|
case TK_NUMBER:
|
|
val = CurrentToken()->dwValue;
|
|
ConsumeToken();
|
|
break;
|
|
|
|
case TK_MINUS: // unary minus
|
|
ConsumeToken();
|
|
val = -expr_c();
|
|
break;
|
|
|
|
case TK_TILDE: // unary not
|
|
ConsumeToken();
|
|
val = ~expr_c();
|
|
break;
|
|
|
|
case TK_LPAREN:
|
|
ConsumeToken();
|
|
val = expr();
|
|
if (CurrentToken()->TokenType != TK_RPAREN) {
|
|
ErrMsg("Syntax error: expected ')'");
|
|
}
|
|
ConsumeToken();
|
|
break;
|
|
|
|
case TK_RSQUARE:
|
|
val = 0;
|
|
break;
|
|
|
|
case TK_SIZEOF:
|
|
ConsumeToken(); // eat the sizeof keyword
|
|
if (CurrentToken()->TokenType != TK_LPAREN) {
|
|
ErrMsg("Expected '(' after 'sizeof\n");
|
|
val = 0;
|
|
break;
|
|
}
|
|
ConsumeToken(); // eat the '('
|
|
if (CurrentToken()->TokenType == TK_STRING) {
|
|
// sizeof(string literal)
|
|
val = strlen(CurrentToken()->Name) + 1;
|
|
ConsumeToken();
|
|
} else {
|
|
// sizeof(some type)
|
|
TYPESINFO TypesInfo;
|
|
DWORD dwIndLevel;
|
|
DWORD dwSize;
|
|
|
|
if (!GetExistingType(&TypesInfo, NULL, NULL)) {
|
|
ExitErrMsg(FALSE, "Parse error in sizeof(typename)\n");
|
|
}
|
|
dwIndLevel = 0;
|
|
ParseIndirection(&dwIndLevel, &dwSize, NULL, NULL, NULL);
|
|
if (dwIndLevel) {
|
|
val = (int)dwSize;
|
|
} else {
|
|
val = TypesInfo.Size;
|
|
}
|
|
}
|
|
if (CurrentToken()->TokenType != TK_RPAREN) {
|
|
ErrMsg("Expected ')' after 'sizeof(expr)\n");
|
|
val = 0;
|
|
break;
|
|
}
|
|
ConsumeToken(); // eat the ')'
|
|
break;
|
|
|
|
default:
|
|
ErrMsg("Syntax error parsing expression\n");
|
|
val = 0;
|
|
break;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
|
|
int
|
|
CreatePseudoName(
|
|
char *pDst,
|
|
char *pSrc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prefixes a given name with an index number and copies it into a buffer.
|
|
|
|
Arguments:
|
|
|
|
pDst -- [OUT] destination for the new name
|
|
pSrc -- [IN] source for the base name (may be same as pDst)
|
|
|
|
Return Value:
|
|
|
|
Chars copied, 0 for failure.
|
|
|
|
--*/
|
|
{
|
|
static PseudoNameIndex = 0;
|
|
int Len;
|
|
char Buffer[MAX_PATH];
|
|
|
|
Len = _snprintf(Buffer,
|
|
sizeof(Buffer) - 1,
|
|
"__wx86%2.2d%s",
|
|
PseudoNameIndex++,
|
|
pSrc
|
|
);
|
|
|
|
if (Len <= 0) {
|
|
ErrMsg("cpn: buffer overflow <%s>\n", pSrc);
|
|
return 0;
|
|
}
|
|
|
|
strcpy(pDst, Buffer);
|
|
|
|
return Len;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
PackPush(
|
|
char *sIdentifier
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles '#pragma pack (push...)'
|
|
|
|
Arguments:
|
|
|
|
sIdentifier -- [OPTIONAL] name to associate with the current pack level
|
|
|
|
Return Value:
|
|
|
|
None. Pack-stack updated.
|
|
|
|
--*/
|
|
{
|
|
PACKHOLDER *ppackholder;
|
|
|
|
if (!sIdentifier) {
|
|
sIdentifier = "";
|
|
}
|
|
|
|
DbgPrintf("push (%d)\n", PackCurrentPacking());
|
|
|
|
ppackholder = GenHeapAlloc(sizeof(PACKHOLDER) + strlen(sIdentifier));
|
|
if (ppackholder == NULL) {
|
|
ExitErrMsg(FALSE, "Out of memory for packing stack");
|
|
}
|
|
|
|
ppackholder->dwPacking = PackCurrentPacking();
|
|
ppackholder->ppackholderNext = ppackholderHead;
|
|
strcpy(ppackholder->sIdentifier, sIdentifier);
|
|
ppackholderHead = ppackholder;
|
|
}
|
|
|
|
|
|
DWORD
|
|
PackPop(
|
|
char *sIdentifier
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles '#pragma pack (pop...)'
|
|
|
|
Arguments:
|
|
|
|
sIdentifier -- [OPTIONAL] name to pop to
|
|
|
|
Return Value:
|
|
|
|
Returns new packing value. Pack-stack updated.
|
|
|
|
--*/
|
|
{
|
|
PACKHOLDER *ppackholder;
|
|
PACKHOLDER *ppackholderPop;
|
|
PACKHOLDER *ppackholderNext;
|
|
DWORD dw = DEFAULTPACKINGSIZE;
|
|
|
|
if (ppackholderHead == NULL) {
|
|
ExitErrMsg(FALSE, "Error: '#pragma pack' stack underflow.");
|
|
}
|
|
|
|
if (sIdentifier == NULL) {
|
|
ppackholder = ppackholderHead;
|
|
ppackholderHead = ppackholder->ppackholderNext;
|
|
dw = ppackholder->dwPacking;
|
|
GenHeapFree(ppackholder);
|
|
} else {
|
|
ppackholderPop = ppackholderHead;
|
|
do {
|
|
DbgPrintf("Poping for %s [%s]\n", sIdentifier, ppackholderPop ? ppackholderPop->sIdentifier : "-");
|
|
ppackholderNext = ppackholderPop->ppackholderNext;
|
|
if (strcmp(sIdentifier, ppackholderPop->sIdentifier) == 0) {
|
|
dw = ppackholderPop->dwPacking;
|
|
break;
|
|
}
|
|
ppackholderPop = ppackholderNext;
|
|
} while (ppackholderPop != NULL);
|
|
|
|
DbgPrintf("Found %s\n", ppackholderPop ? ppackholderPop->sIdentifier : "-");
|
|
if (ppackholderPop != NULL) {
|
|
ppackholderNext = ppackholderHead;
|
|
do {
|
|
ppackholder = ppackholderNext;
|
|
ppackholderNext = ppackholder->ppackholderNext;
|
|
ppackholderHead = ppackholderNext;
|
|
GenHeapFree(ppackholder);
|
|
} while (ppackholder != ppackholderPop);
|
|
}
|
|
}
|
|
|
|
DbgPrintf("pop (%d)\n", dw);
|
|
return(dw);
|
|
}
|
|
|
|
BOOL
|
|
PrepareMappedMemory(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates the memory for the .PPM file.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure.
|
|
|
|
--*/
|
|
{
|
|
PCVMHEAPHEADER pHeader;
|
|
hCvmHeap = CreateAllocCvmHeap(uBaseAddress, // uBaseAddress
|
|
uReserveSize, // uReservedSize
|
|
0x00010000, // uRegionSize
|
|
0, // uUncommited
|
|
0, // uUnReserved
|
|
0); // uAvailable
|
|
|
|
if (hCvmHeap != NULL) {
|
|
|
|
// create the heap header
|
|
pHeader = SortppAllocCvm(sizeof(CVMHEAPHEADER));
|
|
if (!pHeader) {
|
|
return FALSE;
|
|
}
|
|
pHeader->Version = VM_TOOL_VERSION;
|
|
pHeader->BaseAddress = (ULONG_PTR)GetCvmHeapBaseAddress(hCvmHeap);
|
|
|
|
fpTypesListMalloc = SortppAllocCvm;
|
|
|
|
FuncsList = &pHeader->FuncsList;
|
|
StructsList = &pHeader->StructsList;
|
|
TypeDefsList = &pHeader->TypeDefsList;
|
|
NIL = &pHeader->NIL;
|
|
}
|
|
|
|
return(hCvmHeap != NULL);
|
|
}
|
|
|
|
|
|
PVOID
|
|
SortppAllocCvm(
|
|
ULONG Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates memory from the .PPM file mapping.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
ptr to new memory, or NULL on failure.
|
|
|
|
--*/
|
|
{
|
|
return AllocCvm(hCvmHeap, Size);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WritePpmFile(
|
|
char *PpmName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write the .PPM file out to disk.
|
|
|
|
Arguments:
|
|
|
|
Ppmname -- [IN] name for .PPM file
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
BOOL bSuccess;
|
|
HANDLE hPpmFile;
|
|
DWORD BytesWritten;
|
|
ULONG_PTR uBaseAddress = (ULONG_PTR)GetCvmHeapBaseAddress(hCvmHeap);
|
|
ULONG_PTR uAvailable = (ULONG_PTR)GetCvmHeapAvailable(hCvmHeap);
|
|
|
|
hPpmFile = CreateFile(PpmName,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL
|
|
);
|
|
|
|
if (hPpmFile == INVALID_HANDLE_VALUE) {
|
|
ExitErrMsg(FALSE,
|
|
"CreateFile(%s) failed %x\n",
|
|
PpmName,
|
|
GetLastError()
|
|
);
|
|
}
|
|
|
|
if (!AddOpenFile(PpmName, 0, hPpmFile)) {
|
|
ExitErrMsg(FALSE, "AddOpenFile failed\n");
|
|
}
|
|
|
|
#if _WIN64
|
|
if ((uAvailable - uBaseAddress) > MAXHALF_PTR) {
|
|
ExitErrMsg(FALSE, "Attempt to write more than 0x%x bytes not allowed\n", MAXHALF_PTR);
|
|
}
|
|
#endif
|
|
|
|
bSuccess = WriteFile(hPpmFile,
|
|
(PVOID)uBaseAddress,
|
|
(DWORD)(uAvailable - uBaseAddress),
|
|
&BytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if (!bSuccess || BytesWritten != uAvailable - uBaseAddress) {
|
|
ExitErrMsg(FALSE,
|
|
"WriteFile(%s) failed %x\n",
|
|
PpmName,
|
|
GetLastError()
|
|
);
|
|
}
|
|
|
|
DelOpenFile(0, hPpmFile);
|
|
CloseHandle(hPpmFile);
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
HandlePreprocessorDirective(
|
|
char *Line
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scan and process a '#' preprocessor directive.
|
|
Accepts:
|
|
#pragma line LINENUM SOURCEFILE
|
|
#pragma pack( [ [ { push | pop}, ] [ identifier, ] ] [ n ] )
|
|
|
|
Arguments:
|
|
|
|
Line -- ptr to the source line (points at the '#' character)
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
char *p;
|
|
|
|
// skip over '#' character
|
|
Line++;
|
|
|
|
// skip over any spaces between '#' and the next token
|
|
while (*Line == ' ' || *Line == '\t') {
|
|
Line++;
|
|
}
|
|
|
|
// find the first token
|
|
for (p = Line; isalpha(*p); ++p)
|
|
;
|
|
|
|
*p = '\0';
|
|
|
|
if (strcmp(Line, "pragma") == 0) {
|
|
//
|
|
// found: #pragma
|
|
//
|
|
char c;
|
|
p++;
|
|
|
|
while (*p == ' ' || *p == '\t') {
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// Set 'Line' to the start of the word following '#pragma' and
|
|
// move 'p' to the character following that word.
|
|
//
|
|
for (Line = p; isalpha(*p); ++p)
|
|
;
|
|
|
|
//
|
|
// Null-terminate the keyword, but save the overwritten character
|
|
// for later.
|
|
//
|
|
c = *p;
|
|
*p = '\0';
|
|
|
|
if (strcmp(Line, "pack") != 0) {
|
|
//
|
|
// Might be "warning", "function" or "once". Ignore these.
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Remove the null-terminator from the pragma and move 'p' to the
|
|
// first character after "#pragma pack"
|
|
//
|
|
*p = c;
|
|
while (*p == ' ' || *p == '\t') {
|
|
p++;
|
|
}
|
|
|
|
if (*p == '\0') {
|
|
//
|
|
// Found: "#pragma pack" all by itself. Reset packing to the
|
|
// default value.
|
|
//
|
|
PackModify(DEFAULTPACKINGSIZE);
|
|
return;
|
|
} else if (*p != '(') {
|
|
ExitErrMsg(FALSE, "Unknown '#pragma pack' syntax '%s'.\n", Line);
|
|
}
|
|
|
|
//
|
|
// skip over the '(' character and any whitespace
|
|
//
|
|
do {
|
|
p++;
|
|
} while (*p == ' ' || *p == '\t');
|
|
|
|
if (isdigit(*p)) {
|
|
//
|
|
// Found: '#pragma pack(NUMBER)'
|
|
//
|
|
PackModify(atol(p));
|
|
//
|
|
// Don't worry about the closing ')' - assume things are alright.
|
|
//
|
|
return;
|
|
} else if (*p == ')') {
|
|
//
|
|
// Found: '#pragma pack()'
|
|
//
|
|
PackModify(DEFAULTPACKINGSIZE);
|
|
return;
|
|
} else if (!isalpha(*p)) {
|
|
ExitErrMsg(FALSE, "Bad '#pragma pack' syntax '%s'.\n", Line);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Grab the next keyword following '#pragma pack('
|
|
//
|
|
for (Line = p; isalpha(*p); ++p)
|
|
;
|
|
c = *p;
|
|
*p = '\0';
|
|
|
|
if (strcmp(Line, "push") == 0) {
|
|
//
|
|
// Restore the old character and skip over any whitespace
|
|
//
|
|
*p = c;
|
|
while (*p == ' ' || *p == '\t') {
|
|
p++;
|
|
}
|
|
|
|
if (*p == ',') {
|
|
//
|
|
// Skip the ',' and any whitespace
|
|
//
|
|
do {
|
|
p++;
|
|
} while (*p == ' ' || *p == '\t');
|
|
|
|
if (isdigit(*p)) {
|
|
//
|
|
// Found: "#pragma pack(push, n)"
|
|
//
|
|
PackPush(NULL);
|
|
PackModify(atoi(p));
|
|
} else if (isalpha(*p) || *p == '_') {
|
|
//
|
|
// Found an identifier after "#pragma pack(push, ".
|
|
// Scan ahead to end of identifier.
|
|
//
|
|
Line = p;
|
|
do {
|
|
p++;
|
|
} while (isalnum(*p) || *p == '_');
|
|
|
|
//
|
|
// null-terminate the identifier, in 'Line'
|
|
//
|
|
c = *p;
|
|
*p = '\0';
|
|
|
|
//
|
|
// Skip past whitespace
|
|
//
|
|
while (c == ' ' || c == '\t') {
|
|
p++;
|
|
c = *p;
|
|
}
|
|
// 'c' is the first non-white char after identifier
|
|
|
|
|
|
if (c == ')') {
|
|
//
|
|
// Found: "#pragma pack(push, identifier)"
|
|
//
|
|
PackPush(Line);
|
|
} else if (c == ',') {
|
|
//
|
|
// Expect a number as the last thing on the line
|
|
//
|
|
PackPush(Line);
|
|
PackModify(atoi(p+1));
|
|
} else {
|
|
ExitErrMsg(FALSE, "Unknown #pragma pack syntax '%s' at %s(%d)\n", p, SourceFileName, StatementLineNumber );
|
|
}
|
|
} else {
|
|
ExitErrMsg(FALSE, "Unknown #pragma pack syntax '%s'\n", p);
|
|
}
|
|
} else if (*p == ')') {
|
|
//
|
|
// Found: "#pragma pack(push)"
|
|
//
|
|
PackPush(NULL);
|
|
|
|
} else {
|
|
ExitErrMsg(FALSE, "Bad '#pragma pack(push)' syntax '%s' at %s(%d).\n", Line, SourceFileName, StatementLineNumber);
|
|
}
|
|
|
|
} else if (strcmp(Line, "pop") == 0) {
|
|
//
|
|
// Restore the old character and skip over any whitespace
|
|
//
|
|
*p = c;
|
|
while (*p == ' ' || *p == '\t') {
|
|
p++;
|
|
}
|
|
|
|
if (*p == ')') {
|
|
//
|
|
// Found: "#pragma pack(pop)"
|
|
//
|
|
PackModify(PackPop(NULL));
|
|
} else if (*p == ',') {
|
|
//
|
|
// Found: "#pragma pack(pop, identifier)"
|
|
//
|
|
p++;
|
|
while (*p == ' ' || *p == '\t') p++;
|
|
|
|
if (!(isalpha(*p) || *p == '_'))
|
|
ExitErrMsg(FALSE, "Bad '#pragma pack(pop)' syntax '%s' at %s(%d).\n", p, SourceFileName, StatementLineNumber);
|
|
|
|
Line = p;
|
|
do {
|
|
p++;
|
|
} while (isalnum(*p) || *p == '_');
|
|
*p = '\0';
|
|
PackModify(PackPop(Line));
|
|
} else {
|
|
ExitErrMsg(FALSE, "Bad '#pragma pack(pop)' syntax '%s' at %s(%d).\n", p, SourceFileName, StatementLineNumber);
|
|
}
|
|
} else {
|
|
ExitErrMsg(FALSE, "Bad '#pragma pack' syntax '%s' at %s(%d).\n", Line, SourceFileName, StatementLineNumber);
|
|
}
|
|
|
|
} else if (strcmp(Line, "line") == 0) {
|
|
//
|
|
// found: #line LINE_NUMBER "FILENAME"
|
|
//
|
|
int i;
|
|
|
|
//
|
|
// skip over any spaces between '#line' and the line number
|
|
//
|
|
p++;
|
|
while (*p == ' ' || *p == '\t') {
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// copy in the new line number
|
|
//
|
|
SourceLineNumber = 0;
|
|
while (isdigit(*p)) {
|
|
SourceLineNumber = SourceLineNumber * 10 + *p - '0';
|
|
p++;
|
|
}
|
|
SourceLineNumber--;
|
|
|
|
//
|
|
// Skip over any spaces between line number and the filename
|
|
//
|
|
while (*p == ' ' || *p == '\t') {
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// Skip over the opening quote
|
|
//
|
|
if (*p == '\"') {
|
|
p++;
|
|
} else {
|
|
ExitErrMsg(FALSE, "Badly-formed #line directive - filename missing");
|
|
}
|
|
|
|
//
|
|
// Copy in the filename, converting "\\" sequences to single '\'
|
|
//
|
|
for (i=0; *p && *p != '\"' && i<sizeof(SourceFileName)-1; ++i, ++p) {
|
|
if (*p == '\\' && p[1] == '\\') {
|
|
p++;
|
|
}
|
|
SourceFileName[i] = *p;
|
|
}
|
|
SourceFileName[i] = '\0';
|
|
StatementLineNumber = SourceLineNumber;
|
|
} else {
|
|
ExitErrMsg(FALSE, "Unknown '#' directive (%s).\n", Line);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
LexNextStatement(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read from the input file and perform lexical analysis. On return, an
|
|
entire C-language statement has been tokenized. Use CurrentToken(),
|
|
ConsumeToken(), and CurrentTokenIndex to access the tokenized statement.
|
|
|
|
The preprocessor recognizes #pragma and #line directives, ignoring all
|
|
other directives.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if analysis successful.
|
|
- Tokens[] is filled in with the tokenized statement
|
|
- CurrentTokenIndex is set to 0
|
|
- StatmentLineNumber is the line number in the original header file
|
|
corresponding to the first token in the statement
|
|
- SourceFileName[] is the name of the current header file
|
|
- SourceFileLineNumber is the current line number in the header file
|
|
FALSE if end-of-file encountered.
|
|
|
|
--*/
|
|
{
|
|
static char Line[MAX_CHARS_IN_LINE+2]; // a line from the .pp file
|
|
static char *p; // ptr into Line[]
|
|
BOOL fParseDone;
|
|
|
|
//
|
|
// Clean up after the previous statment and prep for the next statement
|
|
//
|
|
ResetLexer();
|
|
StatementLineNumber = SourceLineNumber;
|
|
|
|
//
|
|
// Lex source lines until a complete statement is recognized. That
|
|
// occurs when a ';' character is found at file-scope.
|
|
//
|
|
do {
|
|
|
|
if (p == NULL || *p == '\0') {
|
|
do {
|
|
//
|
|
// Get an entire source line from the file, and set p to
|
|
// point to the first non-space character
|
|
//
|
|
if (feof(fpHeaders)) {
|
|
return FALSE;
|
|
}
|
|
|
|
SourceLineNumber++;
|
|
if (!fgets(Line, MAX_CHARS_IN_LINE, fpHeaders)) {
|
|
return FALSE;
|
|
}
|
|
for (p = Line; isspace(*p); ++p)
|
|
;
|
|
} while (*p == '\0');
|
|
}
|
|
|
|
StatementLineNumber = SourceLineNumber;
|
|
p = LexOneLine(p, TRUE, &fParseDone);
|
|
|
|
} while (!fParseDone);
|
|
|
|
CurrentTokenIndex = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ConsumeDeclSpecOpt(
|
|
BOOL IsFunc,
|
|
BOOL bInitReturns,
|
|
BOOL *pIsDllImport,
|
|
BOOL *pIsGuidDefined,
|
|
GUID *pGuid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Comsumes a __declspec modifier. Returns are unaffected if the corresponding
|
|
__declspec is not found.
|
|
|
|
|
|
Accepts:
|
|
<not a __declspec keyword>
|
|
__declspec()
|
|
__declspec(naked) (only if parsing functions)
|
|
__declspec(thread) (only if parsing data)
|
|
__declspec(novtable) (only if parsing data)
|
|
__declspec(uuid(GUID)) (only if parsing data)
|
|
__declspec(dllimport) (both functions and data)
|
|
__declspec(dllexport) (both functions and data)
|
|
__declspec(align(x)) (only if parsing data)
|
|
|
|
Arguments:
|
|
|
|
IsFunc -- TRUE if parsing a function declaration, FALSE if parsing
|
|
a data/object declaration. Affects which keywords are
|
|
allowed within the __declspec.
|
|
bInitReturns -- TRUE if returns should be initialized to FALSE.
|
|
pIsDllImport -- [OPTIONAL OUT] set to TRUE if __declspec(dllimport) found
|
|
pIsGuidDefined -- [OPTIONAL OUT] set to TRUE if __declspec(uuid(GUID)) found
|
|
pGuid -- [OPTIONAL OUT] set to guid of __declspec(uuid(GUID)) if found.
|
|
|
|
Return Value:
|
|
|
|
TRUE if __declspec consumed OK, FALSE if __declspec parse error.
|
|
|
|
--*/
|
|
{
|
|
|
|
int OldTokenIndex;
|
|
OldTokenIndex = CurrentTokenIndex;
|
|
|
|
if (bInitReturns) {
|
|
if (pIsDllImport != NULL) *pIsDllImport = FALSE;
|
|
if (pIsGuidDefined != NULL) *pIsGuidDefined = FALSE;
|
|
}
|
|
|
|
if (CurrentToken()->TokenType != TK_DECLSPEC) {
|
|
// Reject: no __declspec found
|
|
goto dofail;
|
|
}
|
|
ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType != TK_LPAREN) {
|
|
// Reject: __declspec found without '(' following
|
|
goto dofail;
|
|
}
|
|
ConsumeToken();
|
|
|
|
if (CurrentToken()->TokenType == TK_RPAREN) {
|
|
// Accept: "__declspec ()"
|
|
ConsumeToken();
|
|
return TRUE;
|
|
}
|
|
else if (CurrentToken()->TokenType != TK_IDENTIFIER) {
|
|
goto dofail;
|
|
}
|
|
|
|
//handle cases for both data and functions
|
|
if (strcmp(CurrentToken()->Name, "dllimport") == 0) {
|
|
//Parsing: __declspec(dllimport
|
|
if (NULL != pIsDllImport) *pIsDllImport = TRUE;
|
|
ConsumeToken();
|
|
}
|
|
else if (strcmp(CurrentToken()->Name, "dllexport") == 0) {
|
|
//Parsing: __declspec(dllexport
|
|
ConsumeToken();
|
|
}
|
|
else if (IsFunc) {
|
|
if (strcmp(CurrentToken()->Name, "naked") == 0) {
|
|
//Parsing: __declspec(naked
|
|
ConsumeToken();
|
|
} else if (strcmp(CurrentToken()->Name, "noreturn") == 0) {
|
|
//Parsing: __declspec(noreturn
|
|
ConsumeToken();
|
|
} else if (strcmp(CurrentToken()->Name, "address_safe") == 0) {
|
|
//Parsing: __declspec(address_safe
|
|
ConsumeToken();
|
|
} else if (strcmp(CurrentToken()->Name, "noalias") == 0) {
|
|
//Parsing: __declspec(address_safe
|
|
ConsumeToken();
|
|
} else if (strcmp(CurrentToken()->Name, "restrict") == 0) {
|
|
//Parsing: __declspec(address_safe
|
|
ConsumeToken();
|
|
}
|
|
else goto dofail; //reject
|
|
}
|
|
else { //data
|
|
if (strcmp(CurrentToken()->Name, "thread") == 0) {
|
|
//Parsing: __declspec(thread
|
|
ConsumeToken();
|
|
}
|
|
else if (strcmp(CurrentToken()->Name, "novtable") == 0) {
|
|
//Parsing: __declspec(novtable
|
|
ConsumeToken();
|
|
}
|
|
else if (strcmp(CurrentToken()->Name, "uuid") == 0) {
|
|
GUID gTemp;
|
|
//Parsing: __declspec(uuid
|
|
ConsumeToken();
|
|
if (CurrentToken()->TokenType != TK_LPAREN) goto dofail;
|
|
//Parsing: __declspec(uuid(
|
|
ConsumeToken();
|
|
if (CurrentToken()->TokenType != TK_STRING) goto dofail;
|
|
//Parsing: __declspec(uuid(guid
|
|
if(!ConvertStringToGuid(CurrentToken()->Name, &gTemp)) goto dofail;
|
|
ConsumeToken();
|
|
if (CurrentToken()->TokenType != TK_RPAREN) goto dofail;
|
|
//Parsing: __declspec(uuid(guid)
|
|
ConsumeToken();
|
|
if (pIsGuidDefined != NULL) *pIsGuidDefined = TRUE;
|
|
if (pGuid != NULL) *pGuid = gTemp;
|
|
}
|
|
else if (strcmp(CurrentToken()->Name, "align") == 0) {
|
|
ConsumeToken();
|
|
if (CurrentToken()->TokenType != TK_LPAREN) goto dofail;
|
|
ConsumeToken();
|
|
expr();
|
|
if (CurrentToken()->TokenType != TK_RPAREN) goto dofail;
|
|
ConsumeToken();
|
|
}
|
|
else goto dofail; //reject
|
|
}
|
|
|
|
if (CurrentToken()->TokenType != TK_RPAREN) {
|
|
// Reject: expect ')' after __declspec(extended-decl-modifier)
|
|
goto dofail;
|
|
}
|
|
ConsumeToken();
|
|
|
|
// Accept: __declspec(extended-decl-modifier)
|
|
return TRUE;
|
|
|
|
dofail:
|
|
CurrentTokenIndex = OldTokenIndex;
|
|
return FALSE;
|
|
}
|
|
|
|
PTYPEINFOELEMENT
|
|
TypeInfoElementAllocateLink(
|
|
PTYPEINFOELEMENT *ppHead,
|
|
PTYPEINFOELEMENT pThis,
|
|
TYPESINFO *pType
|
|
)
|
|
{
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a TYPEINFOELEMENT and linked it to the end of the list.
|
|
|
|
Arguments:
|
|
|
|
ppHead - [IN/OUT] ptr ptr to the head of the list.
|
|
pThis - [IN] ptr to the tail of the list.
|
|
pType - [IN] ptr to the typeinfo to add to the list.
|
|
|
|
Return Value:
|
|
|
|
NON-NULL - New tail.
|
|
NULL - Failure.
|
|
--*/
|
|
|
|
PTYPEINFOELEMENT pNew= GenHeapAlloc(sizeof(struct TypeInfoListElement));
|
|
if (NULL == pNew) ExitErrMsg(FALSE, "Out of memory!");
|
|
pNew->pNext = NULL;
|
|
pNew->pTypeInfo = pType;
|
|
if (NULL == pThis) *ppHead = pNew;
|
|
else pThis->pNext = pNew;
|
|
return pNew;
|
|
}
|
|
|
|
BOOL
|
|
AddVariable(
|
|
char *Name,
|
|
GUID * pGuid
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a variable to the list of declared global variabled.
|
|
|
|
Arguments:
|
|
|
|
Name - [IN] ptr to name of variable to add.
|
|
pGuid - [OPTIONAL IN] ptr to guid for this variable.
|
|
|
|
Return Value:
|
|
|
|
TRUE - if success.
|
|
--*/
|
|
PKNOWNTYPES pKnownTypes;
|
|
int Len;
|
|
|
|
if(NULL == Name) return FALSE;
|
|
|
|
//Already in the tree
|
|
pKnownTypes = RBFind(VarsList, Name);
|
|
if (NULL != pKnownTypes) {
|
|
//replace guid in list if pGuid != NULL and ignore the duplication
|
|
if (NULL != pGuid) {
|
|
pKnownTypes->Flags |= BTI_HASGUID;
|
|
pKnownTypes->gGuid = *pGuid;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//Create a KNOWNTYPES structure for variable
|
|
Len = sizeof(KNOWNTYPES) + strlen(Name) + 1;
|
|
pKnownTypes = GenHeapAlloc(Len);
|
|
if(NULL == pKnownTypes) return FALSE;
|
|
|
|
memset(pKnownTypes, 0, Len);
|
|
pKnownTypes->TypeName = pKnownTypes->Names;
|
|
strcpy(pKnownTypes->Names, Name);
|
|
if(NULL != pGuid) {
|
|
pKnownTypes->Flags |= BTI_HASGUID;
|
|
pKnownTypes->gGuid = *pGuid;
|
|
}
|
|
|
|
RBInsert(VarsList, pKnownTypes);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
UpdateGuids(
|
|
VOID
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Looks for variables of whose name starts with IID_ and assigned a guid structure.
|
|
The IID_ is striped and the guid of the corresponding struct is updated
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
PKNOWNTYPES pThis;
|
|
PKNOWNTYPES pLookup;
|
|
char *LookupName;
|
|
|
|
for(pThis = VarsList->pLastNodeInserted; pThis != NULL; pThis = pThis->Next) {
|
|
|
|
//test if name has guid associated with it and that it begins with IID_
|
|
if ((pThis->Flags & BTI_HASGUID) &&
|
|
pThis->TypeName[0] == 'I' &&
|
|
pThis->TypeName[1] == 'I' &&
|
|
pThis->TypeName[2] == 'D' &&
|
|
pThis->TypeName[3] == '_' )
|
|
{
|
|
//Attempt to find a structure with the name except the IID_
|
|
LookupName = pThis->TypeName + 4; //skip the IID_
|
|
pLookup = RBFind(StructsList, LookupName);
|
|
|
|
if(NULL != pLookup) {
|
|
|
|
//if types does not have a GUID defined already, copy guid from here
|
|
if (!(pLookup->Flags & BTI_HASGUID)) {
|
|
pLookup->Flags |= BTI_HASGUID;
|
|
pLookup->gGuid = pThis->gGuid;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|