⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cparser.c

📁 3D游戏场景编辑器
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************************/
/*  CPARSER.C                                                                           */
/*                                                                                      */
/*  Author: Eli Boling                                                                  */
/*  Description: Partial parser for C code.                                             */
/*                                                                                      */
/*  The contents of this file are subject to the Genesis3D Public License               */
/*  Version 1.01 (the "License"); you may not use this file except in                   */
/*  compliance with the License. You may obtain a copy of the License at                */
/*  http://www.genesis3d.com                                                            */
/*                                                                                      */
/*  Software distributed under the License is distributed on an "AS IS"                 */
/*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
/*  the License for the specific language governing rights and limitations              */
/*  under the License.                                                                  */
/*                                                                                      */
/*  The Original Code is Genesis3D, released March 25, 1999.                            */
/*Genesis3D Version 1.1 released November 15, 1999                            */
/*  Copyright (C) 1999 WildTangent, Inc. All Rights Reserved           */
/*                                                                                      */
/****************************************************************************************/
#ifdef	__BORLANDC__
#include	<dir.h>
#else
#define	MAXPATH	_MAX_PATH
#endif
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<assert.h>
#include	<setjmp.h>
#include	<stdarg.h>

#include	"iden.h"
#include	"cscanner.h"
#include	"cparser.h"
#include	"type.h"
#include	"symtab.h"
#include	"ram.h"
#include	"util.h"
#include	"..\filepath.h"

#define	CONTENTS_USER_MASK	(0xFFFF0000)

static	char *	KeywordNames[] =
{
	"typedef",
	"struct",
	"int",
	"char",
	"float",
	"geFloat",
	"GE_RGBA",
	"geWorld_Model",
	"geVec3d",
	"pragma",
	"void",
	"enum",
	"geBoolean",
};

static	jmp_buf	parserError;

#define	NUMKEYWORDS	(sizeof(KeywordNames) / sizeof(KeywordNames[0]))

#define	KW_NOTAKEYWORD	0
#define	KW_TYPEDEF		1
#define KW_STRUCT		2
#define	KW_INT			3
#define	KW_CHAR			4
#define	KW_FLOAT		5
#define	KW_GE_FLOAT		6
#define	KW_GE_RGB		7
#define	KW_GE_MODEL		8
#define	KW_VEC3D		9
#define	KW_PRAGMA		10
#define	KW_VOID			11
#define	KW_ENUM			12
#define KW_BOOLEAN		13

typedef	struct	CParser_BrushEnumValue
{
	Iden *			Name;
	unsigned long	Value;
}	CParser_BrushEnumValue;

typedef	struct	CParser
{
	Scanner *					cpScanner;
	Iden_HashTable *			cpIdenHashTable;
	int							cpNestingLevel;
	Type *						cpTypes;
	Iden *						cpNoName;
	SymTab *					cpSymbolTable;
	SymTab_Scope *				cpGlobalScope;
	Type *						cpVoidType;
	CParser_ErrFunc				cpErrorFunc;
	int							cpBrushContentsCount;
	CParser_BrushEnumValue *	cpBrushContents;
}	CParser;

#define ERR_EXPECTEDPOINTER			0
#define ERR_EXPECTEDIDEN			1
#define ERR_EXPECTEDSEMI			2
#define ERR_SYNTAXERROR				3
#define ERR_EXPECTEDFIELDNAME		4
#define ERR_LIMITEDSTRUCTSUPPORT	5
#define ERR_ILLEGALTYPEREDEFINITION	6
#define	ERR_BADFORWARDTYPEDEF		7
#define ERR_ONLYPRAGMA				8
#define	ERR_EXPECTEDTYPENAME		9
#define	ERR_UNDEFINEDTYPE			10
#define	ERR_OUTOFMEMORY				11
#define	ERR_EXPECTEDENUM			12
#define	ERR_EXPECTEDRBRACE			13
#define	ERR_VALUENOTINRANGE			14
#define ERR_BADREDEFINITION			15
#define ERR_VALUEUSEDTWICE			16

