This commit is contained in:
Dale Weiler 2012-04-10 05:02:58 -04:00
parent d5dcb3aff7
commit 639fc8a32b
7 changed files with 134 additions and 200 deletions

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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);

View 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 ||