From 7176747bdc5715f970bb50152ed1c642d8b94b5c Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 28 Apr 2013 18:42:21 +0000 Subject: [PATCH] More library stuff (the codebase is a mess I know, but we're getting there) --- base.h | 18 ++++++----- code.c | 20 ++++++------ ftepp.c | 4 ++- gmqcc.h | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ir.c | 38 +++++++++++------------ ir.h | 2 +- main.c | 11 +++++-- parser.c | 89 +++++++++++++++++++++++++++++++++++++++++++---------- util.c | 18 +++++++++++ 9 files changed, 236 insertions(+), 58 deletions(-) diff --git a/base.h b/base.h index 88f6591..66cb15c 100644 --- a/base.h +++ b/base.h @@ -327,6 +327,8 @@ char *util_strcat (char *dest, const char *src); char *util_strncpy (char *dest, const char *src, size_t num); const char *util_strerror (int num); +const char *gmqcc_global_error(const char *text); + /* * A flexible vector implementation: all vector pointers contain some @@ -697,7 +699,7 @@ enum { typedef float qcfloat; typedef int32_t qcint; -typedef struct { +typedef struct gmqcc_code_s { prog_section_statement *statements; int *linenums; prog_section_def *defs; @@ -709,7 +711,7 @@ typedef struct { uint32_t entfields; ht string_cache; qcint string_cached_empty; -} code_t; +} gmqcc_code_t; /* * code_write -- writes out the compiled file @@ -719,12 +721,12 @@ typedef struct { * code_push_statement -- keeps statements and linenumbers together * code_pop_statement -- keeps statements and linenumbers together */ -bool code_write (code_t *, const char *filename, const char *lno); -code_t *code_init (void); -uint32_t code_genstring (code_t *, const char *string); -qcint code_alloc_field (code_t *, size_t qcsize); -void code_push_statement(code_t *, prog_section_statement *stmt, int linenum); -void code_pop_statement (code_t *); +bool code_write (gmqcc_code_t *, const char *filename, const char *lno); +gmqcc_code_t *code_init (void); +uint32_t code_genstring (gmqcc_code_t *, const char *string); +qcint code_alloc_field (gmqcc_code_t *, size_t qcsize); +void code_push_statement(gmqcc_code_t *, prog_section_statement *stmt, int linenum); +void code_pop_statement (gmqcc_code_t *); /* * A shallow copy of a lex_file to remember where which ast node diff --git a/code.c b/code.c index 4e404e9..24a53d5 100644 --- a/code.c +++ b/code.c @@ -28,27 +28,27 @@ #define QCINT_TO_HASH_ENTRY(q) ((void*)(uintptr_t)(q)) #define HASH_ENTRY_TO_QCINT(h) ((qcint)(uintptr_t)(h)) -void code_push_statement(code_t *code, prog_section_statement *stmt, int linenum) +void code_push_statement(gmqcc_code_t *code, prog_section_statement *stmt, int linenum) { vec_push(code->statements, *stmt); vec_push(code->linenums, linenum); } -void code_pop_statement(code_t *code) +void code_pop_statement(gmqcc_code_t *code) { vec_pop(code->statements); vec_pop(code->linenums); } -code_t *code_init() { +gmqcc_code_t *code_init() { static prog_section_function empty_function = {0,0,0,0,0,0,0,{0,0,0,0,0,0,0,0}}; static prog_section_statement empty_statement = {0,{0},{0},{0}}; static prog_section_def empty_def = {0, 0, 0}; - code_t *code = (code_t*)mem_a(sizeof(code_t)); + gmqcc_code_t *code = (gmqcc_code_t*)mem_a(sizeof(gmqcc_code_t)); int i = 0; - memset(code, 0, sizeof(code_t)); + memset(code, 0, sizeof(gmqcc_code_t)); code->entfields = 0; code->string_cache = util_htnew(OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS) ? 0x100 : 1024); @@ -72,7 +72,7 @@ code_t *code_init() { void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin); -uint32_t code_genstring(code_t *code, const char *str) +uint32_t code_genstring(gmqcc_code_t *code, const char *str) { uint32_t off; size_t hash; @@ -107,14 +107,14 @@ uint32_t code_genstring(code_t *code, const char *str) return off; } -qcint code_alloc_field (code_t *code, size_t qcsize) +qcint code_alloc_field (gmqcc_code_t *code, size_t qcsize) { qcint pos = (qcint)code->entfields; code->entfields += qcsize; return pos; } -static void code_create_header(code_t *code, prog_header *code_header) { +static void code_create_header(gmqcc_code_t *code, prog_header *code_header) { code_header->statements.offset = sizeof(prog_header); code_header->statements.length = vec_size(code->statements); code_header->defs.offset = code_header->statements.offset + (sizeof(prog_section_statement) * vec_size(code->statements)); @@ -168,7 +168,7 @@ static void code_create_header(code_t *code, prog_header *code_header) { * directly out to allocated memory. Which is actually very useful for the future library support * we're going to add. */ -bool code_write_memory(code_t *code, uint8_t **datmem, size_t *sizedat, uint8_t **lnomem, size_t *sizelno) { +bool code_write_memory(gmqcc_code_t *code, uint8_t **datmem, size_t *sizedat, uint8_t **lnomem, size_t *sizelno) { prog_header code_header; uint32_t offset = 0; @@ -248,7 +248,7 @@ bool code_write_memory(code_t *code, uint8_t **datmem, size_t *sizedat, uint8_t return true; } -bool code_write(code_t *code, const char *filename, const char *lnofile) { +bool code_write(gmqcc_code_t *code, const char *filename, const char *lnofile) { prog_header code_header; FILE *fp = NULL; diff --git a/ftepp.c b/ftepp.c index cada764..7990659 100644 --- a/ftepp.c +++ b/ftepp.c @@ -1834,8 +1834,10 @@ ftepp_t *gmqcc_preprocess_create(void) char major[32]; ftepp = ftepp_new(); - if (!ftepp) + if (!ftepp) { + gmqcc_global_error("Failed to construct a new preprocessor context"); return NULL; + } memset(minor, 0, sizeof(minor)); memset(major, 0, sizeof(major)); diff --git a/gmqcc.h b/gmqcc.h index 2a62778..d0ee78c 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -32,6 +32,7 @@ extern "C" { * that the user shouldn't have information of. */ struct gmqcc_preprocess_s; +struct gmqcc_compiler_s; /* * Function: gmqcc_global_setmemory @@ -56,6 +57,19 @@ bool gmqcc_global_setmemory ( void (*free_impl) (void *) ); +/* + * Funciton: gmqcc_global_geterror + * Get a const string-literal of the last error which occured. + * + * Returns: + * A string-literal describing the error which occured last. + * + * Remarks: + * This should be called to get better diagnostic when a function + * doesn't return successfully. + */ +const char *gmqcc_global_geterror(void); + /* * Function: gmqcc_preprocess_create * Creates a preprocessor context @@ -165,6 +179,86 @@ void gmqcc_preprocess_destroy( struct gmqcc_preprocess_s *pp ); + +/* + * Enumeration: gmqcc_compiler_context_t + * List of bindable contexts for a compiler context + * + * GMQCC_CONTEXT_PREPROCESSOR - A preprocessor context + * GMQCC_CONTEXT_PARSER - A parser context + * GMQCC_CONTEXT_CODE - A code generator context + */ +typedef enum { + GMQCC_CONTEXT_PREPROCESSOR, + GMQCC_CONTEXT_PARSER, + GMQCC_CONTEXT_CODE +} gmqcc_compiler_context_t; + +/* + * Macro: GMQCC_CONTEXT_CAST + * A macro for casting a bindable context, used primarly for context + * manipulation where the functions are abstract and require a cast. + * + * See Also: + * + */ +#define GMQCC_CONTEXT_CAST(X) ((void*)(X)) + +/* + * Function: gmqcc_compiler_create + * Creates a compiler which will require attachments to + * function. + * + * Returns: + * A new compiler context + * + * Remarks: + * Inorder to use the compiler context you'll require + * at minimal a code and parser context. + * + * See Also: + * + */ +struct gmqcc_compiler_s *gmqcc_compiler_create(void); + +/* + * Function: gmqcc_compiler_attachcontext + * Used to attach a context to a compiler context. + * + * Parameters: + * compiler - Compiler context + * base - Base pointer to attachment context + * context - The type of context (see et. all) + * + * Returns: + * true on success, false otherwise. + * + * Remarks: + * A parser context is mandatory, other contexts are optional. + * Contexts can be swaped around, i.e you can detach a parser context, + * back it up somewhere apply a new parser context and run with that. + */ +bool gmqcc_compiler_attachcontext( + struct gmqcc_compiler_s *compiler, + void *base, + gmqcc_compiler_context_t context +); + +/* + * Function: gmqcc_compiler_destroy + * Destroys a compiler context. + * + * Parameters: + * compiler - Compiler context + * + * Remarks: + * This function doesn't destory any associated contexts with + * the compiler context itself. + */ +void gmqcc_compiler_destroy( + struct gmqcc_compiler_s *compiler +); + #ifdef __cplusplus } #endif /*! __cplusplus */ diff --git a/ir.c b/ir.c index 07eb679..0bc0001 100644 --- a/ir.c +++ b/ir.c @@ -212,7 +212,7 @@ const uint16_t type_not_instr[TYPE_COUNT] = { /* protos */ static ir_value* ir_gen_extparam_proto(ir_builder *ir); -static void ir_gen_extparam (code_t *, ir_builder *ir); +static void ir_gen_extparam (gmqcc_code_t *, ir_builder *ir); /* error functions */ @@ -2618,9 +2618,9 @@ bool ir_function_calculate_liferanges(ir_function *self) * * Breaking conventions is annoying... */ -static bool ir_builder_gen_global(code_t *, ir_builder *self, ir_value *global, bool islocal); +static bool ir_builder_gen_global(gmqcc_code_t *, ir_builder *self, ir_value *global, bool islocal); -static bool gen_global_field(code_t *code, ir_value *global) +static bool gen_global_field(gmqcc_code_t *code, ir_value *global) { if (global->hasvalue) { @@ -2652,7 +2652,7 @@ static bool gen_global_field(code_t *code, ir_value *global) return true; } -static bool gen_global_pointer(code_t *code, ir_value *global) +static bool gen_global_pointer(gmqcc_code_t *code, ir_value *global) { if (global->hasvalue) { @@ -2691,7 +2691,7 @@ static bool gen_global_pointer(code_t *code, ir_value *global) return true; } -static bool gen_blocks_recursive(code_t *code, ir_function *func, ir_block *block) +static bool gen_blocks_recursive(gmqcc_code_t *code, ir_function *func, ir_block *block) { prog_section_statement stmt; ir_instr *instr; @@ -2951,7 +2951,7 @@ static bool gen_blocks_recursive(code_t *code, ir_function *func, ir_block *bloc return true; } -static bool gen_function_code(code_t *code, ir_function *self) +static bool gen_function_code(gmqcc_code_t *code, ir_function *self) { ir_block *block; prog_section_statement stmt, *retst; @@ -2992,7 +2992,7 @@ static bool gen_function_code(code_t *code, ir_function *self) return true; } -static qcint ir_builder_filestring(code_t *code, ir_builder *ir, const char *filename) +static qcint ir_builder_filestring(gmqcc_code_t *code, ir_builder *ir, const char *filename) { /* NOTE: filename pointers are copied, we never strdup them, * thus we can use pointer-comparison to find the string. @@ -3011,7 +3011,7 @@ static qcint ir_builder_filestring(code_t *code, ir_builder *ir, const char *fil return str; } -static bool gen_global_function(code_t *code, ir_builder *ir, ir_value *global) +static bool gen_global_function(gmqcc_code_t *code, ir_builder *ir, ir_value *global) { prog_section_function fun; ir_function *irfun; @@ -3066,7 +3066,7 @@ static ir_value* ir_gen_extparam_proto(ir_builder *ir) return global; } -static void ir_gen_extparam(code_t *code, ir_builder *ir) +static void ir_gen_extparam(gmqcc_code_t *code, ir_builder *ir) { prog_section_def def; ir_value *global; @@ -3091,7 +3091,7 @@ static void ir_gen_extparam(code_t *code, ir_builder *ir) vec_push(ir->extparams, global); } -static bool gen_function_extparam_copy(code_t *code, ir_function *self) +static bool gen_function_extparam_copy(gmqcc_code_t *code, ir_function *self) { size_t i, ext, numparams; @@ -3126,7 +3126,7 @@ static bool gen_function_extparam_copy(code_t *code, ir_function *self) return true; } -static bool gen_function_varargs_copy(code_t *code, ir_function *self) +static bool gen_function_varargs_copy(gmqcc_code_t *code, ir_function *self) { size_t i, ext, numparams, maxparams; @@ -3162,7 +3162,7 @@ static bool gen_function_varargs_copy(code_t *code, ir_function *self) return true; } -static bool gen_function_locals(code_t *code, ir_builder *ir, ir_value *global) +static bool gen_function_locals(gmqcc_code_t *code, ir_builder *ir, ir_value *global) { prog_section_function *def; ir_function *irfun; @@ -3211,7 +3211,7 @@ static bool gen_function_locals(code_t *code, ir_builder *ir, ir_value *global) return true; } -static bool gen_global_function_code(code_t *code, ir_builder *ir, ir_value *global) +static bool gen_global_function_code(gmqcc_code_t *code, ir_builder *ir, ir_value *global) { prog_section_function *fundef; ir_function *irfun; @@ -3257,7 +3257,7 @@ static bool gen_global_function_code(code_t *code, ir_builder *ir, ir_value *glo return true; } -static void gen_vector_defs(code_t *code, prog_section_def def, const char *name) +static void gen_vector_defs(gmqcc_code_t *code, prog_section_def def, const char *name) { char *component; size_t len, i; @@ -3287,7 +3287,7 @@ static void gen_vector_defs(code_t *code, prog_section_def def, const char *name mem_d(component); } -static void gen_vector_fields(code_t *code, prog_section_field fld, const char *name) +static void gen_vector_fields(gmqcc_code_t *code, prog_section_field fld, const char *name) { char *component; size_t len, i; @@ -3317,7 +3317,7 @@ static void gen_vector_fields(code_t *code, prog_section_field fld, const char * mem_d(component); } -static bool ir_builder_gen_global(code_t *code, ir_builder *self, ir_value *global, bool islocal) +static bool ir_builder_gen_global(gmqcc_code_t *code, ir_builder *self, ir_value *global, bool islocal) { size_t i; int32_t *iptr; @@ -3488,12 +3488,12 @@ static bool ir_builder_gen_global(code_t *code, ir_builder *self, ir_value *glob } } -static GMQCC_INLINE void ir_builder_prepare_field(code_t *code, ir_value *field) +static GMQCC_INLINE void ir_builder_prepare_field(gmqcc_code_t *code, ir_value *field) { field->code.fieldaddr = code_alloc_field(code, type_sizeof_[field->fieldtype]); } -static bool ir_builder_gen_field(code_t *code, ir_builder *self, ir_value *field) +static bool ir_builder_gen_field(gmqcc_code_t *code, ir_builder *self, ir_value *field) { prog_section_def def; prog_section_field fld; @@ -3563,7 +3563,7 @@ static bool ir_builder_gen_field(code_t *code, ir_builder *self, ir_value *field return field->code.globaladdr >= 0; } -bool ir_builder_generate(code_t *code, ir_builder *self, const char *filename) +bool ir_builder_generate(gmqcc_code_t *code, ir_builder *self, const char *filename) { prog_section_statement stmt; size_t i; diff --git a/ir.h b/ir.h index 85d759f..89eea91 100644 --- a/ir.h +++ b/ir.h @@ -349,7 +349,7 @@ ir_value* ir_builder_create_field(ir_builder*, const char *name, int vtype); ir_value* ir_builder_get_va_count(ir_builder*); -bool ir_builder_generate(code_t *, ir_builder *self, const char *filename); +bool ir_builder_generate(gmqcc_code_t *, ir_builder *self, const char *filename); void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...)); diff --git a/main.c b/main.c index 9ea723a..00f7236 100644 --- a/main.c +++ b/main.c @@ -549,9 +549,13 @@ int main(int argc, char **argv) { bool operators_free = false; bool progs_src = false; FILE *outfile = NULL; - struct parser_s *parser = NULL; - struct gmqcc_preprocess_s *ftepp = NULL; + struct parser_s *parser = NULL; + struct gmqcc_preprocess_s *ftepp = NULL; + struct gmqcc_code_s *code = code_init(); + struct gmqcc_compiler_s *compiler = gmqcc_compiler_create(); + + gmqcc_compiler_attachcontext(compiler, GMQCC_CONTEXT_CAST(code), GMQCC_CONTEXT_CODE); app_name = argv[0]; con_init (); @@ -560,6 +564,7 @@ int main(int argc, char **argv) { util_seed(time(0)); if (!options_parse(argc, argv)) { + gmqcc_compiler_destroy(compiler); return usage(); } @@ -631,6 +636,7 @@ int main(int argc, char **argv) { retval = 1; goto cleanup; } + gmqcc_compiler_attachcontext(compiler, GMQCC_CONTEXT_CAST(parser), GMQCC_CONTEXT_PARSER); } if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) { @@ -639,6 +645,7 @@ int main(int argc, char **argv) { retval = 1; goto cleanup; } + gmqcc_compiler_attachcontext(compiler, GMQCC_CONTEXT_CAST(ftepp), GMQCC_CONTEXT_PREPROCESSOR); } /* add macros */ diff --git a/parser.c b/parser.c index 3bbe68b..61884ac 100644 --- a/parser.c +++ b/parser.c @@ -28,6 +28,7 @@ #include "base.h" #include "lexer.h" #include "ast.h" +#include "gmqcc.h" /* beginning of locals */ #define PARSER_HT_LOCALS 2 @@ -37,15 +38,15 @@ typedef struct parser_s { lex_file *lex; - int tok; + int tok; ast_expression **globals; ast_expression **fields; - ast_function **functions; - ast_value **imm_float; - ast_value **imm_string; - ast_value **imm_vector; - size_t translated; + ast_function **functions; + ast_value **imm_float; + ast_value **imm_string; + ast_value **imm_vector; + size_t translated; ht ht_imm_string; @@ -104,17 +105,77 @@ typedef struct parser_s { /* collected information */ size_t max_param_count; - /* code generator */ - code_t *code; + gmqcc_code_t *code; } parser_t; +/* WORK IN PROGRESS */ +typedef struct gmqcc_compiler_s { + struct parser_s *ctx_parser; + struct gmqcc_preprocess_s *ctx_preprocess; + struct gmqcc_code_s *ctx_code; +} gmqcc_compiler_t; + +gmqcc_compiler_t *gmqcc_compiler_create(void) { + gmqcc_compiler_t *compiler = (gmqcc_compiler_t*)mem_a(sizeof(*compiler)); + memset(compiler, 0, sizeof(*compiler)); + return compiler; +} + +void gmqcc_compiler_destroy(gmqcc_compiler_t *compiler) { + /* Doen't free members yet */ + mem_d(compiler); +} + +bool gmqcc_compiler_attachcontext(gmqcc_compiler_t *c, void *base, gmqcc_compiler_context_t type) { + if (!base) { + gmqcc_global_error("NULL attachment supplied for gmqcc_compiler_attachcontext"); + return false; + } + + switch (type) { + case GMQCC_CONTEXT_CODE: + c->ctx_code = (struct gmqcc_code_s*)base; + /* + * Update the parsers code context copy + * if the code context has changed. + */ + if (c->ctx_parser) + c->ctx_parser->code = c->ctx_code; + break; + + case GMQCC_CONTEXT_PARSER: + /* Free memory */ + if (c->ctx_parser) + parser_cleanup(c->ctx_parser); + if (!c->ctx_code) { + gmqcc_global_error("A code context must be created before a parser context"); + return false; + } + + c->ctx_parser = (struct parser_s*)base; + c->ctx_parser->code = c->ctx_code; + break; + + case GMQCC_CONTEXT_PREPROCESSOR: + if (c->ctx_preprocess) + gmqcc_preprocess_destroy(c->ctx_preprocess); + c->ctx_preprocess = (struct gmqcc_preprocess_s*)base; + break; + + default: + gmqcc_global_error("Invalid context attachment"); + return false; + } + return true; +} + static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; static void parser_enterblock(parser_t *parser); static bool parser_leaveblock(parser_t *parser); -static void parser_addlocal(parser_t *parser, const char *name, ast_expression *e); -static void parser_addglobal(parser_t *parser, const char *name, ast_expression *e); -static bool parse_typedef(parser_t *parser); +static void parser_addlocal (parser_t *parser, const char *name, ast_expression *e); +static void parser_addglobal (parser_t *parser, const char *name, ast_expression *e); +static bool parse_typedef (parser_t *parser); static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref, bool is_static, uint32_t qflags, char *vstring); static ast_block* parse_block(parser_t *parser); static bool parse_block_into(parser_t *parser, ast_block *block); @@ -6012,12 +6073,6 @@ parser_t *parser_create() memset(parser, 0, sizeof(*parser)); - if (!(parser->code = code_init())) { - mem_d(parser); - return NULL; - } - - for (i = 0; i < operator_count; ++i) { if (operators[i].id == opid1('=')) { parser->assign_op = operators+i; diff --git a/util.c b/util.c index f74688c..ca5eb81 100644 --- a/util.c +++ b/util.c @@ -62,6 +62,24 @@ void util_mem_f(void *ptr) { if (mem_provided) mem_free(ptr); else free (ptr); } + +/* + * Protect with mutex some day for thread safety reasons + * otherwise weird things may happen with error reporting + * when multiple-threads are introduced. + */ +const char *gmqcc_global_error(const char *text) { + static char *error = NULL; + if (text) { + if (error) mem_d(error); + error = util_strdup(text); + } + return error; +} + +const char *gmqcc_global_geterror(void) { + return gmqcc_global_error(NULL); +} /* -- 2.39.2