static	char *	ErrStrings[] =
{
	"Expected a pointer declaration",
	"Expected an identifier",
	"Expected a semicolon",
	"Syntax error",
	"Expected a field name",
	"Structs must be of the form 'typedef struct tagfoo { } foo' or 'typedef struct tagfoo foo'",
	"Illegal type definition",
	"Bad forward type declaration",
	"Only pragma directives allowed inside structure definitions",
	"Expected a type name",
	"Undefined type '%s'",
	"Out of memory",
	"Expected enum keyword",
	"Expected a '}'",
	"A numeric value was not in the expected range",
	"Redefinition of a symbol",
	"Value already defined",
};

static	const char *	LoadErrorString(int errCode)
{
	return ErrStrings[errCode];
}

CParser *	CParser_Init(CParser_ErrFunc errFunc)
{
	CParser *	p;
	int			i;

	p = geRam_Allocate(sizeof(*p));
	if	(!p)
		return p;

	memset(p, 0, sizeof(*p));

	p->cpErrorFunc = errFunc;

	p->cpSymbolTable = SymTab_Create();
	if	(!p->cpSymbolTable)
	{
		CParser_Destroy(p);
		return NULL;
	}

	p->cpGlobalScope = SymTab_CreateScope(p->cpSymbolTable, NULL, F_SCP_FILE);
	if	(!p->cpGlobalScope)
	{
		CParser_Destroy(p);
		return NULL;
	}

	p->cpIdenHashTable = Iden_CreateHashTable();
	if	(!p->cpIdenHashTable)
	{
		CParser_Destroy(p);
		return NULL;
	}

	p->cpNoName = Iden_HashName(p->cpIdenHashTable, "<no name>", 9);
	if	(!p->cpNoName)
	{
		CParser_Destroy(p);
		return NULL;
	}

	p->cpScanner = CScanner_Create ();
	if (p->cpScanner == NULL)
	{
		CParser_Destroy (p);
		return NULL;
	}

	for	(i = 0; i < NUMKEYWORDS; i++)
	{
		Iden *	id;
		id = Iden_HashName(p->cpIdenHashTable, KeywordNames[i], strlen(KeywordNames[i]));
		id->idenKeyword = i + 1;
	}

	p->cpTypes = Type_InitTypeList(p->cpIdenHashTable);

	if	(p->cpTypes == NULL)
	{
		CParser_Destroy (p);
		return NULL;
	}

	p->cpVoidType = Type_FindTypeByName(p->cpTypes, Iden_HashName(p->cpIdenHashTable, "void", 4));
	if	(!p->cpVoidType)
	{
		CParser_Destroy (p);
		return NULL;
	}

	return p;
}

void	CParser_Destroy(CParser *p)
{
	assert(p);

	if (p->cpScanner != NULL)
	{
		Scanner_Destroy(p->cpScanner);
	}

	if	(p->cpBrushContents != NULL)
	{
		assert(p->cpBrushContentsCount > 0);
		geRam_Free(p->cpBrushContents);
	}

	if (p->cpGlobalScope != NULL)
	{
		SymTab_DestroyScope(p->cpGlobalScope);
	}

	if (p->cpSymbolTable != NULL)
	{
		SymTab_Destroy(p->cpSymbolTable);
	}

	if (p->cpTypes != NULL)
	{
		Type_DestroyTypeList(p->cpTypes);
	}

	if (p->cpIdenHashTable != NULL)
	{
		Iden_DestroyHashTable(p->cpIdenHashTable);
	}

	geRam_Free (p);
}

