mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-01-31 03:50:36 +00:00
Cleanups
This commit is contained in:
parent
d5dcb3aff7
commit
639fc8a32b
7 changed files with 134 additions and 200 deletions
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ OBJ = main.o \
|
|||
error.o \
|
||||
parse.o \
|
||||
typedef.o \
|
||||
alloc.o
|
||||
util.o
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $< -o $@ $(CFLAGS)
|
||||
|
|
6
README
6
README
|
@ -30,9 +30,9 @@ typedef.c
|
|||
complicated than it sounds. This handles all typedefs, and even recrusive
|
||||
typedefs.
|
||||
|
||||
alloc.c
|
||||
This is just an allocator for the compiler, it's used for debugging reasons
|
||||
only.
|
||||
util.c
|
||||
These are utilities for the compiler, some things in here include a
|
||||
allocator used for debugging, and some string functions.
|
||||
|
||||
README
|
||||
This is the file you're currently reading
|
||||
|
|
54
alloc.c
54
alloc.c
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "gmqcc.h"
|
||||
|
||||
/*
|
||||
* The compiler has it's own memory tracker / allocator for debugging
|
||||
* reasons. It will help find things like buggy CSE or OOMs (if this
|
||||
* compiler ever grows to that point.)
|
||||
*/
|
||||
struct memblock_t {
|
||||
const char *file;
|
||||
unsigned int line;
|
||||
unsigned int byte;
|
||||
};
|
||||
|
||||
void *memory_a(unsigned int byte, unsigned int line, const char *file) {
|
||||
struct memblock_t *data = malloc(sizeof(struct memblock_t) + byte);
|
||||
if (!data) return NULL;
|
||||
data->line = line;
|
||||
data->byte = byte;
|
||||
data->file = file;
|
||||
printf("[MEM] allocation: %08u (bytes) at %s:%u\n", byte, file, line);
|
||||
return (void*)((uintptr_t)data+sizeof(struct memblock_t));
|
||||
}
|
||||
|
||||
void memory_d(void *ptrn, unsigned int line, const char *file) {
|
||||
if (!ptrn) return;
|
||||
void *data = (void*)((uintptr_t)ptrn-sizeof(struct memblock_t));
|
||||
struct memblock_t *info = (struct memblock_t*)data;
|
||||
printf("[MEM] released: %08u (bytes) at %s:%u\n", info->byte, file, line);
|
||||
free(data);
|
||||
}
|
224
gmqcc.h
224
gmqcc.h
|
@ -24,7 +24,109 @@
|
|||
#define GMQCC_HDR
|
||||
#include <stdio.h>
|
||||
|
||||
/* The types supported by the language */
|
||||
//===================================================================
|
||||
//============================ lex.c ================================
|
||||
//===================================================================
|
||||
struct lex_file {
|
||||
FILE *file;
|
||||
char peek [5];
|
||||
char lastok[8192];
|
||||
|
||||
int last;
|
||||
int current;
|
||||
int length;
|
||||
int size;
|
||||
};
|
||||
|
||||
/*
|
||||
* It's important that this table never exceed 32 keywords, the ascii
|
||||
* table starts at 33 (and we don't want conflicts)
|
||||
*/
|
||||
#define TOKEN_DO 0
|
||||
#define TOKEN_ELSE 1
|
||||
#define TOKEN_IF 2
|
||||
#define TOKEN_WHILE 3
|
||||
#define TOKEN_BREAK 4
|
||||
#define TOKEN_CONTINUE 5
|
||||
#define TOKEN_RETURN 6
|
||||
#define TOKEN_GOTO 7
|
||||
#define TOKEN_FOR 8 // extension
|
||||
#define TOKEN_TYPEDEF 9 // extension
|
||||
|
||||
// ensure the token types are out of the
|
||||
// bounds of anyothers that may conflict.
|
||||
#define TOKEN_FLOAT 110
|
||||
#define TOKEN_VECTOR 111
|
||||
#define TOKEN_STRING 112
|
||||
#define TOKEN_ENTITY 113
|
||||
#define TOKEN_VOID 114
|
||||
|
||||
/*
|
||||
* Lexer state constants, these are numbers for where exactly in
|
||||
* the lexing the lexer is at. Or where it decided to stop if a lexer
|
||||
* error occurs. These numbers must be > where the ascii-table ends
|
||||
* and > the last type token which is TOKEN_VOID
|
||||
*/
|
||||
#define LEX_COMMENT 1128
|
||||
#define LEX_CHRLIT 1129
|
||||
#define LEX_STRLIT 1130
|
||||
#define LEX_IDENT 1131
|
||||
|
||||
int lex_token(struct lex_file *);
|
||||
void lex_reset(struct lex_file *);
|
||||
void lex_close(struct lex_file *);
|
||||
struct lex_file *lex_open (FILE *);
|
||||
|
||||
//===================================================================
|
||||
//========================== error.c ================================
|
||||
//===================================================================
|
||||
#define ERROR_LEX (SHRT_MAX+0)
|
||||
#define ERROR_PARSE (SHRT_MAX+1)
|
||||
#define ERROR_INTERNAL (SHRT_MAX+2)
|
||||
#define ERROR_COMPILER (SHRT_MAX+3)
|
||||
#define ERROR_PREPRO (SHRT_MAX+4)
|
||||
int error(int, const char *, ...);
|
||||
|
||||
//===================================================================
|
||||
//========================== parse.c ================================
|
||||
//===================================================================
|
||||
int parse_tree(struct lex_file *);
|
||||
struct parsenode {
|
||||
struct parsenode *next;
|
||||
int type; /* some token */
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
//========================== typedef.c ==============================
|
||||
//===================================================================
|
||||
typedef struct typedef_node_t {
|
||||
char *name;
|
||||
} typedef_node;
|
||||
|
||||
void typedef_init();
|
||||
void typedef_clear();
|
||||
typedef_node *typedef_find(const char *);
|
||||
int typedef_add (const char *, const char *);
|
||||
|
||||
|
||||
//===================================================================
|
||||
//=========================== util.c ================================
|
||||
//===================================================================
|
||||
void *util_memory_a(unsigned int, unsigned int, const char *);
|
||||
void util_memory_d(void *, unsigned int, const char *);
|
||||
char *util_strdup (const char *);
|
||||
|
||||
#ifdef NOTRACK
|
||||
# define mem_a(x) malloc(x)
|
||||
# define mem_d(x) free (x)
|
||||
#else
|
||||
# define mem_a(x) util_memory_a((x), __LINE__, __FILE__)
|
||||
# define mem_d(x) util_memory_d((x), __LINE__, __FILE__)
|
||||
#endif
|
||||
|
||||
//===================================================================
|
||||
//=========================== code.c ================================
|
||||
//===================================================================
|
||||
#define TYPE_VOID 0
|
||||
#define TYPE_STRING 1
|
||||
#define TYPE_FLOAT 2
|
||||
|
@ -34,33 +136,17 @@
|
|||
#define TYPE_FUNCTION 6
|
||||
#define TYPE_POINTER 7
|
||||
|
||||
/*
|
||||
* there are 3 accessible memory zones -
|
||||
* globals
|
||||
* array of 32bit ints/floats, mixed, LE,
|
||||
* entities
|
||||
* structure is up to the engine but the fields are a linear array
|
||||
* of mixed ints/floats, there are globals referring to the offsets
|
||||
* of these in the entity struct so there are ADDRESS and STOREP and
|
||||
* LOAD instructions that use globals containing field offsets.
|
||||
* strings
|
||||
* a static array in the progs.dat, with file parsing creating
|
||||
* additional constants, and some engine fields are mapped by
|
||||
* address as well to unique string offsets
|
||||
*/
|
||||
|
||||
/*
|
||||
* Instructions
|
||||
* These are the external instructions supported by the interperter
|
||||
* this is what things compile to (from the C code). This is not internal
|
||||
* instructions for support like int, and such (which are translated)
|
||||
* this is what things compile to (from the C code).
|
||||
*/
|
||||
#define INSTR_DONE 0
|
||||
// math
|
||||
#define INSTR_MUL_F 1 /* multiplication float */
|
||||
#define INSTR_MUL_V 2 /* multiplication vector */
|
||||
#define INSTR_MUL_FV 3 /* multiplication float->vector */
|
||||
#define INSTR_MUL_VF 4 /* multiplication vector->float */
|
||||
#define INSTR_MUL_F 1
|
||||
#define INSTR_MUL_V 2
|
||||
#define INSTR_MUL_FV 3
|
||||
#define INSTR_MUL_VF 4
|
||||
#define INSTR_DIV_F 5
|
||||
#define INSTR_ADD_F 6
|
||||
#define INSTR_ADD_V 7
|
||||
|
@ -120,98 +206,4 @@
|
|||
#define INSTR_OR 57
|
||||
#define INSTR_BITAND 59
|
||||
#define INSTR_BITOR 60
|
||||
|
||||
/*
|
||||
* This is the smallest lexer I've ever wrote: and I must say, it's quite
|
||||
* more nicer than those large bulky complex parsers that most people write
|
||||
* which has some sort of a complex state.
|
||||
*/
|
||||
struct lex_file {
|
||||
/*
|
||||
* This is a simple state for lexing, no need to be complex for qc
|
||||
* code. It's trivial stuff.
|
||||
*/
|
||||
FILE *file;
|
||||
char peek[5]; /* extend for depthier peeks */
|
||||
int last;
|
||||
int current;
|
||||
int length;
|
||||
int size;
|
||||
char lastok[8192]; /* No token shall ever be bigger than this! */
|
||||
};
|
||||
|
||||
/*
|
||||
* It's important that this table never exceed 32 keywords, the ascii
|
||||
* table starts at 33 (and we don't want conflicts)
|
||||
*/
|
||||
#define TOKEN_DO 0
|
||||
#define TOKEN_ELSE 1
|
||||
#define TOKEN_IF 2
|
||||
#define TOKEN_WHILE 3
|
||||
#define TOKEN_BREAK 4
|
||||
#define TOKEN_CONTINUE 5
|
||||
#define TOKEN_RETURN 6
|
||||
#define TOKEN_GOTO 7
|
||||
#define TOKEN_FOR 8 // extension
|
||||
#define TOKEN_TYPEDEF 9 // extension
|
||||
|
||||
// ensure the token types are out of the
|
||||
// bounds of anyothers that may conflict.
|
||||
#define TOKEN_FLOAT 110
|
||||
#define TOKEN_VECTOR 111
|
||||
#define TOKEN_STRING 112
|
||||
#define TOKEN_ENTITY 113
|
||||
#define TOKEN_VOID 114
|
||||
|
||||
/*
|
||||
* Lexer state constants, these are numbers for where exactly in
|
||||
* the lexing the lexer is at. Or where it decided to stop if a lexer
|
||||
* error occurs. These numbers must be > where the ascii-table ends
|
||||
* and > the last type token which is TOKEN_VOID
|
||||
*/
|
||||
#define LEX_COMMENT 1128
|
||||
#define LEX_CHRLIT 1129
|
||||
#define LEX_STRLIT 1130
|
||||
#define LEX_IDENT 1131
|
||||
|
||||
int lex_token(struct lex_file *);
|
||||
void lex_reset(struct lex_file *);
|
||||
void lex_close(struct lex_file *);
|
||||
struct lex_file *lex_open (FILE *);
|
||||
|
||||
/* errors */
|
||||
#define ERROR_LEX (SHRT_MAX+0)
|
||||
#define ERROR_PARSE (SHRT_MAX+1)
|
||||
#define ERROR_INTERNAL (SHRT_MAX+2)
|
||||
#define ERROR_COMPILER (SHRT_MAX+3)
|
||||
#define ERROR_PREPRO (SHRT_MAX+4)
|
||||
int error(int, const char *, ...);
|
||||
|
||||
/* parse.c */
|
||||
int parse_tree(struct lex_file *);
|
||||
struct parsenode {
|
||||
struct parsenode *next;
|
||||
int type; /* some token */
|
||||
};
|
||||
|
||||
/* typedef.c */
|
||||
typedef struct typedef_node_t {
|
||||
char *name; /* name of actual type */
|
||||
} typedef_node;
|
||||
|
||||
void typedef_init();
|
||||
void typedef_clear();
|
||||
typedef_node *typedef_find(const char *);
|
||||
int typedef_add (const char *, const char *);
|
||||
|
||||
/* alloc.c */
|
||||
void *memory_a(unsigned int, unsigned int, const char *);
|
||||
void memory_d(void *, unsigned int, const char *);
|
||||
#ifdef NOTRACK
|
||||
# define mem_a(x) malloc(x)
|
||||
# define mem_d(x) free (x)
|
||||
#else
|
||||
# define mem_a(x) memory_a((x), __LINE__, __FILE__)
|
||||
# define mem_d(x) memory_d((x), __LINE__, __FILE__)
|
||||
#endif
|
||||
#endif
|
||||
|
|
2
lex.c
2
lex.c
|
@ -293,7 +293,7 @@ int lex_token(struct lex_file *file) {
|
|||
if (!strncmp(X, "entity", sizeof("entity"))) \
|
||||
return TOKEN_ENTITY; \
|
||||
if (!strncmp(X, "void" , sizeof("void"))) \
|
||||
return TOKEN_VOID; \
|
||||
return TOKEN_VOID; \
|
||||
} while(0)
|
||||
|
||||
TEST_TYPE(file->lastok);
|
||||
|
|
43
parse.c
43
parse.c
|
@ -83,7 +83,7 @@
|
|||
} while (0)
|
||||
|
||||
/*
|
||||
* These are all the punctuation handled in the parser, these don't
|
||||
* This is all the punctuation handled in the parser, these don't
|
||||
* need tokens, they're already tokens.
|
||||
*/
|
||||
#if 0
|
||||
|
@ -158,13 +158,13 @@ void parse_debug(struct parsenode *tree) {
|
|||
* and everything will fail.
|
||||
*/
|
||||
#define PARSE_PERFORM(X,C) { \
|
||||
token = lex_token(file); \
|
||||
{ C } \
|
||||
while (token != '\n') { \
|
||||
token = lex_token(file); \
|
||||
} \
|
||||
PARSE_TREE_ADD(X); \
|
||||
break; \
|
||||
token = lex_token(file); \
|
||||
{ C } \
|
||||
while (token != '\n') { \
|
||||
token = lex_token(file); \
|
||||
} \
|
||||
PARSE_TREE_ADD(X); \
|
||||
break; \
|
||||
}
|
||||
|
||||
void parse_clear(struct parsenode *tree) {
|
||||
|
@ -230,17 +230,17 @@ int parse_tree(struct lex_file *file) {
|
|||
* the tokens accordingly here.
|
||||
*/
|
||||
case TOKEN_TYPEDEF: {
|
||||
char *f = NULL;
|
||||
char *t = NULL;
|
||||
char *f,*t;
|
||||
|
||||
token = lex_token(file);
|
||||
token = lex_token(file); f = strdup(file->lastok);
|
||||
token = lex_token(file); f = util_strdup(file->lastok);
|
||||
token = lex_token(file);
|
||||
token = lex_token(file); t = strdup(file->lastok);
|
||||
token = lex_token(file); t = util_strdup(file->lastok);
|
||||
|
||||
typedef_add(f, t);
|
||||
|
||||
free(f);
|
||||
free(t);
|
||||
mem_d(f);
|
||||
mem_d(t);
|
||||
|
||||
while (token != '\n')
|
||||
token = lex_token(file);
|
||||
|
@ -254,8 +254,6 @@ int parse_tree(struct lex_file *file) {
|
|||
case TOKEN_RETURN:
|
||||
PARSE_TREE_ADD(PARSE_TYPE_RETURN);
|
||||
break;
|
||||
//PARSE_PERFORM(PARSE_TYPE_RETURN, {});
|
||||
|
||||
|
||||
case TOKEN_DO: PARSE_PERFORM(PARSE_TYPE_DO, {});
|
||||
case TOKEN_WHILE: PARSE_PERFORM(PARSE_TYPE_WHILE, {});
|
||||
|
@ -293,7 +291,6 @@ int parse_tree(struct lex_file *file) {
|
|||
token = lex_token(file);
|
||||
PARSE_TREE_ADD(PARSE_TYPE_DOT);
|
||||
break;
|
||||
|
||||
case '(':
|
||||
token = lex_token(file);
|
||||
PARSE_TREE_ADD(PARSE_TYPE_LPARTH);
|
||||
|
@ -303,7 +300,7 @@ int parse_tree(struct lex_file *file) {
|
|||
PARSE_TREE_ADD(PARSE_TYPE_RPARTH);
|
||||
break;
|
||||
|
||||
case '&': /* & */
|
||||
case '&': /* & */
|
||||
token = lex_token(file);
|
||||
if (token == '&') { /* && */
|
||||
token = lex_token(file);
|
||||
|
@ -312,7 +309,7 @@ int parse_tree(struct lex_file *file) {
|
|||
}
|
||||
PARSE_TREE_ADD(PARSE_TYPE_BAND);
|
||||
break;
|
||||
case '|': /* | */
|
||||
case '|': /* | */
|
||||
token = lex_token(file);
|
||||
if (token == '|') { /* || */
|
||||
token = lex_token(file);
|
||||
|
@ -321,7 +318,7 @@ int parse_tree(struct lex_file *file) {
|
|||
}
|
||||
PARSE_TREE_ADD(PARSE_TYPE_BOR);
|
||||
break;
|
||||
case '!':
|
||||
case '!': /* ! */
|
||||
token = lex_token(file);
|
||||
if (token == '=') { /* != */
|
||||
token = lex_token(file);
|
||||
|
@ -330,7 +327,7 @@ int parse_tree(struct lex_file *file) {
|
|||
}
|
||||
PARSE_TREE_ADD(PARSE_TYPE_LNOT);
|
||||
break;
|
||||
case '<': /* < */
|
||||
case '<': /* < */
|
||||
token = lex_token(file);
|
||||
if (token == '=') { /* <= */
|
||||
token = lex_token(file);
|
||||
|
@ -339,7 +336,7 @@ int parse_tree(struct lex_file *file) {
|
|||
}
|
||||
PARSE_TREE_ADD(PARSE_TYPE_LT);
|
||||
break;
|
||||
case '>': /* > */
|
||||
case '>': /* > */
|
||||
token = lex_token(file);
|
||||
if (token == '=') { /* >= */
|
||||
token = lex_token(file);
|
||||
|
@ -348,7 +345,7 @@ int parse_tree(struct lex_file *file) {
|
|||
}
|
||||
PARSE_TREE_ADD(PARSE_TYPE_GT);
|
||||
break;
|
||||
case '=':
|
||||
case '=': /* = */
|
||||
token = lex_token(file);
|
||||
if (token == '=') { /* == */
|
||||
token = lex_token(file);
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <limits.h>
|
||||
#include "gmqcc.h"
|
||||
static typedef_node *typedef_table[1024];
|
||||
|
||||
void typedef_init() {
|
||||
int i;
|
||||
for(i = 0; i < sizeof(typedef_table)/sizeof(*typedef_table); i++)
|
||||
|
@ -66,7 +65,7 @@ int typedef_add(const char *from, const char *to) {
|
|||
unsigned int hash = typedef_hash(to);
|
||||
typedef_node *find = typedef_table[hash];
|
||||
if (find)
|
||||
return error(ERROR_PARSE, "typedef for %s already exists\n", to);
|
||||
return error(ERROR_PARSE, "typedef for %s already exists or conflicts\n", to);
|
||||
|
||||
/* check if the type exists first */
|
||||
if (strncmp(from, "float", sizeof("float")) == 0 ||
|
||||
|
|
Loading…
Reference in a new issue