📄 cparser.c
字号:
/****************************************************************************************/
/* 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 + -