#ifdef	ELIDEBUG
static	void	printToken(const Scanner_Token *t)
{
//static	count = 0;
//	printf("% 3d: ", count++);
	switch	(t->tKind)
	{
	case	TK_IDEN:
//		printf("<TK_IDEN: '%s'>\n", t->tTokenData);
		printf("<TK_IDEN: '%s'>\n", t->tIden->idenSpelling);
		break;
	case	TK_ICON:
		printf("<TK_ICON: '%d'>\n", t->tICONValue);
		break;
	case	TK_FCON:
		printf("<TK_FCON: '%f'>\n", t->tFCONValue);
		break;
	case	TK_LPAREN:
		printf("<TK_LPAREN>\n");
		break;
	case	TK_RPAREN:
		printf("<TK_RPAREN>\n");
		break;
	case	TK_LBRACE:
		printf("<TK_LBRACE>\n");
		break;
	case	TK_RBRACE:
		printf("<TK_RBRACE>\n");
		break;
	case	TK_SEMI:
		printf("<TK_SEMI>\n");
		break;
	case	TK_EQUAL:
		printf("<TK_EQUAL>\n");
		break;
	case	TK_PLUS:
		printf("<TK_PLUS>\n");
		break;
	case	TK_SHARP:
		printf("<TK_SHARP>\n");
		break;
	case	TK_STAR:
		printf("<TK_STAR>\n");
		break;
	case	TK_EOF:
		printf("<TK_EOF>\n");
		break;
	default:
		printf("<Illegal token>\n");
		break;
	}
}
#endif

