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
typedef float qcfloat;
typedef int32_t qcint;
-typedef struct {
+typedef struct gmqcc_code_s {
prog_section_statement *statements;
int *linenums;
prog_section_def *defs;
uint32_t entfields;
ht string_cache;
qcint string_cached_empty;
-} code_t;
+} gmqcc_code_t;
/*
* code_write -- writes out the compiled file
* 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
#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);
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;
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));
* 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;
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;
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));
* that the user shouldn't have information of.
*/
struct gmqcc_preprocess_s;
+struct gmqcc_compiler_s;
/*
* Function: 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
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:
+ * <gmqcc_compiler_attachcontext>
+ */
+#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:
+ * <gmqcc_compiler_attachcontext>
+ */
+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 <gmqcc_compiler_context_t> 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 */
/* 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 */
*
* 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)
{
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)
{
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;
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;
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.
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;
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;
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;
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;
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;
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;
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;
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;
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;
}
}
-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;
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;
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*, ...));
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 ();
util_seed(time(0));
if (!options_parse(argc, argv)) {
+ gmqcc_compiler_destroy(compiler);
return usage();
}
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)) {
retval = 1;
goto cleanup;
}
+ gmqcc_compiler_attachcontext(compiler, GMQCC_CONTEXT_CAST(ftepp), GMQCC_CONTEXT_PREPROCESSOR);
}
/* add macros */
#include "base.h"
#include "lexer.h"
#include "ast.h"
+#include "gmqcc.h"
/* beginning of locals */
#define PARSER_HT_LOCALS 2
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;
/* 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);
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;
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);
+}
/*