/* token.c $Id: token.c,v 1.5 2007/07/08 17:01:15 sezero Exp $ */ // HEADER FILES ------------------------------------------------------------ #include "util_inc.h" #include "cmdlib.h" #include "util_io.h" #include "token.h" // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- typedef enum { CHR_EOF, CHR_LETTER, CHR_NUMBER, CHR_QUOTE, CHR_SPECIAL } chr_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void ProcessLetterToken(void); static void ProcessNumberToken(void); static void ProcessQuoteToken(void); static void ProcessSpecialToken(void); static qboolean CheckForKeyword(void); static void NextChr(void); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- tokenType_t tk_Token; int tk_Line; int tk_IntNumber; float tk_FloatNumber; char *tk_String; char tk_SourceName[MAX_FILE_NAME_LENGTH]; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static char Chr; static char *FileStart; static char *FilePtr; static char *FileEnd; static qboolean SourceOpen; static char ASCIIToChrCode[256]; static char TokenStringBuffer[MAX_QUOTED_LENGTH]; static qboolean IncLineNumber; static char TempBuffer[2048]; static struct { char *name; tokenType_t token; } Keywords[] = { { "model", TK_MODEL }, { "mesh", TK_MESH }, { "vertices", TK_VERTICES }, { "position", TK_POSITION }, { "polygons", TK_POLYGONS }, { "nodes", TK_NODES }, { "rotation", TK_ROTATION }, { "scaling", TK_SCALING }, { "translation", TK_TRANSLATION }, { "vertex", TK_VERTEX }, { "HRCH", TK_HRCH }, { "Softimage", TK_SOFTIMAGE }, { "Named", TK_C_NAMED }, { "object", TK_OBJECT }, { "Tri", TK_C_TRI }, { "Vertices", TK_C_VERTICES }, { "Faces", TK_C_FACES }, { "Vertex", TK_C_VERTEX }, { "list", TK_LIST }, { "Face", TK_C_FACE }, { "Hexen", TK_C_HEXEN }, { "Triangles", TK_C_TRIANGLES }, { "Version", TK_C_VERSION }, { "faces", TK_FACES }, { "face", TK_FACE }, { "origin", TK_ORIGIN }, { NULL, TK_BAD } }; static char *TokenNames[] = { "", "", "", "", "", "", "", "(", ")", "{", "}", "[", "]", ":", "mesh", "model", "nodes", "rotation", "scaling", "translation", "polygons", "position", "vertex", "vertices", "HRCH", "Softimage" }; // CODE -------------------------------------------------------------------- //========================================================================== // // TK_Init // //========================================================================== void TK_Init(void) { int i; for (i = 0; i < 256; i++) { ASCIIToChrCode[i] = CHR_SPECIAL; } for (i = '0'; i <= '9'; i++) { ASCIIToChrCode[i] = CHR_NUMBER; } for (i = 'A'; i <= 'Z'; i++) { ASCIIToChrCode[i] = CHR_LETTER; } for (i = 'a'; i <= 'z'; i++) { ASCIIToChrCode[i] = CHR_LETTER; } ASCIIToChrCode[ASCII_QUOTE] = CHR_QUOTE; ASCIIToChrCode[ASCII_UNDERSCORE] = CHR_LETTER; ASCIIToChrCode[EOF_CHARACTER] = CHR_EOF; tk_String = TokenStringBuffer; IncLineNumber = FALSE; SourceOpen = FALSE; } //========================================================================== // // TK_OpenSource // //========================================================================== void TK_OpenSource(char *fileName) { int size; TK_CloseSource(); size = LoadFile(fileName, (void **) (char *) &FileStart); strcpy(tk_SourceName, fileName); SourceOpen = TRUE; FileEnd = FileStart+size; FilePtr = FileStart; tk_Line = 1; tk_Token = TK_NONE; NextChr(); } //========================================================================== // // TK_CloseSource // //========================================================================== void TK_CloseSource(void) { if (SourceOpen) { free(FileStart); SourceOpen = FALSE; } } //========================================================================== // // TK_Fetch // //========================================================================== tokenType_t TK_Fetch(void) { while (Chr == ASCII_SPACE) { NextChr(); } if (Chr == '-') { ProcessNumberToken(); } else switch (ASCIIToChrCode[(byte)Chr]) { case CHR_EOF: tk_Token = TK_EOF; break; case CHR_LETTER: ProcessLetterToken(); break; case CHR_NUMBER: ProcessNumberToken(); break; case CHR_QUOTE: ProcessQuoteToken(); break; default: ProcessSpecialToken(); break; } return tk_Token; } //========================================================================== // // TK_Require // //========================================================================== void TK_Require(tokenType_t tokType) { if (tokType == TK_FLOATNUMBER && tk_Token == TK_INTNUMBER) { tk_FloatNumber = (float)tk_IntNumber; tk_Token = TK_FLOATNUMBER; return; } if (tk_Token != tokType) { Error("File '%s', line %d:\nExpected '%s', found '%s'.\n", tk_SourceName, tk_Line, TokenNames[tokType], TokenNames[tk_Token]); } } void TK_FetchRequire(tokenType_t tokType) { TK_Fetch(); TK_Require(tokType); } tokenType_t TK_RequireFetch(tokenType_t tokType) { TK_Require(tokType); return TK_Fetch(); } tokenType_t TK_FetchRequireFetch(tokenType_t tokType) { TK_Fetch(); TK_Require(tokType); return TK_Fetch(); } tokenType_t TK_Beyond(tokenType_t tokType) { while (tk_Token != tokType) { if (TK_Fetch() == TK_EOF) { Error("File '%s':\nCould not find token '%s'.\n", tk_SourceName, TokenNames[tokType]); } } return TK_Fetch(); } void TK_BeyondRequire(tokenType_t bTok, tokenType_t rTok) { TK_Beyond(bTok); TK_Require(rTok); } //========================================================================== // // ProcessLetterToken // //========================================================================== static void ProcessLetterToken(void) { int i; char *text; i = 0; text = TokenStringBuffer; while (ASCIIToChrCode[(byte)Chr] == CHR_LETTER || ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) { if (++i == MAX_IDENTIFIER_LENGTH) { Error("File '%s', line %d:\nIdentifier too long.\n", tk_SourceName, tk_Line); } *text++ = Chr; NextChr(); } *text = 0; if (CheckForKeyword() == FALSE) { tk_Token = TK_IDENTIFIER; } } //========================================================================== // // CheckForKeyword // //========================================================================== static qboolean CheckForKeyword(void) { int i; for (i = 0; Keywords[i].name != NULL; i++) { if (strcmp(tk_String, Keywords[i].name) == 0) { tk_Token = Keywords[i].token; return TRUE; } } return FALSE; } //========================================================================== // // ProcessNumberToken // //========================================================================== static void ProcessNumberToken(void) { char *buffer; buffer = TempBuffer; *buffer++ = Chr; NextChr(); while (ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) { *buffer++ = Chr; NextChr(); } if (Chr == '.') { // Float *buffer++ = Chr; NextChr(); // Skip period while (ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) { *buffer++ = Chr; NextChr(); } *buffer = 0; tk_FloatNumber = (float)atof(TempBuffer); tk_Token = TK_FLOATNUMBER; return; } // Integer *buffer = 0; tk_IntNumber = atoi(TempBuffer); tk_Token = TK_INTNUMBER; } //========================================================================== // // ProcessQuoteToken // //========================================================================== static void ProcessQuoteToken(void) { int i; char *text; i = 0; text = TokenStringBuffer; NextChr(); while (Chr != ASCII_QUOTE) { if (Chr == EOF_CHARACTER) { Error("File '%s', line %d:\n inside string.\n", tk_SourceName, tk_Line); } if (++i > MAX_QUOTED_LENGTH-1) { Error("File '%s', line %d:\nString literal too long.\n", tk_SourceName, tk_Line); } *text++ = Chr; NextChr(); } *text = 0; NextChr(); tk_Token = TK_STRING; } //========================================================================== // // ProcessSpecialToken // //========================================================================== static void ProcessSpecialToken(void) { char c; c = Chr; NextChr(); switch (c) { case '(': tk_Token = TK_LPAREN; break; case ')': tk_Token = TK_RPAREN; break; case '{': tk_Token = TK_LBRACE; break; case '}': tk_Token = TK_RBRACE; break; case '[': tk_Token = TK_LBRACKET; break; case ']': tk_Token = TK_RBRACKET; break; case ':': tk_Token = TK_COLON; break; default: tk_Token = TK_UNKNOWNCHAR; break; } } //========================================================================== // // NextChr // //========================================================================== static void NextChr(void) { if (FilePtr >= FileEnd) { Chr = EOF_CHARACTER; return; } if (IncLineNumber == TRUE) { tk_Line++; IncLineNumber = FALSE; } Chr = *FilePtr++; if (Chr < ASCII_SPACE) { if (Chr == '\n') { IncLineNumber = TRUE; } Chr = ASCII_SPACE; } }