static	void	CParser_Error(CParser *p, int errCode, ...)
{
	Scanner_Token	t;
	va_list			ap;
	char			buff[1024];
	char			buff2[1024];

	va_start(ap, errCode);
	
#ifdef	DEBUG
	memset(buff, 0, sizeof(buff);
#endif
	vsprintf(buff, LoadErrorString(errCode), ap);
#ifdef	DEBUG
	assert(buff[sizeof(buff) - 1] == 0);
#endif
	va_end(ap);

	sprintf(buff2,
			"Error %s %d: %s\n",
			Scanner_GetFileName(p->cpScanner),
			Scanner_GetLineNo(p->cpScanner),
			buff);
 	
 	if	(p->cpErrorFunc)
 	{
		p->cpErrorFunc(Scanner_GetFileName(p->cpScanner),
					   Scanner_GetLineNo(p->cpScanner),
					   buff2);
	}
	else
	{
		printf("%s", buff2);
	}

	for (;;)
	{
		Scanner_Scan(p->cpScanner, &t);

		if	(t.tKind == TK_LBRACE)
			p->cpNestingLevel++;
		if	(t.tKind == TK_RBRACE)
			p->cpNestingLevel++;
		if	(p->cpNestingLevel == 0)
			break;
		if	(t.tKind == TK_EOF)
			break;
	}
	longjmp(parserError, 1);
}

static	void	CParser_ParseUserDecl(CParser *p, Type *tp, Iden *fieldTypeName, int publishing)
{
	Scanner_Token	t;
	SymTab_Symbol *	fieldSym;
	Type *			ptrTp;
	Type *			fieldTp;
	
	Scanner_Scan(p->cpScanner, &t);
	if	(t.tKind != TK_STAR)
		CParser_Error(p, ERR_EXPECTEDPOINTER);

	fieldTp = Type_FindTypeByName(p->cpTypes, fieldTypeName);
	if	(!fieldTp)
	{
		if	(publishing)
		{
			CParser_Error(p, ERR_UNDEFINEDTYPE, fieldTypeName->idenSpelling);
		}
		else
		{
			fieldTp = Type_FindTypeByName(p->cpTypes, p->cpVoidType->tpName);
			// Could be multiple pointers here.  Burn them off.
			assert(t.tKind == TK_STAR);
			while	(t.tKind == TK_STAR)
				Scanner_Scan(p->cpScanner, &t);

			if	(t.tKind != TK_IDEN)
				CParser_Error(p, ERR_EXPECTEDIDEN);
		}
	}
	else
	{
		Scanner_Scan(p->cpScanner, &t);
		if	(t.tKind != TK_IDEN)
			CParser_Error(p, ERR_EXPECTEDIDEN);
	}
	ptrTp = Type_CreatePtrType(&p->cpTypes, fieldTp);

	fieldSym = SymTab_CreateSymbol(p->cpSymbolTable, tp->tpScope, t.tIden, ptrTp);
	Type_AddTypeField(tp, fieldSym, (unsigned short)(publishing ? F_TF_PUBLISHED : 0));

	Scanner_Scan(p->cpScanner, &t);
	if	(t.tKind != TK_SEMI)
		CParser_Error(p, ERR_EXPECTEDSEMI);
}

static	void	ScanExpecting(CParser *p, Scanner_Token *t, CScanner_TokenKind kind)
{
	Scanner_Scan(p->cpScanner, t);
	if	(t->tKind != kind)
		CParser_Error(p, ERR_SYNTAXERROR);
}

static	void	ParseDefaultValue(CParser *p, Type *tp)
{
	Scanner_Token	t;
	TypeField *		tf;

	ScanExpecting(p, &t, TK_LPAREN);
	ScanExpecting(p, &t, TK_IDEN);
	tf = Type_GetTypeField(tp, t.tIden);
	if	(!tf)
		CParser_Error(p, ERR_EXPECTEDFIELDNAME);
	ScanExpecting(p, &t, TK_COMMA);
	ScanExpecting(p, &t, TK_LITERALSTRING);
	tf->tfDefaultValue = Util_Strdup (t.tTokenData);
	if	(!tf->tfDefaultValue)
		CParser_Error(p, ERR_OUTOFMEMORY);
	ScanExpecting(p, &t, TK_RPAREN);
}

static	Type *	FindType(CParser *p, Iden *name)
{
	SymTab_Symbol *	sym;

	sym = SymTab_FindSymbolInScope(p->cpSymbolTable, p->cpGlobalScope, name);
	if	(!sym)
		return NULL;

	return sym->symType;
}

static void CParser_ParseSpecialField (CParser *p, Type *tp, TypeField **ptfRslt)
{
	TypeField *		tf;
	Scanner_Token	t;


	ScanExpecting(p, &t, TK_LPAREN);
	ScanExpecting(p, &t, TK_IDEN);
	tf = Type_GetTypeField(tp, t.tIden);
	if	(!tf)
		CParser_Error(p, ERR_EXPECTEDFIELDNAME);
	ScanExpecting(p, &t, TK_RPAREN);
	*ptfRslt = tf;
}

static	void	CParser_ParsePrivatePtrDecl(CParser *p, Type *tp, Scanner_Token *t)
{
	SymTab_Symbol *	fieldSym;
	Type *			ptrTp;
	Type *			fieldTp;
	
	fieldTp = Type_FindTypeByName(p->cpTypes, p->cpVoidType->tpName);
	// Could be multiple pointers here.  Burn them off.
	assert(t->tKind == TK_STAR);
	while	(t->tKind == TK_STAR)
		Scanner_Scan(p->cpScanner, t);

	if	(t->tKind != TK_IDEN)
		CParser_Error(p, ERR_EXPECTEDIDEN);

	ptrTp = Type_CreatePtrType(&p->cpTypes, fieldTp);

	fieldSym = SymTab_CreateSymbol(p->cpSymbolTable, tp->tpScope, t->tIden, ptrTp);
	Type_AddTypeField(tp, fieldSym, (unsigned short)0);

	Scanner_Scan(p->cpScanner, t);
	if	(t->tKind != TK_SEMI)
		CParser_Error(p, ERR_EXPECTEDSEMI);
}

static	void	CParser_ParseStruct(CParser *p, const char *typeIcon)
{
	Scanner_Token	t;
	Type *			tp;
	SymTab_Symbol *	fieldSym;
	Type *			fieldTp;
	int				publishing;

	publishing = 0;

	/* Expect: struct <iden> { */
	Scanner_Scan(p->cpScanner, &t);
	if	(t.tKind != TK_IDEN || t.tIden->idenKeyword != KW_NOTAKEYWORD)
		CParser_Error(p, ERR_LIMITEDSTRUCTSUPPORT);

	tp = FindType(p, t.tIden);
	if	(!tp)
	{
		tp = Type_CreateType(&p->cpTypes, t.tIden, 0);
		tp->tpScope = p->cpGlobalScope;
		SymTab_CreateSymbol(p->cpSymbolTable, tp->tpScope, t.tIden, tp);
	}
	else
	{
		if	(tp->tpTopType != T_STRUCT || tp->t.s.tpFields)
			CParser_Error(p, ERR_ILLEGALTYPEREDEFINITION);
	}
	if (tp->t.s.tpIcon != NULL)
	{
		geRam_Free (tp->t.s.tpIcon);
	}
	{
		// prepend the current file's path to the icon file name
		const char *scnFilename;
		char WorkFilename[300];

		scnFilename = Scanner_GetFileName (p->cpScanner);
		FilePath_GetDriveAndDir (scnFilename, WorkFilename);
		FilePath_AppendName (WorkFilename, typeIcon, WorkFilename);
		tp->t.s.tpIcon = Util_Strdup (WorkFilename);
		if	(!tp->t.s.tpIcon)
			CParser_Error(p, ERR_OUTOFMEMORY);
	}

	Scanner_Scan(p->cpScanner, &t);
	if	(t.tKind != TK_LBRACE)
	{
		/* This must be something of the form 'typedef struct tagfoo foo' */
		if	(t.tKind != TK_IDEN)
			CParser_Error(p, ERR_BADFORWARDTYPEDEF);
				
		ScanExpecting(p, &t, TK_SEMI);
		return;
	}

	p->cpNestingLevel++;

	for (;;)
	{
		Scanner_Scan(p->cpScanner, &t);

		while	(t.tKind == TK_SHARP)
		{
			ScanExpecting(p, &t, TK_IDEN);
			if	(t.tIden->idenKeyword != KW_PRAGMA)
				CParser_Error(p, ERR_ONLYPRAGMA);
			ScanExpecting(p, &t, TK_IDEN);
			if	(!strcmp(t.tIden->idenSpelling, "GE_Published"))
				publishing = 1;
			if	(!strcmp(t.tIden->idenSpelling, "GE_Private"))
				publishing = 0;
			if	(!strcmp(t.tIden->idenSpelling, "GE_DefaultValue"))
				ParseDefaultValue(p, tp);
			if	(!strcmp(t.tIden->idenSpelling, "GE_Origin"))
				CParser_ParseSpecialField (p, tp, &tp->tpOriginField);
			if	(!strcmp(t.tIden->idenSpelling, "GE_Arc"))
				CParser_ParseSpecialField (p, tp, &tp->tpArcField);
			if	(!strcmp(t.tIden->idenSpelling, "GE_Angles"))
				CParser_ParseSpecialField (p, tp, &tp->tpAnglesField);
			if	(!strcmp(t.tIden->idenSpelling, "GE_Radius"))
				CParser_ParseSpecialField (p, tp, &tp->tpRadiusField);
			if	(!strcmp(t.tIden->idenSpelling, "GE_Documentation"))
			{
				TypeField *	tf;

				ScanExpecting(p, &t, TK_LPAREN);
				ScanExpecting(p, &t, TK_IDEN);
				tf = Type_GetTypeField(tp, t.tIden);
				if	(!tf)
					CParser_Error(p, ERR_EXPECTEDFIELDNAME);
				ScanExpecting(p, &t, TK_COMMA);
				ScanExpecting(p, &t, TK_LITERALSTRING);
				tf->tfDocumentation = Util_Strdup(t.tTokenData);
				if	(!tf->tfDocumentation)
					CParser_Error(p, ERR_OUTOFMEMORY);
				ScanExpecting(p, &t, TK_RPAREN);
			}

			Scanner_Scan(p->cpScanner, &t);
		}

		if	(t.tKind == TK_RBRACE)
		{
			ScanExpecting(p, &t, TK_IDEN);
			SymTab_CreateSymbol(p->cpSymbolTable, tp->tpScope, t.tIden, tp);
			tp->tpName = t.tIden;
			ScanExpecting(p, &t, TK_SEMI);
			return;
		}

		if	(t.tKind != TK_IDEN)
			CParser_Error(p, ERR_EXPECTEDTYPENAME);
		switch	(t.tIden->idenKeyword)
		{
		case	KW_NOTAKEYWORD:
			CParser_ParseUserDecl(p, tp, t.tIden, publishing);
			break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -