From b3e9ef3ad9f8f9aee8c3472efd2c4485dc684718 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Fri, 26 Apr 2013 10:31:38 +0200 Subject: [PATCH 01/63] an = before an { is also always required when the declared variable is not a function; adding because of planned array initializers --- parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser.c b/parser.c index 7fba786..506f8d2 100644 --- a/parser.c +++ b/parser.c @@ -5623,7 +5623,7 @@ skipvar: } } - if (parser->tok != '{') { + if (parser->tok != '{' || var->expression.vtype != TYPE_FUNCTION) { if (parser->tok != '=') { parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser)); break; From 9f8bee4bf15ba3001ede0788a782e4a34b66c323 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Fri, 26 Apr 2013 10:45:13 +0200 Subject: [PATCH 02/63] ast_value now has an initializer list array, still unused but it's there for later --- ast.c | 17 ++++++++++++++++- ast.h | 24 +++++++++++++++--------- parser.c | 17 ++++++++++++++++- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/ast.c b/ast.c index 3e5d304..1e2836f 100644 --- a/ast.c +++ b/ast.c @@ -317,8 +317,9 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t) self->cvq = CV_NONE; self->hasvalue = false; self->isimm = false; - self->uses = 0; + self->uses = 0; memset(&self->constval, 0, sizeof(self->constval)); + self->initlist = NULL; self->ir_v = NULL; self->ir_values = NULL; @@ -362,6 +363,20 @@ void ast_value_delete(ast_value* self) if (self->desc) mem_d(self->desc); + if (self->initlist) { + if (self->expression.next->expression.vtype == TYPE_STRING) { + /* strings are allocated, free them */ + size_t i, len = vec_size(self->initlist); + /* in theory, len should be expression.count + * but let's not take any chances */ + for (i = 0; i < len; ++i) { + if (self->initlist[i].vstring) + mem_d(self->initlist[i].vstring); + } + } + vec_free(self->initlist); + } + ast_expression_delete((ast_expression*)self); mem_d(self); } diff --git a/ast.h b/ast.h index bae07db..98ad792 100644 --- a/ast.h +++ b/ast.h @@ -161,6 +161,15 @@ typedef struct * typedef float foo; * is like creating a 'float foo', foo serving as the type's name. */ +typedef union { + double vfloat; + int vint; + vector vvec; + const char *vstring; + int ventity; + ast_function *vfunc; + ast_value *vfield; +} basic_value_t; struct ast_value_s { ast_expression_common expression; @@ -179,15 +188,12 @@ struct ast_value_s bool isfield; /* this declares a field */ bool isimm; /* an immediate, not just const */ bool hasvalue; - union { - double vfloat; - int vint; - vector vvec; - const char *vstring; - int ventity; - ast_function *vfunc; - ast_value *vfield; - } constval; + basic_value_t constval; + /* for TYPE_ARRAY we have an optional vector + * of constants when an initializer list + * was provided. + */ + basic_value_t *initlist; /* usecount for the parser */ size_t uses; diff --git a/parser.c b/parser.c index 506f8d2..a09a54a 100644 --- a/parser.c +++ b/parser.c @@ -5725,7 +5725,22 @@ skipvar: break; } } - else if (parser->tok == '{' || parser->tok == '[') + else if (var->expression.vtype == TYPE_ARRAY && parser->tok == '{') + { + if (localblock) { + /* Note that fteqcc and most others don't even *have* + * local arrays, so this is not a high priority. + */ + parseerror(parser, "TODO: initializers for local arrays"); + break; + } + /* +static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels); +*/ + parseerror(parser, "TODO: initializing global arrays is not supported yet!"); + break; + } + else if (var->expression.vtype == TYPE_FUNCTION && (parser->tok == '{' || parser->tok == '[')) { if (localblock) { parseerror(parser, "cannot declare functions within functions"); From 7e0d6bdd872ec33a82c4f8cb4c04886e6162f2d0 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Fri, 26 Apr 2013 17:33:56 +0200 Subject: [PATCH 03/63] don't overwrite ldflags/libs env vars --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ff63173..1da71d4 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,8 @@ MINGW = $(findstring MINGW32, $(UNAME)) CC ?= clang # linker flags and optional additional libraries if required -LDFLAGS := -LIBS := -lm +LDFLAGS += +LIBS += -lm CFLAGS += -Wall -Wextra -Werror -I. -fno-strict-aliasing $(OPTIONAL) ifneq ($(shell git describe --always 2>/dev/null),) From 35120caf80f7571e00a9b8924cfe18d49843cff8 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Sat, 27 Apr 2013 17:00:27 +0200 Subject: [PATCH 04/63] debian Makefile had the same flaw as archlinux/this... fixing --- distro/deb/Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/distro/deb/Makefile b/distro/deb/Makefile index df23602..7594400 100644 --- a/distro/deb/Makefile +++ b/distro/deb/Makefile @@ -10,12 +10,14 @@ DEB := $(DEBDIR)-$(CARCH).deb CONTROL := $(DEBDIR)/DEBIAN/control ifneq (, $(findstring i686, $(CARCH))) - CFLAGS := -m32 + CFLAGS += -m32 + LDFLAGS += -m32 endif base: $(MAKE) -C $(BASEDIR) clean - $(MAKE) -C $(BASEDIR) DESTDIR=distro/deb/$(DEBDIR) PREFIX=$(PREFIX) install + CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" \ + $(MAKE) -C $(BASEDIR) DESTDIR=distro/deb/$(DEBDIR) PREFIX=$(PREFIX) install @install -d -m755 $(DEBDIR)/DEBIAN @echo "Package: gmqcc" > $(CONTROL) @echo "Version: $(MAJOR).$(MINOR).$(PATCH)" >> $(CONTROL) From dc6a7436ee06bc147b6d1e6e22929b8f37c2bd48 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sat, 27 Apr 2013 15:20:01 +0000 Subject: [PATCH 05/63] Expression has undefined behavior (left operand modifies code->globals->used, used by right operand): (code->globals)[(((vector_t*)((void *)code->globals)) - 1)->used++] = (code_genstring(code, global->constval.vstring)) Code has unspecified behavior. Order of evaluation of function parameters or subexpressions is not defined, so if a value is used and modified in different places not separated by a sequence point constraining evaluation order, then the result of the expression is unspecified. --- ir.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ir.c b/ir.c index 82dcb9b..a124bd1 100644 --- a/ir.c +++ b/ir.c @@ -3418,7 +3418,8 @@ static bool ir_builder_gen_global(code_t *code, ir_builder *self, ir_value *glob { ir_value_code_setaddr(global, vec_size(code->globals)); if (global->hasvalue) { - vec_push(code->globals, code_genstring(code, global->constval.vstring)); + uint32_t load = code_genstring(code, global->constval.vstring); + vec_push(code->globals, load); } else { vec_push(code->globals, 0); } From a8e2a47da8cf73db5b624b2640ad3eef06cf9030 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 28 Apr 2013 03:41:03 +0000 Subject: [PATCH 06/63] Less general name for PAK utility, added install targets for PAK utility, added manpag for PAK utility, this closes #108 --- Makefile | 20 +++++++++++++------- doc/gmqpak.1 | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 doc/gmqpak.1 diff --git a/Makefile b/Makefile index 35b825a..febebeb 100644 --- a/Makefile +++ b/Makefile @@ -72,12 +72,12 @@ ifneq ("$(MINGW)", "") QCVM = qcvm.exe GMQCC = gmqcc.exe TESTSUITE = testsuite.exe - PAK = pak.exe + PAK = gmqpak.exe else QCVM = qcvm GMQCC = gmqcc TESTSUITE = testsuite - PAK = pak + PAK = gmqpak endif endif @@ -214,23 +214,29 @@ depend: $(subst .o,.c,$(OBJ_P)) #install rules -install: install-gmqcc install-qcvm install-doc +install: install-gmqcc install-qcvm install-gmqpak install-doc install-gmqcc: $(GMQCC) install -d -m755 $(DESTDIR)$(BINDIR) install -m755 $(GMQCC) $(DESTDIR)$(BINDIR)/$(GMQCC) install-qcvm: $(QCVM) install -d -m755 $(DESTDIR)$(BINDIR) install -m755 $(QCVM) $(DESTDIR)$(BINDIR)/$(QCVM) +install-gmqpak: $(PAK) + install -d -m755 $(DESTDIR)$(BINDIR) + install -m755 $(PAK) $(DESTDIR)$(BINDIR)/$(PAK) install-doc: install -d -m755 $(DESTDIR)$(MANDIR)/man1 install -m644 doc/gmqcc.1 $(DESTDIR)$(MANDIR)/man1/ install -m644 doc/qcvm.1 $(DESTDIR)$(MANDIR)/man1/ + install -m644 doc/gmqpak.1 $(DESTDIR)$(MANDIR)/man1/ uninstall: - rm $(DESTDIR)$(BINDIR)/gmqcc - rm $(DESTDIR)$(BINDIR)/qcvm - rm $(DESTDIR)$(MANDIR)/man1/doc/gmqcc.1 - rm $(DESTDIR)$(MANDIR)/man1/doc/qcvm.1 + rm -f $(DESTDIR)$(BINDIR)/gmqcc + rm -f $(DESTDIR)$(BINDIR)/qcvm + rm -f $(DESTDIR)$(BINDIR)/gmqpak + rm -f $(DESTDIR)$(MANDIR)/man1/doc/gmqcc.1 + rm -f $(DESTDIR)$(MANDIR)/man1/doc/qcvm.1 + rm -f $(DESTDIR)$(MANDIR)/man1/doc/gmqpak.1 # DO NOT DELETE diff --git a/doc/gmqpak.1 b/doc/gmqpak.1 new file mode 100644 index 0000000..967d432 --- /dev/null +++ b/doc/gmqpak.1 @@ -0,0 +1,38 @@ +.\" gmqpak mdoc manpage +.Dd April 27, 2013 +.Dt GMQPAK 2 PRM +.Os +.Sh NAME +.Nm gmqpak +.Nd A standalone Quake PAK utility +.Sh SYNOPSIS +.Nm gmqpak +.Op Cm options +.Op Cm files +.Sh DESCRIPTION +.Nm gmqpak +Is a standalone Quake PAK file utility supporting the extraction of files, +directories, or whole PAKs, as well as the opposite (creation of PAK files). +.Sh OPTIONS +.Bl -tag +.It Fl -file Ar file +Specify the PAK file to create or extract +.It Fl -e +Used to denote the extraction operation on a PAK file. +.It Fl -c +Used to denote the creation operation on a PAK file. +.El +.Sh EXAMPLES +Here's some examples of how to use the utility to manipulate PAK files. +.Bl -ohang +.It Li gmqpak -file id1.pak -e +.D1 extracts a PAK to ./ +.It Li gmqpak -file new.pak -c file1 dir/file2 +.D1 creates a PAK with the files specified +.It Li gmqpak -file new1.pak -c directory. +.D1 creates a PAK from files within the directory, including subdirectories and files. +.Sh AUTHOR +See . +.Sh BUGS +Please report bugs on , +or see on how to contact us. From 721b581376f845326fcf079457c6323cca67cccd Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 28 Apr 2013 03:50:22 +0000 Subject: [PATCH 07/63] Fix deps (remove duplicates with clever make tricks) --- Makefile | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index febebeb..f713417 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,12 @@ OBJ_T = test.o util.o conout.o fs.o OBJ_C = main.o lexer.o parser.o fs.o OBJ_X = exec-standalone.o util.o conout.o fs.o +#we have duplicate object files when dealing with creating a simple list +#for dependinces. To combat this we use some clever recrusive-make to +#filter the list and remove duplicates which we use for make depend +RMDUP = $(if $1,$(firstword $1) $(call RMDUP,$(filter-out $(firstword $1),$1))) +DEPS := $(call RMDUP, $(OBJ_D) $(OBJ_P) $(OBJ_T) $(OBJ_C) $(OBJ_X)) + ifneq ("$(CYGWIN)", "") #nullify the common variables that #most *nix systems have (for windows) @@ -203,15 +209,7 @@ gource-record: depend: @makedepend -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_D)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_T)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_C)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_X)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_P)) + $(subst .o,.c,$(DEPS)) #install rules install: install-gmqcc install-qcvm install-gmqpak install-doc @@ -250,23 +248,8 @@ opts.o: gmqcc.h opts.def fs.o: gmqcc.h opts.def utf8.o: gmqcc.h opts.def correct.o: gmqcc.h opts.def - +pak.o: gmqcc.h opts.def test.o: gmqcc.h opts.def -util.o: gmqcc.h opts.def -conout.o: gmqcc.h opts.def -fs.o: gmqcc.h opts.def - main.o: gmqcc.h opts.def lexer.h lexer.o: gmqcc.h opts.def lexer.h parser.o: gmqcc.h opts.def lexer.h ast.h ir.h intrin.h -fs.o: gmqcc.h opts.def - -util.o: gmqcc.h opts.def -conout.o: gmqcc.h opts.def -fs.o: gmqcc.h opts.def - -util.o: gmqcc.h opts.def -fs.o: gmqcc.h opts.def -conout.o: gmqcc.h opts.def -opts.o: gmqcc.h opts.def -pak.o: gmqcc.h opts.def From 79a5ed04822a172df0307e7ac7d3ea60bdbaa557 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 28 Apr 2013 04:29:20 +0000 Subject: [PATCH 08/63] Implemented support for having codegen (and lno files) be wrote out to memory, this essentially allows us to embed the compiler in applications now. --- code.c | 162 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 128 insertions(+), 34 deletions(-) diff --git a/code.c b/code.c index b0ce2ba..77bba3e 100644 --- a/code.c +++ b/code.c @@ -114,30 +114,26 @@ qcint code_alloc_field (code_t *code, size_t qcsize) return pos; } -bool code_write(code_t *code, const char *filename, const char *lnofile) { - prog_header code_header; - FILE *fp = NULL; - size_t it = 2; - - 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)); - code_header.defs.length = vec_size(code->defs); - code_header.fields.offset = code_header.defs.offset + (sizeof(prog_section_def) * vec_size(code->defs)); - code_header.fields.length = vec_size(code->fields); - code_header.functions.offset = code_header.fields.offset + (sizeof(prog_section_field) * vec_size(code->fields)); - code_header.functions.length = vec_size(code->functions); - code_header.globals.offset = code_header.functions.offset + (sizeof(prog_section_function) * vec_size(code->functions)); - code_header.globals.length = vec_size(code->globals); - code_header.strings.offset = code_header.globals.offset + (sizeof(int32_t) * vec_size(code->globals)); - code_header.strings.length = vec_size(code->chars); - code_header.version = 6; +static void code_create_header(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)); + code_header->defs.length = vec_size(code->defs); + code_header->fields.offset = code_header->defs.offset + (sizeof(prog_section_def) * vec_size(code->defs)); + code_header->fields.length = vec_size(code->fields); + code_header->functions.offset = code_header->fields.offset + (sizeof(prog_section_field) * vec_size(code->fields)); + code_header->functions.length = vec_size(code->functions); + code_header->globals.offset = code_header->functions.offset + (sizeof(prog_section_function) * vec_size(code->functions)); + code_header->globals.length = vec_size(code->globals); + code_header->strings.offset = code_header->globals.offset + (sizeof(int32_t) * vec_size(code->globals)); + code_header->strings.length = vec_size(code->chars); + code_header->version = 6; if (OPTS_OPTION_BOOL(OPTION_FORCECRC)) - code_header.crc16 = OPTS_OPTION_U16(OPTION_FORCED_CRC); + code_header->crc16 = OPTS_OPTION_U16(OPTION_FORCED_CRC); else - code_header.crc16 = code->crc; - code_header.entfield = code->entfields; + code_header->crc16 = code->crc; + code_header->entfield = code->entfields; if (OPTS_FLAG(DARKPLACES_STRING_TABLE_BUG)) { util_debug("GEN", "Patching stringtable for -fdarkplaces-stringtablebug\n"); @@ -149,20 +145,118 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) { } /* ensure all data is in LE format */ - util_endianswap(&code_header.version, 1, sizeof(code_header.version)); - util_endianswap(&code_header.crc16, 1, sizeof(code_header.crc16)); - util_endianswap(&code_header.statements, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.defs, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.fields, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.functions, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.strings, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.globals, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.entfield, 1, sizeof(code_header.entfield)); + util_endianswap(&code_header->version, 1, sizeof(code_header->version)); + util_endianswap(&code_header->crc16, 1, sizeof(code_header->crc16)); + util_endianswap(&code_header->statements, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->defs, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->fields, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->functions, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->strings, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->globals, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->entfield, 1, sizeof(code_header->entfield)); + + /* + * These are not part of the header but we ensure LE format here to save on duplicated + * code. + */ util_endianswap(code->statements, vec_size(code->statements), sizeof(prog_section_statement)); util_endianswap(code->defs, vec_size(code->defs), sizeof(prog_section_def)); util_endianswap(code->fields, vec_size(code->fields), sizeof(prog_section_field)); util_endianswap(code->functions, vec_size(code->functions), sizeof(prog_section_function)); util_endianswap(code->globals, vec_size(code->globals), sizeof(int32_t)); +} + +/* + * Same principle except this one allocates memory and writes the lno(optional) and the dat file + * 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) { + prog_header code_header; + uint32_t offset = 0; + + if (!datmem) + return false; + + code_create_header(code, &code_header); + + #define WRITE_CHUNK(C,X,S) \ + do { \ + memcpy((void*)(&(*C)[offset]), (const void*)(X), (S)); \ + offset += (S); \ + } while (0) + + /* Calculate size required to store entire file out to memory */ + if (lnomem) { + uint32_t version = 1; + + *sizelno += 4; /* LNOF */ + *sizelno += sizeof(version); + *sizelno += sizeof(code_header.defs.length); + *sizelno += sizeof(code_header.globals.length); + *sizelno += sizeof(code_header.fields.length); + *sizelno += sizeof(code_header.statements.length); + *sizelno += sizeof(code->linenums[0]) * vec_size(code->linenums); + + *lnomem = (uint8_t*)mem_a(*sizelno); + + WRITE_CHUNK(lnomem, "LNOF", 4); + WRITE_CHUNK(lnomem, &version, sizeof(version)); + WRITE_CHUNK(lnomem, &code_header.defs.length, sizeof(code_header.defs.length)); + WRITE_CHUNK(lnomem, &code_header.globals.length, sizeof(code_header.globals.length)); + WRITE_CHUNK(lnomem, &code_header.fields.length, sizeof(code_header.fields.length)); + WRITE_CHUNK(lnomem, &code_header.statements.length, sizeof(code_header.statements.length)); + + /* something went terribly wrong */ + if (offset != *sizelno) { + mem_d(*lnomem); + *sizelno = 0; + return false; + } + offset = 0; + } + + /* Write out the dat */ + *sizedat += sizeof(prog_header); + *sizedat += sizeof(prog_section_statement) * vec_size(code->statements); + *sizedat += sizeof(prog_section_def) * vec_size(code->defs); + *sizedat += sizeof(prog_section_field) * vec_size(code->fields); + *sizedat += sizeof(prog_section_function) * vec_size(code->functions); + *sizedat += sizeof(int32_t) * vec_size(code->globals); + *sizedat += 1 * vec_size(code->chars); + + *datmem = (uint8_t*)mem_a(*sizedat); + + WRITE_CHUNK(datmem, &code_header, sizeof(prog_header)); + WRITE_CHUNK(datmem, code->statements, sizeof(prog_section_statement) * vec_size(code->statements)); + WRITE_CHUNK(datmem, code->defs, sizeof(prog_section_def) * vec_size(code->defs)); + WRITE_CHUNK(datmem, code->fields, sizeof(prog_section_field) * vec_size(code->fields)); + WRITE_CHUNK(datmem, code->functions, sizeof(prog_section_function) * vec_size(code->functions)); + WRITE_CHUNK(datmem, code->globals, sizeof(int32_t) * vec_size(code->globals)); + WRITE_CHUNK(datmem, code->chars, 1 * vec_size(code->chars)); + + #undef WRITE_CHUNK + + vec_free(code->statements); + vec_free(code->linenums); + vec_free(code->defs); + vec_free(code->fields); + vec_free(code->functions); + vec_free(code->globals); + vec_free(code->chars); + + util_htdel(code->string_cache); + mem_d(code); + + return true; +} + +bool code_write(code_t *code, const char *filename, const char *lnofile) { + prog_header code_header; + FILE *fp = NULL; + size_t it = 2; + + code_create_header(code, &code_header); if (lnofile) { uint32_t version = 1; @@ -175,13 +269,13 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) { util_endianswap(code->linenums, vec_size(code->linenums), sizeof(code->linenums[0])); - if (fs_file_write("LNOF", 4, 1, fp) != 1 || - fs_file_write(&version, sizeof(version), 1, fp) != 1 || + if (fs_file_write("LNOF", 4, 1, fp) != 1 || + fs_file_write(&version, sizeof(version), 1, fp) != 1 || fs_file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 || fs_file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 || fs_file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 || fs_file_write(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 || - fs_file_write(code->linenums, sizeof(code->linenums[0]), vec_size(code->linenums), fp) != vec_size(code->linenums)) + fs_file_write(code->linenums, sizeof(code->linenums[0]), vec_size(code->linenums), fp) != vec_size(code->linenums)) { con_err("failed to write lno file\n"); } @@ -194,7 +288,7 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) { if (!fp) return false; - if (1 != fs_file_write(&code_header, sizeof(prog_header) , 1 , fp) || + if (1 != fs_file_write(&code_header, sizeof(prog_header) , 1 , fp) || vec_size(code->statements) != fs_file_write(code->statements, sizeof(prog_section_statement), vec_size(code->statements), fp) || vec_size(code->defs) != fs_file_write(code->defs, sizeof(prog_section_def) , vec_size(code->defs) , fp) || vec_size(code->fields) != fs_file_write(code->fields, sizeof(prog_section_field) , vec_size(code->fields) , fp) || From c07c78c666cd749b92862fa08c74b7b7c1138ddc Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Thu, 2 May 2013 19:18:59 +0000 Subject: [PATCH 09/63] Escape strings in executor for -printdefs --- exec.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 0ef3211..9bb3539 100644 --- a/exec.c +++ b/exec.c @@ -923,6 +923,32 @@ static void prog_main_setparams(qc_program *prog) } } +void escapestring(char* dest, const char* src) { + char c; + while ((c = *(src++))) { + switch(c) { + case '\t': + *(dest++) = '\\', *(dest++) = 't'; + break; + case '\n': + *(dest++) = '\\', *(dest++) = 'n'; + break; + case '\r': + *(dest++) = '\\', *(dest++) = 'r'; + break; + case '\\': + *(dest++) = '\\', *(dest++) = '\\'; + break; + case '\"': + *(dest++) = '\\', *(dest++) = '\"'; + break; + default: + *(dest++) = c; + } + } + *dest = '\0'; +} + void prog_disasm_function(qc_program *prog, size_t id); int main(int argc, char **argv) { @@ -1137,6 +1163,9 @@ int main(int argc, char **argv) return 0; } if (opts_printdefs) { + char *escape = NULL; + const char *getstring = NULL; + for (i = 0; i < vec_size(prog->defs); ++i) { printf("Global: %8s %-16s at %u%s", type_name[prog->defs[i].type & DEF_TYPEMASK], @@ -1158,7 +1187,12 @@ int main(int argc, char **argv) printf(" [init: %u]", (unsigned)( ((qcany*)(prog->globals + prog->defs[i].offset))->_int )); break; case TYPE_STRING: - printf(" [init: `%s`]", prog_getstring(prog, ((qcany*)(prog->globals + prog->defs[i].offset))->string )); + getstring = prog_getstring(prog, ((qcany*)(prog->globals + prog->defs[i].offset))->string); + escape = (char*)mem_a(strlen(getstring) * 2 + 1); /* will be enough */ + escapestring(escape, getstring); + printf(" [init: `%s`]", escape); + + mem_d(escape); /* free */ break; default: break; From 9823b294dfaa7176cd78b5f758f6f8a3ee10e879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 5 May 2013 12:53:58 +0200 Subject: [PATCH 10/63] .gitignore: add binarys --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 416e445..0405639 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,8 @@ distro/archbsd/* !distro/archbsd/release/PKGBUILD !distro/archbsd/git/PKGBUILD !distro/archlinux/this/Makefile + +gmqcc +gmqpak +qcvm +testsuite From 8c8ae71d653e3111fc9857ad3381489b82b18a4b Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 7 May 2013 19:39:10 +0200 Subject: [PATCH 11/63] changing a few ast_delete to ast_unref in places where the to-be-deleted maybe coming from some other place --- parser.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/parser.c b/parser.c index a09a54a..5d36bfe 100644 --- a/parser.c +++ b/parser.c @@ -2453,17 +2453,17 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out) /* closing paren */ if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'if' condition"); - ast_delete(cond); + ast_unref(cond); return false; } /* parse into the 'then' branch */ if (!parser_next(parser)) { parseerror(parser, "expected statement for on-true branch of 'if'"); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &ontrue)) { - ast_delete(cond); + ast_unref(cond); return false; } if (!ontrue) @@ -2474,12 +2474,12 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out) if (!parser_next(parser)) { parseerror(parser, "expected on-false branch after 'else'"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &onfalse)) { ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } } @@ -2576,23 +2576,23 @@ static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression ** /* closing paren */ if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'while' condition"); - ast_delete(cond); + ast_unref(cond); return false; } /* parse into the 'then' branch */ if (!parser_next(parser)) { parseerror(parser, "expected while-loop body"); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &ontrue)) { - ast_delete(cond); + ast_unref(cond); return false; } cond = process_condition(parser, cond, &ifnot); if (!cond) { - ast_delete(ontrue); + ast_unref(ontrue); return false; } aloop = ast_loop_new(ctx, NULL, cond, ifnot, NULL, false, NULL, ontrue); @@ -2692,21 +2692,21 @@ static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'while' condition"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } /* parse on */ if (!parser_next(parser) || parser->tok != ';') { parseerror(parser, "expected semicolon after condition"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } if (!parser_next(parser)) { parseerror(parser, "parse error"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } @@ -2883,9 +2883,9 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou retval = false; return retval; onerr: - if (initexpr) ast_delete(initexpr); - if (cond) ast_delete(cond); - if (increment) ast_delete(increment); + if (initexpr) ast_unref(initexpr); + if (cond) ast_unref(cond); + if (increment) ast_unref(increment); (void)!parser_leaveblock(parser); return false; } @@ -2918,7 +2918,7 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou ret = ast_return_new(ctx, exp); if (!ret) { - ast_delete(exp); + ast_unref(exp); return false; } } else { From c5225b2fa1e314447392febdd1dee2a2a1744016 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 7 May 2013 19:56:41 +0200 Subject: [PATCH 12/63] fixing a few leaks - code_write doesn't delete the code object anymore, code_cleanup has to be called --- code.c | 7 +++++-- ftepp.c | 6 +----- gmqcc.h | 1 + ir.c | 1 + parser.c | 3 ++- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/code.c b/code.c index 77bba3e..80154d0 100644 --- a/code.c +++ b/code.c @@ -354,6 +354,11 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) { } } + fs_file_close(fp); + return true; +} + +void code_cleanup(code_t *code) { vec_free(code->statements); vec_free(code->linenums); vec_free(code->defs); @@ -364,7 +369,5 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) { util_htdel(code->string_cache); - fs_file_close(fp); mem_d(code); - return true; } diff --git a/ftepp.c b/ftepp.c index 595b520..9fc0025 100644 --- a/ftepp.c +++ b/ftepp.c @@ -374,7 +374,7 @@ static GMQCC_INLINE ppmacro* ftepp_macro_find(ftepp_t *ftepp, const char *name) static GMQCC_INLINE void ftepp_macro_delete(ftepp_t *ftepp, const char *name) { - util_htrm(ftepp->macros, name, NULL); + util_htrm(ftepp->macros, name, (void (*)(void*))&ppmacro_delete); } static GMQCC_INLINE int ftepp_next(ftepp_t *ftepp) @@ -564,10 +564,6 @@ static bool ftepp_define(ftepp_t *ftepp) return false; } -#if 0 - if (ftepp->output_on) - vec_push(ftepp->macros, macro); -#endif if (ftepp->output_on) util_htset(ftepp->macros, macro->name, (void*)macro); else { diff --git a/gmqcc.h b/gmqcc.h index 0031227..033a2d0 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -735,6 +735,7 @@ typedef struct { */ bool code_write (code_t *, const char *filename, const char *lno); code_t *code_init (void); +void code_cleanup (code_t *); 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); diff --git a/ir.c b/ir.c index a124bd1..00d0875 100644 --- a/ir.c +++ b/ir.c @@ -340,6 +340,7 @@ void ir_builder_delete(ir_builder* self) ir_value_delete(self->extparams[i]); } vec_free(self->extparams); + vec_free(self->extparam_protos); for (i = 0; i != vec_size(self->globals); ++i) { ir_value_delete(self->globals[i]); } diff --git a/parser.c b/parser.c index 5d36bfe..6ad5502 100644 --- a/parser.c +++ b/parser.c @@ -6016,7 +6016,6 @@ parser_t *parser_create() mem_d(parser); return NULL; } - for (i = 0; i < operator_count; ++i) { if (operators[i].id == opid1('=')) { @@ -6195,6 +6194,8 @@ void parser_cleanup(parser_t *parser) intrin_intrinsics_destroy(parser); + code_cleanup(parser->code); + mem_d(parser); } From 4d0a5af4750db921c43cc724bfb5397b67bf7f69 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 7 May 2013 19:59:06 +0200 Subject: [PATCH 13/63] removing this dead code_init call --- gmqcc.h | 1 + ir.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/gmqcc.h b/gmqcc.h index 033a2d0..fc93d92 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -734,6 +734,7 @@ typedef struct { * code_pop_statement -- keeps statements and linenumbers together */ bool code_write (code_t *, const char *filename, const char *lno); +GMQCC_WARN code_t *code_init (void); void code_cleanup (code_t *); uint32_t code_genstring (code_t *, const char *string); diff --git a/ir.c b/ir.c index 00d0875..b67a37c 100644 --- a/ir.c +++ b/ir.c @@ -3570,8 +3570,6 @@ bool ir_builder_generate(code_t *code, ir_builder *self, const char *filename) size_t i; char *lnofile = NULL; - code_init(); - for (i = 0; i < vec_size(self->fields); ++i) { ir_builder_prepare_field(code, self->fields[i]); From 802005f57192f91b73871d48ce8c4b0b64bd6ad1 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 7 May 2013 20:13:19 +0200 Subject: [PATCH 14/63] be more strict here --- parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parser.c b/parser.c index 6ad5502..c95ff91 100644 --- a/parser.c +++ b/parser.c @@ -2227,8 +2227,8 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma } parser->lex->flags.noops = true; - if (!vec_size(sy.out)) { - parseerror(parser, "empty expression"); + if (vec_size(sy.out) != 1) { + parseerror(parser, "expression with not 1 but %lu output values...", (unsigned long) vec_size(sy.out)); expr = NULL; } else expr = sy.out[0].out; From a0fa90ddd555f7d55042b0fb542e63e6b10ad7e2 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 7 May 2013 20:35:20 +0200 Subject: [PATCH 15/63] less confusing --- parser.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/parser.c b/parser.c index c95ff91..4d50bad 100644 --- a/parser.c +++ b/parser.c @@ -2779,7 +2779,6 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou ast_expression *initexpr, *cond, *increment, *ontrue; ast_value *typevar; - bool retval = true; bool ifnot = false; lex_ctx ctx = parser_ctx(parser); @@ -2879,9 +2878,11 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou aloop = ast_loop_new(ctx, initexpr, cond, ifnot, NULL, false, increment, ontrue); *out = (ast_expression*)aloop; - if (!parser_leaveblock(parser)) - retval = false; - return retval; + if (!parser_leaveblock(parser)) { + ast_delete(aloop); + return false; + } + return true; onerr: if (initexpr) ast_unref(initexpr); if (cond) ast_unref(cond); From ef6e2bd5838cfd0935a230805e22591158dfc3bc Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Sat, 11 May 2013 22:05:30 +0200 Subject: [PATCH 16/63] first step to getting rid of those unions we don't use anyway --- ast.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ast.h b/ast.h index 98ad792..f18c73e 100644 --- a/ast.h +++ b/ast.h @@ -683,14 +683,6 @@ bool ast_generate_accessors(ast_value *asvalue, ir_builder *ir); union ast_expression_u { ast_expression_common expression; - - ast_value value; - ast_binary binary; - ast_block block; - ast_ternary ternary; - ast_ifthen ifthen; - ast_store store; - ast_entfield entfield; }; /* Node union @@ -698,7 +690,6 @@ union ast_expression_u union ast_node_u { ast_node_common node; - ast_expression expression; }; #endif From d70b5717699c7f0f1ec8fa98b1fa938f7d5b0bd2 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Sat, 11 May 2013 22:34:01 +0200 Subject: [PATCH 17/63] killing the union types --- ast.c | 274 +++++++++++++++++++++++++++---------------------------- ast.h | 84 +++++++---------- parser.c | 272 +++++++++++++++++++++++++++--------------------------- 3 files changed, 308 insertions(+), 322 deletions(-) diff --git a/ast.c b/ast.c index 1e2836f..b104073 100644 --- a/ast.c +++ b/ast.c @@ -34,7 +34,7 @@ return NULL; \ } \ ast_node_init((ast_node*)self, ctx, TYPE_##T); \ - ( (ast_node*)self )->node.destroy = (ast_node_delete*)destroyfn + ( (ast_node*)self )->destroy = (ast_node_delete*)destroyfn /* It must not be possible to get here. */ @@ -48,11 +48,11 @@ static GMQCC_NORETURN void _ast_node_destroy(ast_node *self) /* Initialize main ast node aprts */ static void ast_node_init(ast_node *self, lex_ctx ctx, int nodetype) { - self->node.context = ctx; - self->node.destroy = &_ast_node_destroy; - self->node.keep = false; - self->node.nodetype = nodetype; - self->node.side_effects = false; + self->context = ctx; + self->destroy = &_ast_node_destroy; + self->keep = false; + self->nodetype = nodetype; + self->side_effects = false; } /* weight and side effects */ @@ -67,28 +67,28 @@ static void _ast_propagate_effects(ast_node *self, ast_node *other) static void ast_expression_init(ast_expression *self, ast_expression_codegen *codegen) { - self->expression.codegen = codegen; - self->expression.vtype = TYPE_VOID; - self->expression.next = NULL; - self->expression.outl = NULL; - self->expression.outr = NULL; - self->expression.params = NULL; - self->expression.count = 0; - self->expression.flags = 0; - self->expression.varparam = NULL; + self->codegen = codegen; + self->vtype = TYPE_VOID; + self->next = NULL; + self->outl = NULL; + self->outr = NULL; + self->params = NULL; + self->count = 0; + self->flags = 0; + self->varparam = NULL; } static void ast_expression_delete(ast_expression *self) { size_t i; - if (self->expression.next) - ast_delete(self->expression.next); - for (i = 0; i < vec_size(self->expression.params); ++i) { - ast_delete(self->expression.params[i]); + if (self->next) + ast_delete(self->next); + for (i = 0; i < vec_size(self->params); ++i) { + ast_delete(self->params[i]); } - vec_free(self->expression.params); - if (self->expression.varparam) - ast_delete(self->expression.varparam); + vec_free(self->params); + if (self->varparam) + ast_delete(self->varparam); } static void ast_expression_delete_full(ast_expression *self) @@ -100,8 +100,8 @@ static void ast_expression_delete_full(ast_expression *self) ast_value* ast_value_copy(const ast_value *self) { size_t i; - const ast_expression_common *fromex; - ast_expression_common *selfex; + const ast_expression *fromex; + ast_expression *selfex; ast_value *cp = ast_value_new(self->expression.node.context, self->name, self->expression.vtype); if (self->expression.next) { cp->expression.next = ast_type_copy(self->expression.node.context, self->expression.next); @@ -120,14 +120,14 @@ ast_value* ast_value_copy(const ast_value *self) void ast_type_adopt_impl(ast_expression *self, const ast_expression *other) { size_t i; - const ast_expression_common *fromex; - ast_expression_common *selfex; - self->expression.vtype = other->expression.vtype; - if (other->expression.next) { - self->expression.next = (ast_expression*)ast_type_copy(ast_ctx(self), other->expression.next); + const ast_expression *fromex; + ast_expression *selfex; + self->vtype = other->vtype; + if (other->next) { + self->next = (ast_expression*)ast_type_copy(ast_ctx(self), other->next); } - fromex = &other->expression; - selfex = &self->expression; + fromex = other; + selfex = self; selfex->count = fromex->count; selfex->flags = fromex->flags; for (i = 0; i < vec_size(fromex->params); ++i) { @@ -140,17 +140,17 @@ static ast_expression* ast_shallow_type(lex_ctx ctx, int vtype) { ast_instantiate(ast_expression, ctx, ast_expression_delete_full); ast_expression_init(self, NULL); - self->expression.codegen = NULL; - self->expression.next = NULL; - self->expression.vtype = vtype; + self->codegen = NULL; + self->next = NULL; + self->vtype = vtype; return self; } ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex) { size_t i; - const ast_expression_common *fromex; - ast_expression_common *selfex; + const ast_expression *fromex; + ast_expression *selfex; if (!ex) return NULL; @@ -159,8 +159,8 @@ ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex) ast_instantiate(ast_expression, ctx, ast_expression_delete_full); ast_expression_init(self, NULL); - fromex = &ex->expression; - selfex = &self->expression; + fromex = ex; + selfex = self; /* This may never be codegen()d */ selfex->codegen = NULL; @@ -184,30 +184,30 @@ ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex) bool ast_compare_type(ast_expression *a, ast_expression *b) { - if (a->expression.vtype == TYPE_NIL || - b->expression.vtype == TYPE_NIL) + if (a->vtype == TYPE_NIL || + b->vtype == TYPE_NIL) return true; - if (a->expression.vtype != b->expression.vtype) + if (a->vtype != b->vtype) return false; - if (!a->expression.next != !b->expression.next) + if (!a->next != !b->next) return false; - if (vec_size(a->expression.params) != vec_size(b->expression.params)) + if (vec_size(a->params) != vec_size(b->params)) return false; - if ((a->expression.flags & AST_FLAG_TYPE_MASK) != - (b->expression.flags & AST_FLAG_TYPE_MASK) ) + if ((a->flags & AST_FLAG_TYPE_MASK) != + (b->flags & AST_FLAG_TYPE_MASK) ) { return false; } - if (vec_size(a->expression.params)) { + if (vec_size(a->params)) { size_t i; - for (i = 0; i < vec_size(a->expression.params); ++i) { - if (!ast_compare_type((ast_expression*)a->expression.params[i], - (ast_expression*)b->expression.params[i])) + for (i = 0; i < vec_size(a->params); ++i) { + if (!ast_compare_type((ast_expression*)a->params[i], + (ast_expression*)b->params[i])) return false; } } - if (a->expression.next) - return ast_compare_type(a->expression.next, b->expression.next); + if (a->next) + return ast_compare_type(a->next, b->next); return true; } @@ -227,43 +227,43 @@ static size_t ast_type_to_string_impl(ast_expression *e, char *buf, size_t bufsi if (pos + 1 >= bufsize) goto full; - switch (e->expression.vtype) { + switch (e->vtype) { case TYPE_VARIANT: util_strncpy(buf + pos, "(variant)", 9); return pos + 9; case TYPE_FIELD: buf[pos++] = '.'; - return ast_type_to_string_impl(e->expression.next, buf, bufsize, pos); + return ast_type_to_string_impl(e->next, buf, bufsize, pos); case TYPE_POINTER: if (pos + 3 >= bufsize) goto full; buf[pos++] = '*'; buf[pos++] = '('; - pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos); + pos = ast_type_to_string_impl(e->next, buf, bufsize, pos); if (pos + 1 >= bufsize) goto full; buf[pos++] = ')'; return pos; case TYPE_FUNCTION: - pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos); + pos = ast_type_to_string_impl(e->next, buf, bufsize, pos); if (pos + 2 >= bufsize) goto full; - if (!vec_size(e->expression.params)) { + if (!vec_size(e->params)) { buf[pos++] = '('; buf[pos++] = ')'; return pos; } buf[pos++] = '('; - pos = ast_type_to_string_impl((ast_expression*)(e->expression.params[0]), buf, bufsize, pos); - for (i = 1; i < vec_size(e->expression.params); ++i) { + pos = ast_type_to_string_impl((ast_expression*)(e->params[0]), buf, bufsize, pos); + for (i = 1; i < vec_size(e->params); ++i) { if (pos + 2 >= bufsize) goto full; buf[pos++] = ','; buf[pos++] = ' '; - pos = ast_type_to_string_impl((ast_expression*)(e->expression.params[i]), buf, bufsize, pos); + pos = ast_type_to_string_impl((ast_expression*)(e->params[i]), buf, bufsize, pos); } if (pos + 1 >= bufsize) goto full; @@ -271,18 +271,18 @@ static size_t ast_type_to_string_impl(ast_expression *e, char *buf, size_t bufsi return pos; case TYPE_ARRAY: - pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos); + pos = ast_type_to_string_impl(e->next, buf, bufsize, pos); if (pos + 1 >= bufsize) goto full; buf[pos++] = '['; - pos += util_snprintf(buf + pos, bufsize - pos - 1, "%i", (int)e->expression.count); + pos += util_snprintf(buf + pos, bufsize - pos - 1, "%i", (int)e->count); if (pos + 1 >= bufsize) goto full; buf[pos++] = ']'; return pos; default: - typestr = type_name[e->expression.vtype]; + typestr = type_name[e->vtype]; typelen = strlen(typestr); if (pos + typelen >= bufsize) goto full; @@ -364,7 +364,7 @@ void ast_value_delete(ast_value* self) mem_d(self->desc); if (self->initlist) { - if (self->expression.next->expression.vtype == TYPE_STRING) { + if (self->expression.next->vtype == TYPE_STRING) { /* strings are allocated, free them */ size_t i, len = vec_size(self->initlist); /* in theory, len should be expression.count @@ -422,7 +422,7 @@ ast_binary* ast_binary_new(lex_ctx ctx, int op, else if (op == INSTR_MUL_V) self->expression.vtype = TYPE_FLOAT; else - self->expression.vtype = left->expression.vtype; + self->expression.vtype = left->vtype; /* references all */ self->refs = AST_REF_ALL; @@ -516,11 +516,11 @@ void ast_return_delete(ast_return *self) ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field) { - if (field->expression.vtype != TYPE_FIELD) { + if (field->vtype != TYPE_FIELD) { compile_error(ctx, "ast_entfield_new with expression not of type field"); return NULL; } - return ast_entfield_new_force(ctx, entity, field, field->expression.next); + return ast_entfield_new_force(ctx, entity, field, field->next); } ast_entfield* ast_entfield_new_force(lex_ctx ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype) @@ -560,9 +560,9 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel return NULL; } - if (owner->expression.vtype != TYPE_VECTOR && - owner->expression.vtype != TYPE_FIELD) { - compile_error(ctx, "member-access on an invalid owner of type %s", type_name[owner->expression.vtype]); + if (owner->vtype != TYPE_VECTOR && + owner->vtype != TYPE_FIELD) { + compile_error(ctx, "member-access on an invalid owner of type %s", type_name[owner->vtype]); mem_d(self); return NULL; } @@ -570,7 +570,7 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_member_codegen); self->expression.node.keep = true; /* keep */ - if (owner->expression.vtype == TYPE_VECTOR) { + if (owner->vtype == TYPE_VECTOR) { self->expression.vtype = TYPE_FLOAT; self->expression.next = NULL; } else { @@ -619,7 +619,7 @@ ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_exp ast_expression *outtype; ast_instantiate(ast_array_index, ctx, ast_array_index_delete); - outtype = array->expression.next; + outtype = array->next; if (!outtype) { mem_d(self); /* Error: field has no type... */ @@ -634,7 +634,7 @@ ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_exp ast_propagate_effects(self, index); ast_type_adopt(self, outtype); - if (array->expression.vtype == TYPE_FIELD && outtype->expression.vtype == TYPE_ARRAY) { + if (array->vtype == TYPE_FIELD && outtype->vtype == TYPE_ARRAY) { if (self->expression.vtype != TYPE_ARRAY) { compile_error(ast_ctx(self), "array_index node on type"); ast_array_index_delete(self); @@ -708,7 +708,7 @@ ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression * ast_propagate_effects(self, ontrue); ast_propagate_effects(self, onfalse); - if (ontrue->expression.vtype == TYPE_NIL) + if (ontrue->vtype == TYPE_NIL) exprtype = onfalse; ast_type_adopt(self, exprtype); @@ -878,7 +878,7 @@ ast_call* ast_call_new(lex_ctx ctx, ast_expression *funcexpr) { ast_instantiate(ast_call, ctx, ast_call_delete); - if (!funcexpr->expression.next) { + if (!funcexpr->next) { compile_error(ctx, "not a function"); mem_d(self); return NULL; @@ -891,7 +891,7 @@ ast_call* ast_call_new(lex_ctx ctx, self->func = funcexpr; self->va_count = NULL; - ast_type_adopt(self, funcexpr->expression.next); + ast_type_adopt(self, funcexpr->next); return self; } @@ -921,14 +921,14 @@ bool ast_call_check_types(ast_call *self) bool retval = true; const ast_expression *func = self->func; size_t count = vec_size(self->params); - if (count > vec_size(func->expression.params)) - count = vec_size(func->expression.params); + if (count > vec_size(func->params)) + count = vec_size(func->params); for (i = 0; i < count; ++i) { - if (!ast_compare_type(self->params[i], (ast_expression*)(func->expression.params[i]))) + if (!ast_compare_type(self->params[i], (ast_expression*)(func->params[i]))) { ast_type_to_string(self->params[i], tgot, sizeof(tgot)); - ast_type_to_string((ast_expression*)func->expression.params[i], texp, sizeof(texp)); + ast_type_to_string((ast_expression*)func->params[i], texp, sizeof(texp)); compile_error(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s", (unsigned int)(i+1), texp, tgot); /* we don't immediately return */ @@ -936,12 +936,12 @@ bool ast_call_check_types(ast_call *self) } } count = vec_size(self->params); - if (count > vec_size(func->expression.params) && func->expression.varparam) { + if (count > vec_size(func->params) && func->varparam) { for (; i < count; ++i) { - if (!ast_compare_type(self->params[i], func->expression.varparam)) + if (!ast_compare_type(self->params[i], func->varparam)) { ast_type_to_string(self->params[i], tgot, sizeof(tgot)); - ast_type_to_string(func->expression.varparam, texp, sizeof(texp)); + ast_type_to_string(func->varparam, texp, sizeof(texp)); compile_error(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s", (unsigned int)(i+1), texp, tgot); /* we don't immediately return */ @@ -1005,7 +1005,7 @@ bool ast_block_add_expr(ast_block *self, ast_expression *e) void ast_block_collect(ast_block *self, ast_expression *expr) { vec_push(self->collect, expr); - expr->expression.node.keep = true; + expr->node.keep = true; } void ast_block_delete(ast_block *self) @@ -1132,12 +1132,12 @@ const char* ast_function_label(ast_function *self, const char *prefix) * But I can't imagine a pituation where the output is truly unnecessary. */ -void _ast_codegen_output_type(ast_expression_common *self, ir_value *out) +void _ast_codegen_output_type(ast_expression *self, ir_value *out) { if (out->vtype == TYPE_FIELD) - out->fieldtype = self->next->expression.vtype; + out->fieldtype = self->next->vtype; if (out->vtype == TYPE_FUNCTION) - out->outtype = self->next->expression.vtype; + out->outtype = self->next->vtype; } #define codegen_output_type(a,o) (_ast_codegen_output_type(&((a)->expression),(o))) @@ -1178,7 +1178,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) if (self->hasvalue && self->expression.vtype == TYPE_FUNCTION) { - ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->expression.vtype); + ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->vtype); if (!func) return false; func->context = ast_ctx(self); @@ -1200,14 +1200,14 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) goto error; } - if (fieldtype->expression.vtype == TYPE_ARRAY) { + if (fieldtype->vtype == TYPE_ARRAY) { size_t ai; char *name; size_t namelen; - ast_expression_common *elemtype; - int vtype; - ast_value *array = (ast_value*)fieldtype; + ast_expression *elemtype; + int vtype; + ast_value *array = (ast_value*)fieldtype; if (!ast_istype(fieldtype, ast_value)) { compile_error(ast_ctx(self), "internal error: ast_value required"); @@ -1218,7 +1218,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) if (!array->expression.count || array->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE)) compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count); - elemtype = &array->expression.next->expression; + elemtype = array->expression.next; vtype = elemtype->vtype; v = ir_builder_create_field(ir, self->name, vtype); @@ -1257,7 +1257,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) } else { - v = ir_builder_create_field(ir, self->name, self->expression.next->expression.vtype); + v = ir_builder_create_field(ir, self->name, self->expression.next->vtype); if (!v) return false; v->context = ast_ctx(self); @@ -1273,7 +1273,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) char *name; size_t namelen; - ast_expression_common *elemtype = &self->expression.next->expression; + ast_expression *elemtype = self->expression.next; int vtype = elemtype->vtype; /* same as with field arrays */ @@ -1403,7 +1403,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param) char *name; size_t namelen; - ast_expression_common *elemtype = &self->expression.next->expression; + ast_expression *elemtype = self->expression.next; int vtype = elemtype->vtype; func->flags |= IR_FLAG_HAS_ARRAYS; @@ -1550,7 +1550,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) { ir_function *irf; ir_value *dummy; - ast_expression_common *ec; + ast_expression *ec; ast_expression_codegen *cgen; size_t i; @@ -1567,7 +1567,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) for (i = 0; i < vec_size(ec->params); ++i) { if (ec->params[i]->expression.vtype == TYPE_FIELD) - vec_push(irf->params, ec->params[i]->expression.next->expression.vtype); + vec_push(irf->params, ec->params[i]->expression.next->vtype); else vec_push(irf->params, ec->params[i]->expression.vtype); if (!self->builtin) { @@ -1632,7 +1632,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) if (!self->curblock->final) { if (!self->vtype->expression.next || - self->vtype->expression.next->expression.vtype == TYPE_VOID) + self->vtype->expression.next->vtype == TYPE_VOID) { return ir_block_create_return(self->curblock, ast_ctx(self), NULL); } @@ -1701,7 +1701,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu return false; continue; } - gen = self->exprs[i]->expression.codegen; + gen = self->exprs[i]->codegen; if (!(*gen)(self->exprs[i], func, false, out)) return false; } @@ -1765,7 +1765,7 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval)) return false; - cgen = self->source->expression.codegen; + cgen = self->source->codegen; if (!(*cgen)((ast_expression*)(self->source), func, false, &right)) return false; @@ -1780,13 +1780,13 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu { /* regular code */ - cgen = self->dest->expression.codegen; + cgen = self->dest->codegen; /* lvalue! */ if (!(*cgen)((ast_expression*)(self->dest), func, true, &left)) return false; self->expression.outl = left; - cgen = self->source->expression.codegen; + cgen = self->source->codegen; /* rvalue! */ if (!(*cgen)((ast_expression*)(self->source), func, false, &right)) return false; @@ -1838,7 +1838,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_merge")); /* generate the left expression */ - cgen = self->left->expression.codegen; + cgen = self->left->codegen; if (!(*cgen)((ast_expression*)(self->left), func, false, &left)) return false; /* remember the block */ @@ -1861,7 +1861,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va /* enter the right-expression's block */ func->curblock = other; /* generate */ - cgen = self->right->expression.codegen; + cgen = self->right->codegen; if (!(*cgen)((ast_expression*)(self->right), func, false, &right)) return false; /* remember block */ @@ -1924,11 +1924,11 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va return true; } - cgen = self->left->expression.codegen; + cgen = self->left->codegen; if (!(*cgen)((ast_expression*)(self->left), func, false, &left)) return false; - cgen = self->right->expression.codegen; + cgen = self->right->codegen; if (!(*cgen)((ast_expression*)(self->right), func, false, &right)) return false; @@ -1979,12 +1979,12 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i if (!(*cgen)((ast_expression*)(idx), func, false, &iridx)) return false; } - cgen = self->dest->expression.codegen; + cgen = self->dest->codegen; if (!(*cgen)((ast_expression*)(self->dest), func, false, &leftr)) return false; /* source as rvalue only */ - cgen = self->source->expression.codegen; + cgen = self->source->codegen; if (!(*cgen)((ast_expression*)(self->source), func, false, &right)) return false; @@ -2022,7 +2022,7 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i self->expression.outr = bin; } else { /* now store them */ - cgen = self->dest->expression.codegen; + cgen = self->dest->codegen; /* lvalue of destination */ if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftl)) return false; @@ -2061,7 +2061,7 @@ bool ast_unary_codegen(ast_unary *self, ast_function *func, bool lvalue, ir_valu return true; } - cgen = self->operand->expression.codegen; + cgen = self->operand->codegen; /* lvalue! */ if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand)) return false; @@ -2097,7 +2097,7 @@ bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_va self->expression.outr = (ir_value*)1; if (self->operand) { - cgen = self->operand->expression.codegen; + cgen = self->operand->codegen; /* lvalue! */ if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand)) return false; @@ -2132,11 +2132,11 @@ bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, i return true; } - cgen = self->entity->expression.codegen; + cgen = self->entity->codegen; if (!(*cgen)((ast_expression*)(self->entity), func, false, &ent)) return false; - cgen = self->field->expression.codegen; + cgen = self->field->codegen; if (!(*cgen)((ast_expression*)(self->field), func, false, &field)) return false; @@ -2184,12 +2184,12 @@ bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_va return true; } - cgen = self->owner->expression.codegen; + cgen = self->owner->codegen; if (!(*cgen)((ast_expression*)(self->owner), func, false, &vec)) return false; if (vec->vtype != TYPE_VECTOR && - !(vec->vtype == TYPE_FIELD && self->owner->expression.next->expression.vtype == TYPE_VECTOR)) + !(vec->vtype == TYPE_FIELD && self->owner->next->vtype == TYPE_VECTOR)) { return false; } @@ -2243,7 +2243,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva return false; } - cgen = self->index->expression.codegen; + cgen = self->index->codegen; if (!(*cgen)((ast_expression*)(self->index), func, false, &iridx)) return false; @@ -2265,7 +2265,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva if (idx->expression.vtype == TYPE_FLOAT) { unsigned int arridx = idx->constval.vfloat; - if (arridx >= self->array->expression.count) + if (arridx >= self->array->count) { compile_error(ast_ctx(self), "array index out of bounds: %i", arridx); return false; @@ -2274,7 +2274,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva } else if (idx->expression.vtype == TYPE_INTEGER) { unsigned int arridx = idx->constval.vint; - if (arridx >= self->array->expression.count) + if (arridx >= self->array->count) { compile_error(ast_ctx(self), "array index out of bounds: %i", arridx); return false; @@ -2315,7 +2315,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va self->expression.outr = (ir_value*)1; /* generate the condition */ - cgen = self->cond->expression.codegen; + cgen = self->cond->codegen; if (!(*cgen)((ast_expression*)(self->cond), func, false, &condval)) return false; /* update the block which will get the jump - because short-logic or ternaries may have changed this */ @@ -2333,7 +2333,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va func->curblock = ontrue; /* generate */ - cgen = self->on_true->expression.codegen; + cgen = self->on_true->codegen; if (!(*cgen)((ast_expression*)(self->on_true), func, false, &dummy)) return false; @@ -2353,7 +2353,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va func->curblock = onfalse; /* generate */ - cgen = self->on_false->expression.codegen; + cgen = self->on_false->codegen; if (!(*cgen)((ast_expression*)(self->on_false), func, false, &dummy)) return false; @@ -2422,7 +2422,7 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ /* generate the condition */ func->curblock = cond; - cgen = self->cond->expression.codegen; + cgen = self->cond->codegen; if (!(*cgen)((ast_expression*)(self->cond), func, false, &condval)) return false; cond_out = func->curblock; @@ -2437,7 +2437,7 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ func->curblock = ontrue; /* generate */ - cgen = self->on_true->expression.codegen; + cgen = self->on_true->codegen; if (!(*cgen)((ast_expression*)(self->on_true), func, false, &trueval)) return false; @@ -2454,7 +2454,7 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ func->curblock = onfalse; /* generate */ - cgen = self->on_false->expression.codegen; + cgen = self->on_false->codegen; if (!(*cgen)((ast_expression*)(self->on_false), func, false, &falseval)) return false; @@ -2551,7 +2551,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value */ if (self->initexpr) { - cgen = self->initexpr->expression.codegen; + cgen = self->initexpr->codegen; if (!(*cgen)((ast_expression*)(self->initexpr), func, false, &dummy)) return false; } @@ -2575,7 +2575,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value func->curblock = bprecond; /* generate */ - cgen = self->precond->expression.codegen; + cgen = self->precond->codegen; if (!(*cgen)((ast_expression*)(self->precond), func, false, &precond)) return false; @@ -2629,7 +2629,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value /* generate */ if (self->body) { - cgen = self->body->expression.codegen; + cgen = self->body->codegen; if (!(*cgen)((ast_expression*)(self->body), func, false, &dummy)) return false; } @@ -2646,7 +2646,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value func->curblock = bpostcond; /* generate */ - cgen = self->postcond->expression.codegen; + cgen = self->postcond->codegen; if (!(*cgen)((ast_expression*)(self->postcond), func, false, &postcond)) return false; @@ -2660,7 +2660,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value func->curblock = bincrement; /* generate */ - cgen = self->increment->expression.codegen; + cgen = self->increment->codegen; if (!(*cgen)((ast_expression*)(self->increment), func, false, &dummy)) return false; @@ -2809,7 +2809,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va (void)lvalue; (void)out; - cgen = self->operand->expression.codegen; + cgen = self->operand->codegen; if (!(*cgen)((ast_expression*)(self->operand), func, false, &irop)) return false; @@ -2842,7 +2842,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va if (swcase->value) { /* A regular case */ /* generate the condition operand */ - cgen = swcase->value->expression.codegen; + cgen = swcase->value->codegen; if (!(*cgen)((ast_expression*)(swcase->value), func, false, &val)) return false; /* generate the condition */ @@ -2870,7 +2870,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va /* enter the case */ func->curblock = bcase; - cgen = swcase->code->expression.codegen; + cgen = swcase->code->codegen; if (!(*cgen)((ast_expression*)swcase->code, func, false, &dummy)) return false; @@ -2915,7 +2915,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va } /* Now generate the default code */ - cgen = def_case->code->expression.codegen; + cgen = def_case->code->codegen; if (!(*cgen)((ast_expression*)def_case->code, func, false, &dummy)) return false; @@ -3040,7 +3040,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value return true; } - cgen = self->func->expression.codegen; + cgen = self->func->codegen; if (!(*cgen)((ast_expression*)(self->func), func, false, &funval)) return false; if (!funval) @@ -3054,7 +3054,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value ir_value *param; ast_expression *expr = self->params[i]; - cgen = expr->expression.codegen; + cgen = expr->codegen; if (!(*cgen)(expr, func, false, ¶m)) goto error; if (!param) @@ -3066,7 +3066,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value if (self->va_count) { ir_value *va_count; ir_builder *builder = func->curblock->owner->owner; - cgen = self->va_count->expression.codegen; + cgen = self->va_count->codegen; if (!(*cgen)((ast_expression*)(self->va_count), func, false, &va_count)) return false; if (!ir_block_create_store_op(func->curblock, ast_ctx(self), INSTR_STORE_F, @@ -3078,7 +3078,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value callinstr = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "call"), - funval, !!(self->func->expression.flags & AST_FLAG_NORETURN)); + funval, !!(self->func->flags & AST_FLAG_NORETURN)); if (!callinstr) goto error; diff --git a/ast.h b/ast.h index f18c73e..26d0c0c 100644 --- a/ast.h +++ b/ast.h @@ -28,8 +28,8 @@ * "main" ast node types for now. */ -typedef union ast_node_u ast_node; -typedef union ast_expression_u ast_expression; +typedef struct ast_node_common ast_node; +typedef struct ast_expression_common ast_expression; typedef struct ast_value_s ast_value; typedef struct ast_function_s ast_function; @@ -75,14 +75,14 @@ enum { TYPE_ast_goto /* 20 */ }; -#define ast_istype(x, t) ( ((ast_node_common*)x)->nodetype == (TYPE_##t) ) -#define ast_ctx(node) (((ast_node_common*)(node))->context) -#define ast_side_effects(node) (((ast_node_common*)(node))->side_effects) +#define ast_istype(x, t) ( ((ast_node*)x)->nodetype == (TYPE_##t) ) +#define ast_ctx(node) (((ast_node*)(node))->context) +#define ast_side_effects(node) (((ast_node*)(node))->side_effects) /* Node interface with common components */ typedef void ast_node_delete(ast_node*); -typedef struct +struct ast_node_common { lex_ctx context; /* I don't feel comfortable using keywords like 'delete' as names... */ @@ -93,14 +93,14 @@ typedef struct */ bool keep; bool side_effects; -} ast_node_common; +}; -#define ast_delete(x) (*( ((ast_node*)(x))->node.destroy ))((ast_node*)(x)) -#define ast_unref(x) do \ -{ \ - if (! (((ast_node*)(x))->node.keep) ) { \ - ast_delete(x); \ - } \ +#define ast_delete(x) (*( ((ast_node*)(x))->destroy ))((ast_node*)(x)) +#define ast_unref(x) do \ +{ \ + if (! (((ast_node*)(x))->keep) ) { \ + ast_delete(x); \ + } \ } while(0) /* Expression interface @@ -122,9 +122,9 @@ typedef bool ast_expression_codegen(ast_expression*, * type `expression`, so the ast_ident's codegen would search for * variables through the environment (or functions, constants...). */ -typedef struct +struct ast_expression_common { - ast_node_common node; + ast_node node; ast_expression_codegen *codegen; int vtype; ast_expression *next; @@ -143,7 +143,7 @@ typedef struct */ ir_value *outl; ir_value *outr; -} ast_expression_common; +}; #define AST_FLAG_VARIADIC (1<<0) #define AST_FLAG_NORETURN (1<<1) #define AST_FLAG_INLINE (1<<2) @@ -172,7 +172,7 @@ typedef union { } basic_value_t; struct ast_value_s { - ast_expression_common expression; + ast_expression expression; const char *name; const char *desc; @@ -239,7 +239,7 @@ typedef enum ast_binary_ref_s { */ struct ast_binary_s { - ast_expression_common expression; + ast_expression expression; int op; ast_expression *left; @@ -262,7 +262,7 @@ bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**); */ struct ast_binstore_s { - ast_expression_common expression; + ast_expression expression; int opstore; int opbin; @@ -286,7 +286,7 @@ bool ast_binstore_codegen(ast_binstore*, ast_function*, bool lvalue, ir_value**) */ struct ast_unary_s { - ast_expression_common expression; + ast_expression expression; int op; ast_expression *operand; @@ -306,7 +306,7 @@ bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**); */ struct ast_return_s { - ast_expression_common expression; + ast_expression expression; ast_expression *operand; }; ast_return* ast_return_new(lex_ctx ctx, @@ -330,7 +330,7 @@ bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**); */ struct ast_entfield_s { - ast_expression_common expression; + ast_expression expression; /* The entity can come from an expression of course. */ ast_expression *entity; /* As can the field, it just must result in a value of TYPE_FIELD */ @@ -349,7 +349,7 @@ bool ast_entfield_codegen(ast_entfield*, ast_function*, bool lvalue, ir_value**) */ struct ast_member_s { - ast_expression_common expression; + ast_expression expression; ast_expression *owner; unsigned int field; const char *name; @@ -373,7 +373,7 @@ bool ast_member_codegen(ast_member*, ast_function*, bool lvalue, ir_value**); */ struct ast_array_index_s { - ast_expression_common expression; + ast_expression expression; ast_expression *array; ast_expression *index; }; @@ -389,7 +389,7 @@ bool ast_array_index_codegen(ast_array_index*, ast_function*, bool lvalue, ir_va */ struct ast_store_s { - ast_expression_common expression; + ast_expression expression; int op; ast_expression *dest; ast_expression *source; @@ -413,7 +413,7 @@ bool ast_store_codegen(ast_store*, ast_function*, bool lvalue, ir_value**); */ struct ast_ifthen_s { - ast_expression_common expression; + ast_expression expression; ast_expression *cond; /* It's all just 'expressions', since an ast_block is one too. */ ast_expression *on_true; @@ -439,7 +439,7 @@ bool ast_ifthen_codegen(ast_ifthen*, ast_function*, bool lvalue, ir_value**); */ struct ast_ternary_s { - ast_expression_common expression; + ast_expression expression; ast_expression *cond; /* It's all just 'expressions', since an ast_block is one too. */ ast_expression *on_true; @@ -475,7 +475,7 @@ continue: // a 'continue' will jump here */ struct ast_loop_s { - ast_expression_common expression; + ast_expression expression; ast_expression *initexpr; ast_expression *precond; ast_expression *postcond; @@ -504,7 +504,7 @@ bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**); */ struct ast_breakcont_s { - ast_expression_common expression; + ast_expression expression; bool is_continue; unsigned int levels; }; @@ -529,7 +529,7 @@ typedef struct { } ast_switch_case; struct ast_switch_s { - ast_expression_common expression; + ast_expression expression; ast_expression *operand; ast_switch_case *cases; @@ -546,7 +546,7 @@ bool ast_switch_codegen(ast_switch*, ast_function*, bool lvalue, ir_value**); */ struct ast_label_s { - ast_expression_common expression; + ast_expression expression; const char *name; ir_block *irblock; ast_goto **gotos; @@ -566,7 +566,7 @@ bool ast_label_codegen(ast_label*, ast_function*, bool lvalue, ir_value**); */ struct ast_goto_s { - ast_expression_common expression; + ast_expression expression; const char *name; ast_label *target; ir_block *irblock_from; @@ -590,7 +590,7 @@ bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**); */ struct ast_call_s { - ast_expression_common expression; + ast_expression expression; ast_expression *func; ast_expression* *params; ast_expression *va_count; @@ -606,7 +606,7 @@ bool ast_call_check_types(ast_call*); */ struct ast_block_s { - ast_expression_common expression; + ast_expression expression; ast_value* *locals; ast_expression* *exprs; @@ -633,7 +633,7 @@ bool GMQCC_WARN ast_block_add_expr(ast_block*, ast_expression*); */ struct ast_function_s { - ast_node_common node; + ast_node node; ast_value *vtype; const char *name; @@ -678,18 +678,4 @@ const char* ast_function_label(ast_function*, const char *prefix); bool ast_function_codegen(ast_function *self, ir_builder *builder); bool ast_generate_accessors(ast_value *asvalue, ir_builder *ir); -/* Expression union - */ -union ast_expression_u -{ - ast_expression_common expression; -}; - -/* Node union - */ -union ast_node_u -{ - ast_node_common node; -}; - #endif diff --git a/parser.c b/parser.c index 4d50bad..9fd94f6 100644 --- a/parser.c +++ b/parser.c @@ -585,7 +585,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) blocks[i] = sy->out[vec_size(sy->out)+i].block; asvalue[i] = (ast_value*)exprs[i]; - if (exprs[i]->expression.vtype == TYPE_NOEXPR && + if (exprs[i]->vtype == TYPE_NOEXPR && !(i != 0 && op->id == opid2('?',':')) && !(i == 1 && op->id == opid1('.'))) { @@ -603,11 +603,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } #define NotSameType(T) \ - (exprs[0]->expression.vtype != exprs[1]->expression.vtype || \ - exprs[0]->expression.vtype != T) + (exprs[0]->vtype != exprs[1]->vtype || \ + exprs[0]->vtype != T) #define CanConstFold1(A) \ (ast_istype((A), ast_value) && ((ast_value*)(A))->hasvalue && (((ast_value*)(A))->cvq == CV_CONST) &&\ - (A)->expression.vtype != TYPE_FUNCTION) + (A)->vtype != TYPE_FUNCTION) #define CanConstFold(A, B) \ (CanConstFold1(A) && CanConstFold1(B)) #define ConstV(i) (asvalue[(i)]->constval.vvec) @@ -620,8 +620,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; case opid1('.'): - if (exprs[0]->expression.vtype == TYPE_VECTOR && - exprs[1]->expression.vtype == TYPE_NOEXPR) + if (exprs[0]->vtype == TYPE_VECTOR && + exprs[1]->vtype == TYPE_NOEXPR) { if (exprs[1] == (ast_expression*)parser->const_vec[0]) out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL); @@ -634,14 +634,14 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } } - else if (exprs[0]->expression.vtype == TYPE_ENTITY) { - if (exprs[1]->expression.vtype != TYPE_FIELD) { + else if (exprs[0]->vtype == TYPE_ENTITY) { + if (exprs[1]->vtype != TYPE_FIELD) { compile_error(ast_ctx(exprs[1]), "type error: right hand of member-operand should be an entity-field"); return false; } out = (ast_expression*)ast_entfield_new(ctx, exprs[0], exprs[1]); } - else if (exprs[0]->expression.vtype == TYPE_VECTOR) { + else if (exprs[0]->vtype == TYPE_VECTOR) { compile_error(ast_ctx(exprs[1]), "vectors cannot be accessed this way"); return false; } @@ -652,15 +652,15 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid1('['): - if (exprs[0]->expression.vtype != TYPE_ARRAY && - !(exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_ARRAY)) + if (exprs[0]->vtype != TYPE_ARRAY && + !(exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_ARRAY)) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "cannot index value of type %s", ty1); return false; } - if (exprs[1]->expression.vtype != TYPE_FLOAT) { + if (exprs[1]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[1]), "index must be of type float, not %s", ty1); return false; @@ -707,7 +707,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = exprs[0]; break; case opid2('-','P'): - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold1(exprs[0])) out = (ast_expression*)parser_const_float(parser, -ConstF(0)); @@ -727,13 +727,13 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot negate type %s", - type_name[exprs[0]->expression.vtype]); + type_name[exprs[0]->vtype]); return false; } break; case opid2('!','P'): - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold1(exprs[0])) out = (ast_expression*)parser_const_float(parser, !ConstF(0)); @@ -769,21 +769,21 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot logically negate type %s", - type_name[exprs[0]->expression.vtype]); + type_name[exprs[0]->vtype]); return false; } break; case opid1('+'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold(exprs[0], exprs[1])) { @@ -800,21 +800,21 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; case opid1('-'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_float(parser, ConstF(0) - ConstF(1)); @@ -829,27 +829,27 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; }; break; case opid1('*'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype && - !(exprs[0]->expression.vtype == TYPE_VECTOR && - exprs[1]->expression.vtype == TYPE_FLOAT) && - !(exprs[1]->expression.vtype == TYPE_VECTOR && - exprs[0]->expression.vtype == TYPE_FLOAT) + if (exprs[0]->vtype != exprs[1]->vtype && + !(exprs[0]->vtype == TYPE_VECTOR && + exprs[1]->vtype == TYPE_FLOAT) && + !(exprs[1]->vtype == TYPE_VECTOR && + exprs[0]->vtype == TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: - if (exprs[1]->expression.vtype == TYPE_VECTOR) + if (exprs[1]->vtype == TYPE_VECTOR) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(1), ConstF(0))); @@ -865,7 +865,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } break; case TYPE_VECTOR: - if (exprs[1]->expression.vtype == TYPE_FLOAT) + if (exprs[1]->vtype == TYPE_FLOAT) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), ConstF(1))); @@ -881,7 +881,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (!vec.y && !vec.z) { /* 'n 0 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 0, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.x != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.x), out); @@ -889,7 +889,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.z) { /* '0 n 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 1, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.y != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.y), out); @@ -897,7 +897,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.y) { /* '0 n 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 2, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.z != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.z), out); @@ -910,7 +910,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (!vec.y && !vec.z) { /* v * 'n 0 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.x != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.x)); @@ -918,7 +918,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.z) { /* v * '0 n 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 1, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.y != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.y)); @@ -926,7 +926,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.y) { /* v * '0 n 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 2, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.z != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.z)); @@ -940,25 +940,25 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; }; break; case opid1('/'): - if (exprs[1]->expression.vtype != TYPE_FLOAT) { + if (exprs[1]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); compile_error(ctx, "invalid types used in expression: cannot divide tyeps %s and %s", ty1, ty2); return false; } - if (exprs[0]->expression.vtype == TYPE_FLOAT) { + if (exprs[0]->vtype == TYPE_FLOAT) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_float(parser, ConstF(0) / ConstF(1)); else out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]); } - else if (exprs[0]->expression.vtype == TYPE_VECTOR) { + else if (exprs[0]->vtype == TYPE_VECTOR) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), 1.0/ConstF(1))); else { @@ -988,8 +988,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid1('%'): if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform modulo operation between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } if (CanConstFold(exprs[0], exprs[1])) { @@ -1017,8 +1017,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid1('&'): if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform bit operations between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } if (CanConstFold(exprs[0], exprs[1])) @@ -1074,7 +1074,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } for (i = 0; i < 2; ++i) { - if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->expression.vtype == TYPE_VECTOR) { + if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->vtype == TYPE_VECTOR) { out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[i]); if (!out) break; out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); @@ -1085,7 +1085,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; } } - else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->expression.vtype == TYPE_STRING) { + else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->vtype == TYPE_STRING) { out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[i]); if (!out) break; out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); @@ -1192,49 +1192,49 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) generated_op += INSTR_LE; if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); break; case opid2('!', '='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { + if (exprs[0]->vtype != exprs[1]->vtype) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid2('=', '='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { + if (exprs[0]->vtype != exprs[1]->vtype) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid1('='): if (ast_istype(exprs[0], ast_entfield)) { ast_expression *field = ((ast_entfield*)exprs[0])->field; if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) && - exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_VECTOR) + exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_VECTOR) { assignop = type_storep_instr[TYPE_VECTOR]; } else - assignop = type_storep_instr[exprs[0]->expression.vtype]; - if (assignop == VINSTR_END || !ast_compare_type(field->expression.next, exprs[1])) + assignop = type_storep_instr[exprs[0]->vtype]; + if (assignop == VINSTR_END || !ast_compare_type(field->next, exprs[1])) { - ast_type_to_string(field->expression.next, ty1, sizeof(ty1)); + ast_type_to_string(field->next, ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) && - field->expression.next->expression.vtype == TYPE_FUNCTION && - exprs[1]->expression.vtype == TYPE_FUNCTION) + field->next->vtype == TYPE_FUNCTION && + exprs[1]->vtype == TYPE_FUNCTION) { (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@ -1246,13 +1246,13 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else { if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) && - exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_VECTOR) + exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_VECTOR) { assignop = type_store_instr[TYPE_VECTOR]; } else { - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; } if (assignop == VINSTR_END) { @@ -1265,8 +1265,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) && - exprs[0]->expression.vtype == TYPE_FUNCTION && - exprs[1]->expression.vtype == TYPE_FUNCTION) + exprs[0]->vtype == TYPE_FUNCTION && + exprs[1]->vtype == TYPE_FUNCTION) { (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@ -1283,7 +1283,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid3('+','+','P'): case opid3('-','-','P'): /* prefix ++ */ - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for prefix increment: %s", ty1); return false; @@ -1308,7 +1308,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid3('S','+','+'): case opid3('S','-','-'): /* prefix ++ */ - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for suffix increment: %s", ty1); return false; @@ -1340,8 +1340,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid2('+','='): case opid2('-','='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@ -1353,10 +1353,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; - switch (exprs[0]->expression.vtype) { + assignop = type_store_instr[exprs[0]->vtype]; + switch (exprs[0]->vtype) { case TYPE_FLOAT: out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('+','=') ? INSTR_ADD_F : INSTR_SUB_F), @@ -1369,16 +1369,16 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; case opid2('*','='): case opid2('/','='): - if (exprs[1]->expression.vtype != TYPE_FLOAT || - !(exprs[0]->expression.vtype == TYPE_FLOAT || - exprs[0]->expression.vtype == TYPE_VECTOR)) + if (exprs[1]->vtype != TYPE_FLOAT || + !(exprs[0]->vtype == TYPE_FLOAT || + exprs[0]->vtype == TYPE_VECTOR)) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@ -1390,10 +1390,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; - switch (exprs[0]->expression.vtype) { + assignop = type_store_instr[exprs[0]->vtype]; + switch (exprs[0]->vtype) { case TYPE_FLOAT: out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('*','=') ? INSTR_MUL_F : INSTR_DIV_F), @@ -1422,8 +1422,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; @@ -1440,9 +1440,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('&','=') ? INSTR_BITAND : INSTR_BITOR), exprs[0], exprs[1]); @@ -1460,9 +1460,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; out = (ast_expression*)ast_binary_new(ctx, INSTR_BITAND, exprs[0], exprs[1]); if (!out) return false; @@ -1475,7 +1475,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid2('~', 'P'): - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for bit not: %s", ty1); return false; @@ -1571,7 +1571,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) if (ast_istype(fun, ast_value)) { funval = (ast_value*)fun; - if ((fun->expression.flags & AST_FLAG_VARIADIC) && + if ((fun->flags & AST_FLAG_VARIADIC) && !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin)) { call->va_count = (ast_expression*)parser_const_float(parser, (double)paramcount); @@ -1581,18 +1581,18 @@ static bool parser_close_call(parser_t *parser, shunt *sy) /* overwrite fid, the function, with a call */ sy->out[fid] = syexp(call->expression.node.context, (ast_expression*)call); - if (fun->expression.vtype != TYPE_FUNCTION) { - parseerror(parser, "not a function (%s)", type_name[fun->expression.vtype]); + if (fun->vtype != TYPE_FUNCTION) { + parseerror(parser, "not a function (%s)", type_name[fun->vtype]); return false; } - if (!fun->expression.next) { + if (!fun->next) { parseerror(parser, "could not determine function return type"); return false; } else { ast_value *fval = (ast_istype(fun, ast_value) ? ((ast_value*)fun) : NULL); - if (fun->expression.flags & AST_FLAG_DEPRECATED) { + if (fun->flags & AST_FLAG_DEPRECATED) { if (!fval) { return !parsewarning(parser, WARN_DEPRECATED, "call to function (which is marked deprecated)\n", @@ -1612,22 +1612,22 @@ static bool parser_close_call(parser_t *parser, shunt *sy) ast_ctx(fun).line); } - if (vec_size(fun->expression.params) != paramcount && - !((fun->expression.flags & AST_FLAG_VARIADIC) && - vec_size(fun->expression.params) < paramcount)) + if (vec_size(fun->params) != paramcount && + !((fun->flags & AST_FLAG_VARIADIC) && + vec_size(fun->params) < paramcount)) { - const char *fewmany = (vec_size(fun->expression.params) > paramcount) ? "few" : "many"; + const char *fewmany = (vec_size(fun->params) > paramcount) ? "few" : "many"; if (fval) return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT, "too %s parameters for call to %s: expected %i, got %i\n" " -> `%s` has been declared here: %s:%i", - fewmany, fval->name, (int)vec_size(fun->expression.params), (int)paramcount, + fewmany, fval->name, (int)vec_size(fun->params), (int)paramcount, fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line); else return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT, "too %s parameters for function call: expected %i, got %i\n" " -> it has been declared here: %s:%i", - fewmany, (int)vec_size(fun->expression.params), (int)paramcount, + fewmany, (int)vec_size(fun->params), (int)paramcount, ast_ctx(fun).file, (int)ast_ctx(fun).line); } } @@ -1881,7 +1881,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) /* When adding more intrinsics, fix the above condition */ prev = NULL; } - if (prev && prev->expression.vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1]) + if (prev && prev->vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1]) { var = (ast_expression*)parser->const_vec[ctoken[0]-'x']; } else { @@ -2363,13 +2363,13 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond, ast_unary *unary; ast_expression *prev; - if (cond->expression.vtype == TYPE_VOID || cond->expression.vtype >= TYPE_VARIANT) { + if (cond->vtype == TYPE_VOID || cond->vtype >= TYPE_VARIANT) { char ty[1024]; ast_type_to_string(cond, ty, sizeof(ty)); compile_error(ast_ctx(cond), "invalid type for if() condition: %s", ty); } - if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->expression.vtype == TYPE_STRING) + if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->vtype == TYPE_STRING) { prev = cond; cond = (ast_expression*)ast_unary_new(ast_ctx(cond), INSTR_NOT_S, cond); @@ -2380,7 +2380,7 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond, } ifnot = !ifnot; } - else if (OPTS_FLAG(CORRECT_LOGIC) && cond->expression.vtype == TYPE_VECTOR) + else if (OPTS_FLAG(CORRECT_LOGIC) && cond->vtype == TYPE_VECTOR) { /* vector types need to be cast to true booleans */ ast_binary *bin = (ast_binary*)cond; @@ -2911,8 +2911,8 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou if (!exp) return false; - if (exp->expression.vtype != TYPE_NIL && - exp->expression.vtype != expected->expression.next->expression.vtype) + if (exp->vtype != TYPE_NIL && + exp->vtype != ((ast_expression*)expected)->next->vtype) { parseerror(parser, "return with invalid expression"); } @@ -2925,7 +2925,7 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou } else { if (!parser_next(parser)) parseerror(parser, "parse error"); - if (expected->expression.next->expression.vtype != TYPE_VOID) { + if (expected->expression.next->vtype != TYPE_VOID) { (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); } ret = ast_return_new(ctx, NULL); @@ -4067,9 +4067,9 @@ static bool parse_function_body(parser_t *parser, ast_value *var) /* qc allows the use of not-yet-declared functions here * - this automatically creates a prototype */ ast_value *thinkfunc; - ast_expression *functype = fld_think->expression.next; + ast_expression *functype = fld_think->next; - thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->expression.vtype); + thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->vtype); if (!thinkfunc) { /* || !ast_type_adopt(thinkfunc, functype)*/ ast_unref(framenum); parseerror(parser, "failed to create implicit prototype for `%s`", parser_tokval(parser)); @@ -4224,7 +4224,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) if (param->expression.vtype != TYPE_VECTOR && (param->expression.vtype != TYPE_FIELD || - param->expression.next->expression.vtype != TYPE_VECTOR)) + param->expression.next->vtype != TYPE_VECTOR)) { continue; } @@ -4354,7 +4354,7 @@ static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast ast_store *st; int assignop = type_store_instr[value->expression.vtype]; - if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR) + if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STORE_V; subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); @@ -4420,7 +4420,7 @@ static ast_expression *array_field_setter_node( ast_store *st; int assignop = type_storep_instr[value->expression.vtype]; - if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR) + if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STOREP_V; subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); @@ -5271,7 +5271,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield { /* deal with other globals */ old = parser_find_global(parser, var->name); - if (old && var->expression.vtype == TYPE_FUNCTION && old->expression.vtype == TYPE_FUNCTION) + if (old && var->expression.vtype == TYPE_FUNCTION && old->vtype == TYPE_FUNCTION) { /* This is a function which had a prototype */ if (!ast_istype(old, ast_value)) { @@ -5379,7 +5379,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield if (var->expression.vtype == TYPE_VECTOR) isvector = true; else if (var->expression.vtype == TYPE_FIELD && - var->expression.next->expression.vtype == TYPE_VECTOR) + var->expression.next->vtype == TYPE_VECTOR) isvector = true; if (isvector) { @@ -5418,7 +5418,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield return false; } - if (var->expression.vtype != find->expression.vtype) { + if (var->expression.vtype != find->vtype) { char ty1[1024]; char ty2[1024]; @@ -5567,7 +5567,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } else if (!localblock && !nofields && var->expression.vtype == TYPE_FIELD && - var->expression.next->expression.vtype == TYPE_ARRAY) + var->expression.next->vtype == TYPE_ARRAY) { char name[1024]; ast_expression *telem; @@ -5984,7 +5984,7 @@ static void generate_checksum(parser_t *parser) if (!ast_istype(parser->fields[i], ast_value)) continue; value = (ast_value*)(parser->fields[i]); - switch (value->expression.next->expression.vtype) { + switch (value->expression.next->vtype) { case TYPE_FLOAT: crc = progdefs_crc_both(crc, "\tfloat\t"); break; case TYPE_VECTOR: crc = progdefs_crc_both(crc, "\tvec3_t\t"); break; case TYPE_STRING: crc = progdefs_crc_both(crc, "\tstring_t\t"); break; @@ -6235,11 +6235,11 @@ bool parser_finish(parser_t *parser, const char *output) ast_expression *subtype; field->hasvalue = true; subtype = field->expression.next; - ifld = ir_builder_create_field(ir, field->name, subtype->expression.vtype); - if (subtype->expression.vtype == TYPE_FIELD) - ifld->fieldtype = subtype->expression.next->expression.vtype; - else if (subtype->expression.vtype == TYPE_FUNCTION) - ifld->outtype = subtype->expression.next->expression.vtype; + ifld = ir_builder_create_field(ir, field->name, subtype->vtype); + if (subtype->vtype == TYPE_FIELD) + ifld->fieldtype = subtype->next->vtype; + else if (subtype->vtype == TYPE_FUNCTION) + ifld->outtype = subtype->next->vtype; (void)!ir_value_set_field(field->ir_v, ifld); } } @@ -6327,7 +6327,7 @@ bool parser_finish(parser_t *parser, const char *output) } for (i = 0; i < vec_size(parser->fields); ++i) { ast_value *asvalue; - asvalue = (ast_value*)(parser->fields[i]->expression.next); + asvalue = (ast_value*)(parser->fields[i]->next); if (!ast_istype((ast_expression*)asvalue, ast_value)) continue; From f281de7a3c742dbff01a1f960e41ba78d49012f6 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 29 May 2013 02:16:50 +0000 Subject: [PATCH 18/63] Cleanups and fixes --- Makefile | 1 - code.c | 49 ++++++++++++++++---------- exec.c | 102 +++++++++++++++++++++---------------------------------- gmqcc.h | 2 +- main.c | 1 + pak.c | 1 - 6 files changed, 72 insertions(+), 84 deletions(-) diff --git a/Makefile b/Makefile index f713417..01a5dac 100644 --- a/Makefile +++ b/Makefile @@ -163,7 +163,6 @@ SPLINTFLAGS = \ -realcompare \ -observertrans \ -shiftnegative \ - -freshtrans \ -abstract \ -statictrans \ -castfcnptr diff --git a/code.c b/code.c index 80154d0..35f758a 100644 --- a/code.c +++ b/code.c @@ -23,10 +23,25 @@ */ #include "gmqcc.h" -/* This is outrageous! */ -#define QCINT_ENTRY void* -#define QCINT_TO_HASH_ENTRY(q) ((void*)(uintptr_t)(q)) -#define HASH_ENTRY_TO_QCINT(h) ((qcint)(uintptr_t)(h)) +/* + * We could use the old method of casting to uintptr_t then to void* + * or qcint; however, it's incredibly unsafe for two reasons. + * 1) The compilers aliasing optimization can legally make it unstable + * (it's undefined behaviour). + * + * 2) The cast itself depends on fresh storage (newly allocated in which + * ever function is using the cast macros), the contents of which are + * transferred in a way that the obligation to release storage is not + * propagated. + */ +typedef union { + void *enter; + qcint leave; +} code_hash_entry_t; + +/* Some sanity macros */ +#define CODE_HASH_ENTER(ENTRY) ((ENTRY).enter) +#define CODE_HASH_LEAVE(ENTRY) ((ENTRY).leave) void code_push_statement(code_t *code, prog_section_statement *stmt, int linenum) { @@ -72,11 +87,9 @@ 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 off; - size_t hash; - QCINT_ENTRY existing; +uint32_t code_genstring(code_t *code, const char *str) { + size_t hash; + code_hash_entry_t existing; if (!str) return 0; @@ -90,21 +103,21 @@ uint32_t code_genstring(code_t *code, const char *str) } if (OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS)) { - hash = ((unsigned char*)str)[strlen(str)-1]; - existing = code_util_str_htgeth(code->string_cache, str, hash); + hash = ((unsigned char*)str)[strlen(str)-1]; + CODE_HASH_ENTER(existing) = code_util_str_htgeth(code->string_cache, str, hash); } else { - hash = util_hthash(code->string_cache, str); - existing = util_htgeth(code->string_cache, str, hash); + hash = util_hthash(code->string_cache, str); + CODE_HASH_ENTER(existing) = util_htgeth(code->string_cache, str, hash); } - if (existing) - return HASH_ENTRY_TO_QCINT(existing); + if (CODE_HASH_ENTER(existing)) + return CODE_HASH_LEAVE(existing); - off = vec_size(code->chars); + CODE_HASH_LEAVE(existing) = vec_size(code->chars); vec_upload(code->chars, str, strlen(str)+1); - util_htseth(code->string_cache, str, hash, QCINT_TO_HASH_ENTRY(off)); - return off; + util_htseth(code->string_cache, str, hash, CODE_HASH_ENTER(existing)); + return CODE_HASH_LEAVE(existing); } qcint code_alloc_field (code_t *code, size_t qcsize) diff --git a/exec.c b/exec.c index 9bb3539..49cff44 100644 --- a/exec.c +++ b/exec.c @@ -167,16 +167,15 @@ void prog_delete(qc_program *prog) * VM code */ -char* prog_getstring(qc_program *prog, qcint str) -{ +const char* prog_getstring(qc_program *prog, qcint str) { /* cast for return required for C++ */ if (str < 0 || str >= (qcint)vec_size(prog->strings)) - return (char*)"<<>>"; + return "<<>>"; + return prog->strings + str; } -prog_section_def* prog_entfield(qc_program *prog, qcint off) -{ +prog_section_def* prog_entfield(qc_program *prog, qcint off) { size_t i; for (i = 0; i < vec_size(prog->fields); ++i) { if (prog->fields[i].offset == off) @@ -195,8 +194,7 @@ prog_section_def* prog_getdef(qc_program *prog, qcint off) return NULL; } -qcany* prog_getedict(qc_program *prog, qcint e) -{ +qcany* prog_getedict(qc_program *prog, qcint e) { if (e >= (qcint)vec_size(prog->entitypool)) { prog->vmerror++; fprintf(stderr, "Accessing out of bounds edict %i\n", (int)e); @@ -205,8 +203,7 @@ qcany* prog_getedict(qc_program *prog, qcint e) return (qcany*)(prog->entitydata + (prog->entityfields * e)); } -qcint prog_spawn_entity(qc_program *prog) -{ +qcint prog_spawn_entity(qc_program *prog) { char *data; qcint e; for (e = 0; e < (qcint)vec_size(prog->entitypool); ++e) { @@ -223,8 +220,7 @@ qcint prog_spawn_entity(qc_program *prog) return e; } -void prog_free_entity(qc_program *prog, qcint e) -{ +void prog_free_entity(qc_program *prog, qcint e) { if (!e) { prog->vmerror++; fprintf(stderr, "Trying to free world entity\n"); @@ -243,8 +239,7 @@ void prog_free_entity(qc_program *prog, qcint e) prog->entitypool[e] = false; } -qcint prog_tempstring(qc_program *prog, const char *str) -{ +qcint prog_tempstring(qc_program *prog, const char *str) { size_t len = strlen(str); size_t at = prog->tempstring_at; @@ -266,8 +261,7 @@ qcint prog_tempstring(qc_program *prog, const char *str) return at; } -static size_t print_escaped_string(const char *str, size_t maxlen) -{ +static size_t print_escaped_string(const char *str, size_t maxlen) { size_t len = 2; putchar('"'); --maxlen; /* because we're lazy and have escape sequences */ @@ -300,8 +294,7 @@ static size_t print_escaped_string(const char *str, size_t maxlen) return len; } -static void trace_print_global(qc_program *prog, unsigned int glob, int vtype) -{ +static void trace_print_global(qc_program *prog, unsigned int glob, int vtype) { static char spaces[28+1] = " "; prog_section_def *def; qcany *value; @@ -359,8 +352,7 @@ done: } } -static void prog_print_statement(qc_program *prog, prog_section_statement *st) -{ +static void prog_print_statement(qc_program *prog, prog_section_statement *st) { if (st->opcode >= (sizeof(asm_instr)/sizeof(asm_instr[0]))) { printf("\n", st->opcode); return; @@ -457,8 +449,7 @@ static void prog_print_statement(qc_program *prog, prog_section_statement *st) } } -static qcint prog_enterfunction(qc_program *prog, prog_section_function *func) -{ +static qcint prog_enterfunction(qc_program *prog, prog_section_function *func) { qc_exec_stack st; size_t parampos; int32_t p; @@ -507,8 +498,7 @@ static qcint prog_enterfunction(qc_program *prog, prog_section_function *func) return func->entry; } -static qcint prog_leavefunction(qc_program *prog) -{ +static qcint prog_leavefunction(qc_program *prog) { prog_section_function *prev = NULL; size_t oldsp; @@ -540,8 +530,7 @@ static qcint prog_leavefunction(qc_program *prog) return st.stmt - 1; /* offset the ++st */ } -bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long maxjumps) -{ +bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long maxjumps) { long jumpcount = 0; size_t oldxflags = prog->xflags; prog_section_statement *st; @@ -640,8 +629,7 @@ static qcvm_parameter *main_params = NULL; #define GetArg(num) GetGlobal(OFS_PARM0 + 3*(num)) #define Return(any) *(GetGlobal(OFS_RETURN)) = (any) -static int qc_print(qc_program *prog) -{ +static int qc_print(qc_program *prog) { size_t i; const char *laststr = NULL; for (i = 0; i < (size_t)prog->argc; ++i) { @@ -657,16 +645,14 @@ static int qc_print(qc_program *prog) return 0; } -static int qc_error(qc_program *prog) -{ +static int qc_error(qc_program *prog) { fprintf(stderr, "*** VM raised an error:\n"); qc_print(prog); prog->vmerror++; return -1; } -static int qc_ftos(qc_program *prog) -{ +static int qc_ftos(qc_program *prog) { char buffer[512]; qcany *num; qcany str; @@ -678,8 +664,7 @@ static int qc_ftos(qc_program *prog) return 0; } -static int qc_stof(qc_program *prog) -{ +static int qc_stof(qc_program *prog) { qcany *str; qcany num; CheckArgs(1); @@ -689,8 +674,7 @@ static int qc_stof(qc_program *prog) return 0; } -static int qc_vtos(qc_program *prog) -{ +static int qc_vtos(qc_program *prog) { char buffer[512]; qcany *num; qcany str; @@ -702,8 +686,7 @@ static int qc_vtos(qc_program *prog) return 0; } -static int qc_etos(qc_program *prog) -{ +static int qc_etos(qc_program *prog) { char buffer[512]; qcany *num; qcany str; @@ -715,8 +698,7 @@ static int qc_etos(qc_program *prog) return 0; } -static int qc_spawn(qc_program *prog) -{ +static int qc_spawn(qc_program *prog) { qcany ent; CheckArgs(0); ent.edict = prog_spawn_entity(prog); @@ -724,8 +706,7 @@ static int qc_spawn(qc_program *prog) return (ent.edict ? 0 : -1); } -static int qc_kill(qc_program *prog) -{ +static int qc_kill(qc_program *prog) { qcany *ent; CheckArgs(1); ent = GetArg(0); @@ -733,8 +714,7 @@ static int qc_kill(qc_program *prog) return 0; } -static int qc_sqrt(qc_program *prog) -{ +static int qc_sqrt(qc_program *prog) { qcany *num, out; CheckArgs(1); num = GetArg(0); @@ -743,8 +723,7 @@ static int qc_sqrt(qc_program *prog) return 0; } -static int qc_vlen(qc_program *prog) -{ +static int qc_vlen(qc_program *prog) { qcany *vec, len; CheckArgs(1); vec = GetArg(0); @@ -755,8 +734,7 @@ static int qc_vlen(qc_program *prog) return 0; } -static int qc_normalize(qc_program *prog) -{ +static int qc_normalize(qc_program *prog) { double len; qcany *vec; qcany out; @@ -776,13 +754,14 @@ static int qc_normalize(qc_program *prog) return 0; } -static int qc_strcat(qc_program *prog) -{ +static int qc_strcat(qc_program *prog) { char *buffer; size_t len1, len2; - char *cstr1, *cstr2; qcany *str1, *str2; qcany out; + + const char *cstr1; + const char *cstr2; CheckArgs(2); str1 = GetArg(0); @@ -800,12 +779,13 @@ static int qc_strcat(qc_program *prog) return 0; } -static int qc_strcmp(qc_program *prog) -{ - char *cstr1, *cstr2; +static int qc_strcmp(qc_program *prog) { qcany *str1, *str2; qcany out; + const char *cstr1; + const char *cstr2; + if (prog->argc != 2 && prog->argc != 3) { fprintf(stderr, "ERROR: invalid number of arguments for strcmp/strncmp: %i, expected 2 or 3\n", prog->argc); @@ -824,8 +804,7 @@ static int qc_strcmp(qc_program *prog) return 0; } -static int qc_floor(qc_program *prog) -{ +static int qc_floor(qc_program *prog) { qcany *num, out; CheckArgs(1); num = GetArg(0); @@ -865,8 +844,7 @@ static void version() { ); } -static void usage() -{ +static void usage() { printf("usage: %s [options] [parameters] file\n", arg0); printf("options:\n"); printf(" -h, --help print this message\n" @@ -886,8 +864,7 @@ static void usage() " -string pass a string parameter to main() \n"); } -static void prog_main_setparams(qc_program *prog) -{ +static void prog_main_setparams(qc_program *prog) { size_t i; qcany *arg; @@ -950,8 +927,8 @@ void escapestring(char* dest, const char* src) { } void prog_disasm_function(qc_program *prog, size_t id); -int main(int argc, char **argv) -{ + +int main(int argc, char **argv) { size_t i; qcint fnmain = -1; qc_program *prog; @@ -1266,8 +1243,7 @@ int main(int argc, char **argv) return 0; } -void prog_disasm_function(qc_program *prog, size_t id) -{ +void prog_disasm_function(qc_program *prog, size_t id) { prog_section_function *fdef = prog->functions + id; prog_section_statement *st; diff --git a/gmqcc.h b/gmqcc.h index fc93d92..2e019a5 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -993,7 +993,7 @@ void prog_delete(qc_program *prog); bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long maxjumps); -char* prog_getstring (qc_program *prog, qcint str); +const char* prog_getstring (qc_program *prog, qcint str); prog_section_def* prog_entfield (qc_program *prog, qcint off); prog_section_def* prog_getdef (qc_program *prog, qcint off); qcany* prog_getedict (qc_program *prog, qcint e); diff --git a/main.c b/main.c index bbc685a..840a6a7 100644 --- a/main.c +++ b/main.c @@ -41,6 +41,7 @@ static ppitem *ppems = NULL; #define TYPE_ASM 1 #define TYPE_SRC 2 + static const char *app_name; static void version() { diff --git a/pak.c b/pak.c index 653a463..0f90d67 100644 --- a/pak.c +++ b/pak.c @@ -575,7 +575,6 @@ int main(int argc, char **argv) { pak_close(pak); vec_free(files); - util_meminfo(); return EXIT_SUCCESS; } From e02ebfe4866c5dadc1d411b38673e360405de983 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 29 May 2013 02:24:12 +0000 Subject: [PATCH 19/63] Result of shift operation on signed integers is bad. --- Makefile | 1 - gmqcc.h | 2 +- parser.c | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 01a5dac..d419daa 100644 --- a/Makefile +++ b/Makefile @@ -162,7 +162,6 @@ SPLINTFLAGS = \ -mayaliasunique \ -realcompare \ -observertrans \ - -shiftnegative \ -abstract \ -statictrans \ -castfcnptr diff --git a/gmqcc.h b/gmqcc.h index 2e019a5..3b221e9 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -1163,7 +1163,7 @@ typedef struct { extern opts_cmd_t opts; -#define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1<< ((i)%32)))) +#define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1<< (unsigned)((i)%32)))) #define OPTS_FLAG(i) OPTS_GENERIC(opts.flags, (i)) #define OPTS_WARN(i) OPTS_GENERIC(opts.warn, (i)) #define OPTS_WERROR(i) OPTS_GENERIC(opts.werror, (i)) diff --git a/parser.c b/parser.c index 4d50bad..da9d33a 100644 --- a/parser.c +++ b/parser.c @@ -1038,9 +1038,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid2('>','>'): if (CanConstFold(exprs[0], exprs[1]) && ! NotSameType(TYPE_FLOAT)) { if (op->id == opid2('<','<')) - out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) << (int)(ConstF(1)))); + out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) << (unsigned int)(ConstF(1)))); else - out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) >> (int)(ConstF(1)))); + out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) >> (unsigned int)(ConstF(1)))); break; } case opid3('<','<','='): From df8b486c98750ee719ddb88a6bb9b90f1e7557d8 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 29 May 2013 02:37:45 +0000 Subject: [PATCH 20/63] Prevent negitive numbers from being used as the left operand of shift operator. --- Makefile | 1 - lexer.h | 11 ++++++++--- pak.c | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index d419daa..2ab06dd 100644 --- a/Makefile +++ b/Makefile @@ -148,7 +148,6 @@ SPLINTFLAGS = \ -temptrans \ -usereleased \ -warnposix \ - -shiftimplementation \ +charindex \ -kepttrans \ -unqualifiedtrans \ diff --git a/lexer.h b/lexer.h index 24ac39a..2573fb2 100644 --- a/lexer.h +++ b/lexer.h @@ -163,9 +163,14 @@ typedef struct { unsigned int flags; } oper_info; -#define opid1(a) (a) -#define opid2(a,b) ((a<<8)|b) -#define opid3(a,b,c) ((a<<16)|(b<<8)|c) +/* + * Explicit uint8_t casts since the left operand of shift operator cannot + * be negative, even though it won't happen, this supresses the future + * possibility. + */ +#define opid1(a) ((uint8_t)a) +#define opid2(a,b) (((uint8_t)a<<8) |(uint8_t)b) +#define opid3(a,b,c) (((uint8_t)a<<16)|((uint8_t)b<<8)|(uint8_t)c) static const oper_info c_operators[] = { { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */ diff --git a/pak.c b/pak.c index 0f90d67..048469b 100644 --- a/pak.c +++ b/pak.c @@ -26,7 +26,7 @@ * The PAK format uses a FOURCC concept for storing the magic ident within * the header as a uint32_t. */ -#define PAK_FOURCC ((uint32_t)(('P' | ('A' << 8) | ('C' << 16) | ('K' << 24)))) +#define PAK_FOURCC ((uint32_t)(((uint8_t)'P'|((uint8_t)'A'<<8)|((uint8_t)'C'<<16)|((uint8_t)'K'<<24)))) typedef struct { uint32_t magic; /* "PACK" */ From f892b323351eb110dc97b8cf4e15d03dddc6fb78 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 29 May 2013 03:29:04 +0000 Subject: [PATCH 21/63] Major export cleanup. Anything that was exported but wasn't used outside where it was implemented has been turned into static, and their exports have been removed. This actually makes the compiler compile slightly faster. --- Makefile | 1 - ast.c | 46 +++++++++++++++++++++-- ast.h | 54 +++------------------------ conout.c | 2 +- ftepp.c | 18 ++++----- intrin.h | 16 ++++---- ir.c | 83 ++++++++++++++++++++++++++--------------- ir.h | 112 +++++++++---------------------------------------------- lexer.c | 4 +- lexer.h | 2 +- pak.c | 12 +++--- parser.c | 4 +- test.c | 32 ++++++++-------- util.c | 2 +- 14 files changed, 163 insertions(+), 225 deletions(-) diff --git a/Makefile b/Makefile index 2ab06dd..fea3356 100644 --- a/Makefile +++ b/Makefile @@ -135,7 +135,6 @@ SPLINTFLAGS = \ -onlytrans \ -predboolint \ -boolops \ - -exportlocal \ -incondefs \ -macroredef \ -retvalint \ diff --git a/ast.c b/ast.c index 1e2836f..96f768f 100644 --- a/ast.c +++ b/ast.c @@ -36,6 +36,43 @@ ast_node_init((ast_node*)self, ctx, TYPE_##T); \ ( (ast_node*)self )->node.destroy = (ast_node_delete*)destroyfn +/* + * forward declarations, these need not be in ast.h for obvious + * static reasons. + */ +static bool ast_member_codegen(ast_member*, ast_function*, bool lvalue, ir_value**); +static void ast_array_index_delete(ast_array_index*); +static bool ast_array_index_codegen(ast_array_index*, ast_function*, bool lvalue, ir_value**); +static void ast_store_delete(ast_store*); +static bool ast_store_codegen(ast_store*, ast_function*, bool lvalue, ir_value**); +static void ast_ifthen_delete(ast_ifthen*); +static bool ast_ifthen_codegen(ast_ifthen*, ast_function*, bool lvalue, ir_value**); +static void ast_ternary_delete(ast_ternary*); +static bool ast_ternary_codegen(ast_ternary*, ast_function*, bool lvalue, ir_value**); +static void ast_loop_delete(ast_loop*); +static bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**); +static void ast_breakcont_delete(ast_breakcont*); +static bool ast_breakcont_codegen(ast_breakcont*, ast_function*, bool lvalue, ir_value**); +static void ast_switch_delete(ast_switch*); +static bool ast_switch_codegen(ast_switch*, ast_function*, bool lvalue, ir_value**); +static void ast_label_delete(ast_label*); +static void ast_label_register_goto(ast_label*, ast_goto*); +static bool ast_label_codegen(ast_label*, ast_function*, bool lvalue, ir_value**); +static bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**); +static void ast_goto_delete(ast_goto*); +static void ast_call_delete(ast_call*); +static bool ast_call_codegen(ast_call*, ast_function*, bool lvalue, ir_value**); +static bool ast_block_codegen(ast_block*, ast_function*, bool lvalue, ir_value**); +static void ast_unary_delete(ast_unary*); +static bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**); +static void ast_entfield_delete(ast_entfield*); +static bool ast_entfield_codegen(ast_entfield*, ast_function*, bool lvalue, ir_value**); +static void ast_return_delete(ast_return*); +static bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**); +static void ast_binstore_delete(ast_binstore*); +static bool ast_binstore_codegen(ast_binstore*, ast_function*, bool lvalue, ir_value**); +static void ast_binary_delete(ast_binary*); +static bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**); /* It must not be possible to get here. */ static GMQCC_NORETURN void _ast_node_destroy(ast_node *self) @@ -303,6 +340,7 @@ void ast_type_to_string(ast_expression *e, char *buf, size_t bufsize) buf[pos] = 0; } +static bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out); ast_value* ast_value_new(lex_ctx ctx, const char *name, int t) { ast_instantiate(ast_value, ctx, ast_value_delete); @@ -845,7 +883,7 @@ void ast_label_delete(ast_label *self) mem_d(self); } -void ast_label_register_goto(ast_label *self, ast_goto *g) +static void ast_label_register_goto(ast_label *self, ast_goto *g) { vec_push(self->gotos, g); } @@ -1098,7 +1136,7 @@ void ast_function_delete(ast_function *self) mem_d(self); } -const char* ast_function_label(ast_function *self, const char *prefix) +static const char* ast_function_label(ast_function *self, const char *prefix) { size_t id; size_t len; @@ -1132,7 +1170,7 @@ const char* ast_function_label(ast_function *self, const char *prefix) * But I can't imagine a pituation where the output is truly unnecessary. */ -void _ast_codegen_output_type(ast_expression_common *self, ir_value *out) +static void _ast_codegen_output_type(ast_expression_common *self, ir_value *out) { if (out->vtype == TYPE_FIELD) out->fieldtype = self->next->expression.vtype; @@ -1381,7 +1419,7 @@ error: /* clean up */ return false; } -bool ast_local_codegen(ast_value *self, ir_function *func, bool param) +static bool ast_local_codegen(ast_value *self, ir_function *func, bool param) { ir_value *v = NULL; diff --git a/ast.h b/ast.h index f18c73e..f130fb4 100644 --- a/ast.h +++ b/ast.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2012, 2013 * Wolfgang Bumiller + * 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 @@ -214,8 +215,11 @@ void ast_value_delete(ast_value*); bool ast_value_set_name(ast_value*, const char *name); +/* bool ast_value_codegen(ast_value*, ast_function*, bool lvalue, ir_value**); bool ast_local_codegen(ast_value *self, ir_function *func, bool isparam); +*/ + bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield); void ast_value_params_add(ast_value*, ast_value*); @@ -251,9 +255,6 @@ ast_binary* ast_binary_new(lex_ctx ctx, int op, ast_expression *left, ast_expression *right); -void ast_binary_delete(ast_binary*); - -bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**); /* Binstore * @@ -276,9 +277,6 @@ ast_binstore* ast_binstore_new(lex_ctx ctx, int op, ast_expression *left, ast_expression *right); -void ast_binstore_delete(ast_binstore*); - -bool ast_binstore_codegen(ast_binstore*, ast_function*, bool lvalue, ir_value**); /* Unary * @@ -294,9 +292,6 @@ struct ast_unary_s ast_unary* ast_unary_new(lex_ctx ctx, int op, ast_expression *expr); -void ast_unary_delete(ast_unary*); - -bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**); /* Return * @@ -311,9 +306,6 @@ struct ast_return_s }; ast_return* ast_return_new(lex_ctx ctx, ast_expression *expr); -void ast_return_delete(ast_return*); - -bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**); /* Entity-field * @@ -338,9 +330,6 @@ struct ast_entfield_s }; ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field); ast_entfield* ast_entfield_new_force(lex_ctx ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype); -void ast_entfield_delete(ast_entfield*); - -bool ast_entfield_codegen(ast_entfield*, ast_function*, bool lvalue, ir_value**); /* Member access: * @@ -359,7 +348,6 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel void ast_member_delete(ast_member*); bool ast_member_set_name(ast_member*, const char *name); -bool ast_member_codegen(ast_member*, ast_function*, bool lvalue, ir_value**); /* Array index access: * @@ -378,9 +366,6 @@ struct ast_array_index_s ast_expression *index; }; ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_expression *index); -void ast_array_index_delete(ast_array_index*); - -bool ast_array_index_codegen(ast_array_index*, ast_function*, bool lvalue, ir_value**); /* Store * @@ -396,9 +381,6 @@ struct ast_store_s }; ast_store* ast_store_new(lex_ctx ctx, int op, ast_expression *d, ast_expression *s); -void ast_store_delete(ast_store*); - -bool ast_store_codegen(ast_store*, ast_function*, bool lvalue, ir_value**); /* If * @@ -420,9 +402,6 @@ struct ast_ifthen_s ast_expression *on_false; }; ast_ifthen* ast_ifthen_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse); -void ast_ifthen_delete(ast_ifthen*); - -bool ast_ifthen_codegen(ast_ifthen*, ast_function*, bool lvalue, ir_value**); /* Ternary expressions... * @@ -446,9 +425,6 @@ struct ast_ternary_s ast_expression *on_false; }; ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse); -void ast_ternary_delete(ast_ternary*); - -bool ast_ternary_codegen(ast_ternary*, ast_function*, bool lvalue, ir_value**); /* A general loop node * @@ -496,9 +472,6 @@ ast_loop* ast_loop_new(lex_ctx ctx, ast_expression *postcond, bool post_not, ast_expression *increment, ast_expression *body); -void ast_loop_delete(ast_loop*); - -bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**); /* Break/Continue */ @@ -509,9 +482,6 @@ struct ast_breakcont_s unsigned int levels; }; ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont, unsigned int levels); -void ast_breakcont_delete(ast_breakcont*); - -bool ast_breakcont_codegen(ast_breakcont*, ast_function*, bool lvalue, ir_value**); /* Switch Statements * @@ -536,9 +506,6 @@ struct ast_switch_s }; ast_switch* ast_switch_new(lex_ctx ctx, ast_expression *op); -void ast_switch_delete(ast_switch*); - -bool ast_switch_codegen(ast_switch*, ast_function*, bool lvalue, ir_value**); /* Label nodes * @@ -555,10 +522,6 @@ struct ast_label_s }; ast_label* ast_label_new(lex_ctx ctx, const char *name, bool undefined); -void ast_label_delete(ast_label*); -void ast_label_register_goto(ast_label*, ast_goto*); - -bool ast_label_codegen(ast_label*, ast_function*, bool lvalue, ir_value**); /* GOTO nodes * @@ -573,11 +536,8 @@ struct ast_goto_s }; ast_goto* ast_goto_new(lex_ctx ctx, const char *name); -void ast_goto_delete(ast_goto*); void ast_goto_set_label(ast_goto*, ast_label*); -bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**); - /* CALL node * * Contains an ast_expression as target, rather than an ast_function/value. @@ -597,8 +557,6 @@ struct ast_call_s }; ast_call* ast_call_new(lex_ctx ctx, ast_expression *funcexpr); -void ast_call_delete(ast_call*); -bool ast_call_codegen(ast_call*, ast_function*, bool lvalue, ir_value**); bool ast_call_check_types(ast_call*); /* Blocks @@ -615,8 +573,6 @@ struct ast_block_s ast_block* ast_block_new(lex_ctx ctx); void ast_block_delete(ast_block*); void ast_block_set_type(ast_block*, ast_expression *from); - -bool ast_block_codegen(ast_block*, ast_function*, bool lvalue, ir_value**); void ast_block_collect(ast_block*, ast_expression*); bool GMQCC_WARN ast_block_add_expr(ast_block*, ast_expression*); @@ -673,7 +629,7 @@ void ast_function_delete(ast_function*); /* For "optimized" builds this can just keep returning "foo"... * or whatever... */ -const char* ast_function_label(ast_function*, const char *prefix); +/*const char* ast_function_label(ast_function*, const char *prefix);*/ bool ast_function_codegen(ast_function *self, ir_builder *builder); bool ast_generate_accessors(ast_value *asvalue, ir_builder *ir); diff --git a/conout.c b/conout.c index dd4dca3..2f72076 100644 --- a/conout.c +++ b/conout.c @@ -333,7 +333,7 @@ int con_out(const char *fmt, ...) { * for reporting of file:line based on lexer context, These are used * heavily in the parser/ir/ast. */ -void con_vprintmsg_c(int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap, const char *condname) { +static void con_vprintmsg_c(int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap, const char *condname) { /* color selection table */ static int sel[] = { CON_WHITE, diff --git a/ftepp.c b/ftepp.c index 9fc0025..f8d41d9 100644 --- a/ftepp.c +++ b/ftepp.c @@ -81,7 +81,7 @@ static uint32_t ftepp_predef_countval = 0; static uint32_t ftepp_predef_randval = 0; /* __DATE__ */ -char *ftepp_predef_date(lex_file *context) { +static char *ftepp_predef_date(lex_file *context) { struct tm *itime = NULL; time_t rtime; char *value = (char*)mem_a(82); @@ -104,7 +104,7 @@ char *ftepp_predef_date(lex_file *context) { } /* __TIME__ */ -char *ftepp_predef_time(lex_file *context) { +static char *ftepp_predef_time(lex_file *context) { struct tm *itime = NULL; time_t rtime; char *value = (char*)mem_a(82); @@ -127,13 +127,13 @@ char *ftepp_predef_time(lex_file *context) { } /* __LINE__ */ -char *ftepp_predef_line(lex_file *context) { +static char *ftepp_predef_line(lex_file *context) { char *value; util_asprintf(&value, "%d", (int)context->line); return value; } /* __FILE__ */ -char *ftepp_predef_file(lex_file *context) { +static char *ftepp_predef_file(lex_file *context) { size_t length = strlen(context->name) + 3; /* two quotes and a terminator */ char *value = (char*)mem_a(length); util_snprintf(value, length, "\"%s\"", context->name); @@ -141,7 +141,7 @@ char *ftepp_predef_file(lex_file *context) { return value; } /* __COUNTER_LAST__ */ -char *ftepp_predef_counterlast(lex_file *context) { +static char *ftepp_predef_counterlast(lex_file *context) { char *value; util_asprintf(&value, "%u", ftepp_predef_countval); @@ -149,7 +149,7 @@ char *ftepp_predef_counterlast(lex_file *context) { return value; } /* __COUNTER__ */ -char *ftepp_predef_counter(lex_file *context) { +static char *ftepp_predef_counter(lex_file *context) { char *value; ftepp_predef_countval ++; util_asprintf(&value, "%u", ftepp_predef_countval); @@ -158,7 +158,7 @@ char *ftepp_predef_counter(lex_file *context) { return value; } /* __RANDOM__ */ -char *ftepp_predef_random(lex_file *context) { +static char *ftepp_predef_random(lex_file *context) { char *value; ftepp_predef_randval = (util_rand() % 0xFF) + 1; util_asprintf(&value, "%u", ftepp_predef_randval); @@ -167,7 +167,7 @@ char *ftepp_predef_random(lex_file *context) { return value; } /* __RANDOM_LAST__ */ -char *ftepp_predef_randomlast(lex_file *context) { +static char *ftepp_predef_randomlast(lex_file *context) { char *value; util_asprintf(&value, "%u", ftepp_predef_randval); @@ -175,7 +175,7 @@ char *ftepp_predef_randomlast(lex_file *context) { return value; } /* __TIMESTAMP__ */ -char *ftepp_predef_timestamp(lex_file *context) { +static char *ftepp_predef_timestamp(lex_file *context) { struct stat finfo; char *find; char *value; diff --git a/intrin.h b/intrin.h index 4f672dd..81af620 100644 --- a/intrin.h +++ b/intrin.h @@ -36,7 +36,7 @@ typedef struct { const char *alias; } intrin_t; -ht intrin_intrinsics() { +static ht intrin_intrinsics() { static ht intrinsics = NULL; if (!intrinsics) intrinsics = util_htnew(PARSER_HT_SIZE); @@ -69,12 +69,10 @@ ht intrin_intrinsics() { vec_push(parser->globals, (ast_expression*)(VALUE)); \ } while (0) - -ast_expression *intrin_func (parser_t *parser, const char *name); - #define QC_M_E 2.71828182845905 -ast_expression *intrin_pow(parser_t *parser) { +static ast_expression *intrin_func(parser_t *parser, const char *name); +static ast_expression *intrin_pow (parser_t *parser) { /* * float pow(float x, float y) { * float local = 1.0f; @@ -221,7 +219,7 @@ ast_expression *intrin_pow(parser_t *parser) { return (ast_expression*)value; } -ast_expression *intrin_mod(parser_t *parser) { +static ast_expression *intrin_mod(parser_t *parser) { /* * float mod(float x, float y) { * return x - y * floor(x / y); @@ -276,7 +274,7 @@ ast_expression *intrin_mod(parser_t *parser) { return (ast_expression*)value; } -ast_expression *intrin_exp(parser_t *parser) { +static ast_expression *intrin_exp(parser_t *parser) { /* * float exp(float x) { * return pow(QC_M_E, x); @@ -314,7 +312,7 @@ ast_expression *intrin_exp(parser_t *parser) { return (ast_expression*)value; } -ast_expression *intrin_isnan(parser_t *parser) { +static ast_expression *intrin_isnan(parser_t *parser) { /* * float isnan(float x) { * float local; @@ -383,7 +381,7 @@ void intrin_intrinsics_destroy(parser_t *parser) { } -ast_expression *intrin_func(parser_t *parser, const char *name) { +static ast_expression *intrin_func(parser_t *parser, const char *name) { static bool init = false; size_t i = 0; void *find; diff --git a/ir.c b/ir.c index b67a37c..5dae734 100644 --- a/ir.c +++ b/ir.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2012, 2013 * Wolfgang Bumiller + * 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 @@ -211,9 +212,31 @@ 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 ir_value* ir_value_var(const char *name, int st, int vtype); +static bool ir_value_set_name(ir_value*, const char *name); +static void ir_value_dump(ir_value*, int (*oprintf)(const char*,...)); +static ir_value* ir_gen_extparam_proto(ir_builder *ir); +static void ir_gen_extparam (code_t *, ir_builder *ir); + +static bool ir_builder_set_name(ir_builder *self, const char *name); + +static ir_function* ir_function_new(struct ir_builder_s *owner, int returntype); +static bool ir_function_set_name(ir_function*, const char *name); +static void ir_function_delete(ir_function*); +static void ir_function_dump(ir_function*, char *ind, int (*oprintf)(const char*,...)); + +static ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx, const char *label, + int op, ir_value *a, ir_value *b, int outype); +static void ir_block_delete(ir_block*); +static ir_block* ir_block_new(struct ir_function_s *owner, const char *label); +static bool GMQCC_WARN ir_block_create_store(ir_block*, lex_ctx, ir_value *target, ir_value *what); +static bool ir_block_set_label(ir_block*, const char *label); +static void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...)); + +static bool ir_instr_op(ir_instr*, int op, ir_value *value, bool writing); +static void ir_instr_delete(ir_instr*); +static void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...)); /* error functions */ static void irerror(lex_ctx ctx, const char *msg, ...) @@ -238,7 +261,7 @@ static bool irwarning(lex_ctx ctx, int warntype, const char *fmt, ...) * Vector utility functions */ -bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx) +static bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx) { size_t i; size_t len = vec_size(vec); @@ -251,7 +274,7 @@ bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t * return false; } -bool GMQCC_WARN vec_ir_block_find(ir_block **vec, ir_block *what, size_t *idx) +static bool GMQCC_WARN vec_ir_block_find(ir_block **vec, ir_block *what, size_t *idx) { size_t i; size_t len = vec_size(vec); @@ -264,7 +287,7 @@ bool GMQCC_WARN vec_ir_block_find(ir_block **vec, ir_block *what, size_t *idx) return false; } -bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx) +static bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx) { size_t i; size_t len = vec_size(vec); @@ -363,7 +386,7 @@ bool ir_builder_set_name(ir_builder *self, const char *name) return !!self->name; } -ir_function* ir_builder_get_function(ir_builder *self, const char *name) +static ir_function* ir_builder_get_function(ir_builder *self, const char *name) { return (ir_function*)util_htget(self->htfunctions, name); } @@ -398,7 +421,7 @@ ir_function* ir_builder_create_function(ir_builder *self, const char *name, int return fn; } -ir_value* ir_builder_get_global(ir_builder *self, const char *name) +static ir_value* ir_builder_get_global(ir_builder *self, const char *name) { return (ir_value*)util_htget(self->htglobals, name); } @@ -428,7 +451,7 @@ ir_value* ir_builder_get_va_count(ir_builder *self) return (self->reserved_va_count = ir_builder_create_global(self, "reserved:va_count", TYPE_FLOAT)); } -ir_value* ir_builder_get_field(ir_builder *self, const char *name) +static ir_value* ir_builder_get_field(ir_builder *self, const char *name) { return (ir_value*)util_htget(self->htfields, name); } @@ -452,10 +475,10 @@ ir_value* ir_builder_create_field(ir_builder *self, const char *name, int vtype) *IR Function */ -bool ir_function_naive_phi(ir_function*); -void ir_function_enumerate(ir_function*); -bool ir_function_calculate_liferanges(ir_function*); -bool ir_function_allocate_locals(ir_function*); +static bool ir_function_naive_phi(ir_function*); +static void ir_function_enumerate(ir_function*); +static bool ir_function_calculate_liferanges(ir_function*); +static bool ir_function_allocate_locals(ir_function*); ir_function* ir_function_new(ir_builder* owner, int outtype) { @@ -552,7 +575,7 @@ void ir_function_delete(ir_function *self) mem_d(self); } -void ir_function_collect_value(ir_function *self, ir_value *v) +static void ir_function_collect_value(ir_function *self, ir_value *v) { vec_push(self->values, v); } @@ -575,7 +598,7 @@ static bool instr_is_operation(uint16_t op) (op >= INSTR_CALL0 && op <= INSTR_CALL8) ); } -bool ir_function_pass_peephole(ir_function *self) +static bool ir_function_pass_peephole(ir_function *self) { size_t b; @@ -691,7 +714,7 @@ bool ir_function_pass_peephole(ir_function *self) return true; } -bool ir_function_pass_tailrecursion(ir_function *self) +static bool ir_function_pass_tailrecursion(ir_function *self) { size_t b, p; @@ -927,7 +950,7 @@ bool ir_block_set_label(ir_block *self, const char *name) *IR Instructions */ -ir_instr* ir_instr_new(lex_ctx ctx, ir_block* owner, int op) +static ir_instr* ir_instr_new(lex_ctx ctx, ir_block* owner, int op) { ir_instr *self; self = (ir_instr*)mem_a(sizeof(*self)); @@ -959,7 +982,7 @@ static void ir_instr_delete_quick(ir_instr *self) mem_d(self); } -void ir_instr_delete(ir_instr *self) +static void ir_instr_delete(ir_instr *self) { size_t i; /* The following calls can only delete from @@ -990,7 +1013,7 @@ void ir_instr_delete(ir_instr *self) mem_d(self); } -bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing) +static bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing) { if (self->_ops[op]) { size_t idx; @@ -1013,7 +1036,7 @@ bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing) *IR Value */ -void ir_value_code_setaddr(ir_value *self, int32_t gaddr) +static void ir_value_code_setaddr(ir_value *self, int32_t gaddr) { self->code.globaladdr = gaddr; if (self->members[0]) self->members[0]->code.globaladdr = gaddr; @@ -1021,7 +1044,7 @@ void ir_value_code_setaddr(ir_value *self, int32_t gaddr) if (self->members[2]) self->members[2]->code.globaladdr = gaddr; } -int32_t ir_value_code_addr(const ir_value *self) +static int32_t ir_value_code_addr(const ir_value *self) { if (self->store == store_return) return OFS_RETURN + self->code.addroffset; @@ -1134,7 +1157,7 @@ static GMQCC_INLINE size_t ir_value_sizeof(const ir_value *self) return type_sizeof_[self->vtype]; } -ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype) +static ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype) { ir_value *v = ir_value_var(name, storetype, vtype); if (!v) @@ -1241,7 +1264,7 @@ bool ir_value_lives(ir_value *self, size_t at) return false; } -bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e) +static bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e) { size_t k; vec_push(self->life, e); @@ -1251,7 +1274,7 @@ bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e) return true; } -bool ir_value_life_merge(ir_value *self, size_t s) +static bool ir_value_life_merge(ir_value *self, size_t s) { size_t i; const size_t vs = vec_size(self->life); @@ -1314,7 +1337,7 @@ bool ir_value_life_merge(ir_value *self, size_t s) return ir_value_life_insert(self, i, new_entry); } -bool ir_value_life_merge_into(ir_value *self, const ir_value *other) +static bool ir_value_life_merge_into(ir_value *self, const ir_value *other) { size_t i, myi; @@ -1388,7 +1411,7 @@ bool ir_value_life_merge_into(ir_value *self, const ir_value *other) return true; } -bool ir_values_overlap(const ir_value *a, const ir_value *b) +static bool ir_values_overlap(const ir_value *a, const ir_value *b) { /* For any life entry in A see if it overlaps with * any life entry in B. @@ -1484,7 +1507,7 @@ bool ir_block_create_store_op(ir_block *self, lex_ctx ctx, int op, ir_value *tar return true; } -bool ir_block_create_store(ir_block *self, lex_ctx ctx, ir_value *target, ir_value *what) +static bool ir_block_create_store(ir_block *self, lex_ctx ctx, ir_value *target, ir_value *what) { int op = 0; int vtype; @@ -1827,7 +1850,7 @@ ir_value* ir_block_create_unary(ir_block *self, lex_ctx ctx, return ir_block_create_general_instr(self, ctx, label, opcode, operand, NULL, ot); } -ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx ctx, const char *label, +static ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx ctx, const char *label, int op, ir_value *a, ir_value *b, int outype) { ir_instr *instr; @@ -3686,7 +3709,7 @@ bool ir_builder_generate(code_t *code, ir_builder *self, const char *filename) # define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE) #endif -const char *qc_opname(int op) +static const char *qc_opname(int op) { if (op < 0) return ""; if (op < (int)( sizeof(asm_instr) / sizeof(asm_instr[0]) )) @@ -3838,7 +3861,7 @@ void ir_block_dump(ir_block* b, char *ind, ind[strlen(ind)-1] = 0; } -void dump_phi(ir_instr *in, int (*oprintf)(const char*, ...)) +static void dump_phi(ir_instr *in, int (*oprintf)(const char*, ...)) { size_t i; oprintf("%s <- phi ", in->_ops[0]->name); @@ -3908,7 +3931,7 @@ void ir_instr_dump(ir_instr *in, char *ind, ind[strlen(ind)-1] = 0; } -void ir_value_dump_string(const char *str, int (*oprintf)(const char*, ...)) +static void ir_value_dump_string(const char *str, int (*oprintf)(const char*, ...)) { oprintf("\""); for (; *str; ++str) { diff --git a/ir.h b/ir.h index dac16a3..cd38295 100644 --- a/ir.h +++ b/ir.h @@ -23,7 +23,6 @@ #ifndef GMQCC_IR_HDR #define GMQCC_IR_HDR #include "gmqcc.h" -/* ir_value */ typedef struct { @@ -86,42 +85,19 @@ typedef struct ir_value_s { ir_life_entry_t *life; } ir_value; -int32_t ir_value_code_addr(const ir_value*); - /* ir_value can be a variable, or created by an operation */ -ir_value* ir_value_var(const char *name, int st, int vtype); /* if a result of an operation: the function should store * it to remember to delete it / garbage collect it */ -ir_value* ir_value_out(struct ir_function_s *owner, const char *name, int st, int vtype); -void ir_value_delete(ir_value*); -bool ir_value_set_name(ir_value*, const char *name); -ir_value* ir_value_vector_member(ir_value*, unsigned int member); - -bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx); - +void ir_value_delete(ir_value*); +ir_value* ir_value_vector_member(ir_value*, unsigned int member); bool GMQCC_WARN ir_value_set_float(ir_value*, float f); bool GMQCC_WARN ir_value_set_func(ir_value*, int f); -#if 0 -bool GMQCC_WARN ir_value_set_int(ir_value*, int i); -#endif bool GMQCC_WARN ir_value_set_string(ir_value*, const char *s); bool GMQCC_WARN ir_value_set_vector(ir_value*, vector v); bool GMQCC_WARN ir_value_set_field(ir_value*, ir_value *fld); -/*bool ir_value_set_pointer_v(ir_value*, ir_value* p); */ -/*bool ir_value_set_pointer_i(ir_value*, int i); */ - -/* merge an instruction into the life-range */ -/* returns false if the lifepoint was already known */ -bool ir_value_life_merge(ir_value*, size_t); -bool ir_value_life_merge_into(ir_value*, const ir_value*); -/* check if a value lives at a specific point */ -bool ir_value_lives(ir_value*, size_t); -/* check if the life-range of 2 values overlaps */ -bool ir_values_overlap(const ir_value*, const ir_value*); - -void ir_value_dump(ir_value*, int (*oprintf)(const char*,...)); -void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...)); +bool ir_value_lives(ir_value*, size_t); +void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...)); /* PHI data */ typedef struct ir_phi_entry_s @@ -150,15 +126,6 @@ typedef struct ir_instr_s struct ir_block_s *owner; } ir_instr; -ir_instr* ir_instr_new(lex_ctx ctx, struct ir_block_s *owner, int opcode); -void ir_instr_delete(ir_instr*); - -bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx); - -bool ir_instr_op(ir_instr*, int op, ir_value *value, bool writing); - -void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...)); - /* block */ typedef struct ir_block_s { @@ -182,30 +149,16 @@ typedef struct ir_block_s size_t code_start; } ir_block; -ir_block* ir_block_new(struct ir_function_s *owner, const char *label); -void ir_block_delete(ir_block*); - -bool ir_block_set_label(ir_block*, const char *label); - -ir_value* ir_block_create_binop(ir_block*, lex_ctx, const char *label, int op, - ir_value *left, ir_value *right); -ir_value* ir_block_create_unary(ir_block*, lex_ctx, const char *label, int op, - ir_value *operand); +ir_value* ir_block_create_binop(ir_block*, lex_ctx, const char *label, int op, ir_value *left, ir_value *right); +ir_value* ir_block_create_unary(ir_block*, lex_ctx, const char *label, int op, ir_value *operand); bool GMQCC_WARN ir_block_create_store_op(ir_block*, lex_ctx, int op, ir_value *target, ir_value *what); -bool GMQCC_WARN ir_block_create_store(ir_block*, lex_ctx, ir_value *target, ir_value *what); bool GMQCC_WARN ir_block_create_storep(ir_block*, lex_ctx, ir_value *target, ir_value *what); - -/* field must be of TYPE_FIELD */ -ir_value* ir_block_create_load_from_ent(ir_block*, lex_ctx, const char *label, ir_value *ent, ir_value *field, int outype); - -ir_value* ir_block_create_fieldaddress(ir_block*, lex_ctx, const char *label, ir_value *entity, ir_value *field); +ir_value* ir_block_create_load_from_ent(ir_block*, lex_ctx, const char *label, ir_value *ent, ir_value *field, int outype); +ir_value* ir_block_create_fieldaddress(ir_block*, lex_ctx, const char *label, ir_value *entity, ir_value *field); /* This is to create an instruction of the form * %label := opcode a, b */ -ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx, const char *label, - int op, ir_value *a, ir_value *b, int outype); - ir_instr* ir_block_create_phi(ir_block*, lex_ctx, const char *label, int vtype); ir_value* ir_phi_value(ir_instr*); void ir_phi_add(ir_instr*, ir_block *b, ir_value *v); @@ -226,10 +179,7 @@ bool GMQCC_WARN ir_block_create_if(ir_block*, lex_ctx, ir_value *cond, bool GMQCC_WARN ir_block_create_jump(ir_block*, lex_ctx, ir_block *to); bool GMQCC_WARN ir_block_create_goto(ir_block*, lex_ctx, ir_block *to); -void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...)); - /* function */ - typedef struct ir_function_s { char *name; @@ -276,6 +226,7 @@ typedef struct ir_function_s /* vararg support: */ size_t max_varargs; } ir_function; + #define IR_FLAG_HAS_ARRAYS (1<<1) #define IR_FLAG_HAS_UNINITIALIZED (1<<2) #define IR_FLAG_HAS_GOTO (1<<3) @@ -283,25 +234,9 @@ typedef struct ir_function_s #define IR_FLAG_MASK_NO_OVERLAP (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED) #define IR_FLAG_MASK_NO_LOCAL_TEMPS (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED) -ir_function* ir_function_new(struct ir_builder_s *owner, int returntype); -void ir_function_delete(ir_function*); - -void ir_function_collect_value(ir_function*, ir_value *value); - -bool ir_function_set_name(ir_function*, const char *name); - -ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param); - +ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param); bool GMQCC_WARN ir_function_finalize(ir_function*); -/* -bool ir_function_naive_phi(ir_function*); -bool ir_function_enumerate(ir_function*); -bool ir_function_calculate_liferanges(ir_function*); -*/ - -ir_block* ir_function_create_block(lex_ctx ctx, ir_function*, const char *label); - -void ir_function_dump(ir_function*, char *ind, int (*oprintf)(const char*,...)); +ir_block* ir_function_create_block(lex_ctx ctx, ir_function*, const char *label); /* builder */ #define IR_HT_SIZE 1024 @@ -334,25 +269,14 @@ typedef struct ir_builder_s ir_value *reserved_va_count; } ir_builder; -ir_builder* ir_builder_new(const char *modulename); -void ir_builder_delete(ir_builder*); - -bool ir_builder_set_name(ir_builder *self, const char *name); - -ir_function* ir_builder_get_function(ir_builder*, const char *fun); +ir_builder* ir_builder_new(const char *modulename); +void ir_builder_delete(ir_builder*); ir_function* ir_builder_create_function(ir_builder*, const char *name, int outtype); - -ir_value* ir_builder_get_global(ir_builder*, const char *fun); -ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype); -ir_value* ir_builder_get_field(ir_builder*, const char *fun); -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); - -void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...)); - +ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype); +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); +void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...)); /* * This code assumes 32 bit floats while generating binary diff --git a/lexer.c b/lexer.c index 7722f4f..035dc1b 100644 --- a/lexer.c +++ b/lexer.c @@ -60,7 +60,7 @@ static size_t num_keywords_fg = sizeof(keywords_fg) / sizeof(keywords_fg[0]); static char* *lex_filenames; -void lexerror(lex_file *lex, const char *fmt, ...) +static void lexerror(lex_file *lex, const char *fmt, ...) { va_list ap; @@ -72,7 +72,7 @@ void lexerror(lex_file *lex, const char *fmt, ...) va_end(ap); } -bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...) +static bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...) { bool r; lex_ctx ctx; diff --git a/lexer.h b/lexer.h index 2573fb2..5f0bb63 100644 --- a/lexer.h +++ b/lexer.h @@ -340,6 +340,6 @@ static const size_t qcc_operator_count = (sizeof(qcc_operators) / sizeof(qcc_ope extern const oper_info *operators; extern size_t operator_count; -void lexerror(lex_file*, const char *fmt, ...); +/*void lexerror(lex_file*, const char *fmt, ...);*/ #endif diff --git a/pak.c b/pak.c index 048469b..9ff7e78 100644 --- a/pak.c +++ b/pak.c @@ -222,7 +222,7 @@ static pak_file_t *pak_open_write(const char *file) { return pak; } -pak_file_t *pak_open(const char *file, const char *mode) { +static pak_file_t *pak_open(const char *file, const char *mode) { if (!file || !mode) return NULL; @@ -234,7 +234,7 @@ pak_file_t *pak_open(const char *file, const char *mode) { return NULL; } -bool pak_exists(pak_file_t *pak, const char *file, pak_directory_t **dir) { +static bool pak_exists(pak_file_t *pak, const char *file, pak_directory_t **dir) { size_t itr; if (!pak || !file) @@ -259,7 +259,7 @@ bool pak_exists(pak_file_t *pak, const char *file, pak_directory_t **dir) { /* * Extraction abilities. These work as you expect them to. */ -bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) { +static bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) { pak_directory_t *dir = NULL; unsigned char *dat = NULL; char *local = NULL; @@ -310,7 +310,7 @@ bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) { return true; } -bool pak_extract_all(pak_file_t *pak, const char *dir) { +static bool pak_extract_all(pak_file_t *pak, const char *dir) { size_t itr; if (!fs_dir_make(dir)) @@ -328,7 +328,7 @@ bool pak_extract_all(pak_file_t *pak, const char *dir) { * Insertion functions (the opposite of extraction). Yes for generating * PAKs. */ -bool pak_insert_one(pak_file_t *pak, const char *file) { +static bool pak_insert_one(pak_file_t *pak, const char *file) { pak_directory_t dir; unsigned char *dat; FILE *fp; @@ -413,7 +413,7 @@ bool pak_insert_all(pak_file_t *pak, const char *dir) { return true; } -bool pak_close(pak_file_t *pak) { +static bool pak_close(pak_file_t *pak) { size_t itr; if (!pak) diff --git a/parser.c b/parser.c index da9d33a..6d0c010 100644 --- a/parser.c +++ b/parser.c @@ -185,7 +185,7 @@ vector vec3_mulvf(vector a, float b) * parsing */ -bool parser_next(parser_t *parser) +static bool parser_next(parser_t *parser) { /* lex_do kills the previous token */ parser->tok = lex_do(parser->lex); @@ -6069,7 +6069,7 @@ parser_t *parser_create() return parser; } -bool parser_compile(parser_t *parser) +static bool parser_compile(parser_t *parser) { /* initial lexer/parser state */ parser->lex->flags.noops = true; diff --git a/test.c b/test.c index 7722af2..2febbff 100644 --- a/test.c +++ b/test.c @@ -60,7 +60,7 @@ typedef struct { int pid; } popen_t; -FILE ** task_popen(const char *command, const char *mode) { +static FILE ** task_popen(const char *command, const char *mode) { int inhandle [2]; int outhandle [2]; int errhandle [2]; @@ -137,7 +137,7 @@ task_popen_error_0: return NULL; } -int task_pclose(FILE **handles) { +static int task_pclose(FILE **handles) { popen_t *data = (popen_t*)handles; int status = 0; @@ -158,7 +158,7 @@ int task_pclose(FILE **handles) { char name_out[L_tmpnam]; } popen_t; - FILE **task_popen(const char *command, const char *mode) { + static FILE **task_popen(const char *command, const char *mode) { char *cmd = NULL; popen_t *open = (popen_t*)mem_a(sizeof(popen_t)); @@ -179,7 +179,7 @@ int task_pclose(FILE **handles) { return open->handles; } - void task_pclose(FILE **files) { + static void task_pclose(FILE **files) { popen_t *open = ((popen_t*)files); fs_file_close(files[1]); fs_file_close(files[2]); @@ -281,7 +281,7 @@ typedef struct { * This is very much like a compiler code generator :-). This generates * a value from some data observed from the compiler. */ -bool task_template_generate(task_template_t *tmpl, char tag, const char *file, size_t line, char *value, size_t *pad) { +static bool task_template_generate(task_template_t *tmpl, char tag, const char *file, size_t line, char *value, size_t *pad) { size_t desclen = 0; size_t filelen = 0; char **destval = NULL; @@ -354,7 +354,7 @@ bool task_template_generate(task_template_t *tmpl, char tag, const char *file, s return true; } -bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size_t *pad) { +static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size_t *pad) { char *data = NULL; char *back = NULL; size_t size = 0; @@ -480,7 +480,7 @@ failure: * Nullifies the template data: used during initialization of a new * template and free. */ -void task_template_nullify(task_template_t *tmpl) { +static void task_template_nullify(task_template_t *tmpl) { if (!tmpl) return; @@ -495,7 +495,7 @@ void task_template_nullify(task_template_t *tmpl) { tmpl->testflags = NULL; } -task_template_t *task_template_compile(const char *file, const char *dir, size_t *pad) { +static task_template_t *task_template_compile(const char *file, const char *dir, size_t *pad) { /* a page should be enough */ char fullfile[4096]; size_t filepadd = 0; @@ -609,7 +609,7 @@ failure: return NULL; } -void task_template_destroy(task_template_t **tmpl) { +static void task_template_destroy(task_template_t **tmpl) { if (!tmpl) return; @@ -660,7 +660,7 @@ static task_t *task_tasks = NULL; * Read a directory and searches for all template files in it * which is later used to run all tests. */ -bool task_propagate(const char *curdir, size_t *pad, const char *defs) { +static bool task_propagate(const char *curdir, size_t *pad, const char *defs) { bool success = true; DIR *dir; struct dirent *files; @@ -840,7 +840,7 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) { * Task precleanup removes any existing temporary files or log files * left behind from a previous invoke of the test-suite. */ -void task_precleanup(const char *curdir) { +static void task_precleanup(const char *curdir) { DIR *dir; struct dirent *files; char buffer[4096]; @@ -863,7 +863,7 @@ void task_precleanup(const char *curdir) { fs_dir_close(dir); } -void task_destroy(void) { +static void task_destroy(void) { /* * Free all the data in the task list and finally the list itself * then proceed to cleanup anything else outside the program like @@ -912,7 +912,7 @@ void task_destroy(void) { * messages IF the procedure type is -execute, otherwise it matches * the preprocessor output. */ -bool task_trymatch(task_template_t *tmpl, char ***line) { +static bool task_trymatch(task_template_t *tmpl, char ***line) { bool success = true; bool preprocessing = false; FILE *execute; @@ -1020,7 +1020,7 @@ bool task_trymatch(task_template_t *tmpl, char ***line) { return success; } -const char *task_type(task_template_t *tmpl) { +static const char *task_type(task_template_t *tmpl) { if (!strcmp(tmpl->proceduretype, "-pp")) return "type: preprocessor"; if (!strcmp(tmpl->proceduretype, "-execute")) @@ -1037,7 +1037,7 @@ const char *task_type(task_template_t *tmpl) { * from thin air and executed INLINE. */ #include -void task_schedualize(size_t *pad) { +static void task_schedualize(size_t *pad) { char space[2][64]; bool execute = false; char *data = NULL; @@ -1210,7 +1210,7 @@ void task_schedualize(size_t *pad) { * * It expects con_init() was called before hand. */ -GMQCC_WARN bool test_perform(const char *curdir, const char *defs) { +static GMQCC_WARN bool test_perform(const char *curdir, const char *defs) { static const char *default_defs = "defs.qh"; size_t pad[] = { diff --git a/util.c b/util.c index c8d50f5..d695ae6 100644 --- a/util.c +++ b/util.c @@ -491,7 +491,7 @@ GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) { return (size_t) (hash % ht->size); } -hash_node_t *_util_htnewpair(const char *key, void *value) { +static hash_node_t *_util_htnewpair(const char *key, void *value) { hash_node_t *node; if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t)))) return NULL; From d45956f55e303c59fc188eb1535a3625c8ba81fa Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 29 May 2013 03:35:51 +0000 Subject: [PATCH 22/63] Fix that memory leak that I spent hours trying to find months ago and didn't succeed at. --- Makefile | 1 - parser.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fea3356..2f2b08a 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,6 @@ SPLINTFLAGS = \ -nullstate \ -varuse \ -mustfreefresh \ - -compdestroy \ -compmempass \ -nullpass \ -onlytrans \ diff --git a/parser.c b/parser.c index 6d0c010..a9fa3f6 100644 --- a/parser.c +++ b/parser.c @@ -5814,6 +5814,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma } vec_free(sy.out); vec_free(sy.ops); + vec_free(sy.argc); var->cvq = cvq; } } From e3f4ae303870eb765812a4f48c68164b8e051c83 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 29 May 2013 03:39:38 +0000 Subject: [PATCH 23/63] Add back that splint flag --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 2f2b08a..fea3356 100644 --- a/Makefile +++ b/Makefile @@ -129,6 +129,7 @@ SPLINTFLAGS = \ -nullstate \ -varuse \ -mustfreefresh \ + -compdestroy \ -compmempass \ -nullpass \ -onlytrans \ From 6d6a2efadac46d5f8d2b44e5f73bd94549529681 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 29 May 2013 11:13:42 +0000 Subject: [PATCH 24/63] Experimental support for implicit return assignments. This closes #107. To enable return assignment support use -freturn-assignments. This allows you to do the following in QC code. T name() { return = expr_eval_T; return; /* returns expr_eval_T */ }. It allows for concise code and to rid locals in functions. It also saves a tremendous amount of space since only types of certian globals need to be allocated for returns. --- ast.c | 8 ++-- opts.def | 1 + parser.c | 96 ++++++++++++++++++++++++++++++++++++++++++++-- tests/rassign.qc | 23 +++++++++++ tests/rassign.tmpl | 7 ++++ 5 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 tests/rassign.qc create mode 100644 tests/rassign.tmpl diff --git a/ast.c b/ast.c index 01a08e5..41dfb29 100644 --- a/ast.c +++ b/ast.c @@ -1101,9 +1101,9 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype) vtype->hasvalue = true; vtype->constval.vfunc = self; - self->varargs = NULL; - self->argc = NULL; - self->fixedparams = NULL; + self->varargs = NULL; + self->argc = NULL; + self->fixedparams = NULL; return self; } @@ -1419,7 +1419,7 @@ error: /* clean up */ return false; } -static bool ast_local_codegen(ast_value *self, ir_function *func, bool param) +bool ast_local_codegen(ast_value *self, ir_function *func, bool param) { ir_value *v = NULL; diff --git a/opts.def b/opts.def index a9301a5..520f9b9 100644 --- a/opts.def +++ b/opts.def @@ -51,6 +51,7 @@ GMQCC_DEFINE_FLAG(VARIADIC_ARGS) GMQCC_DEFINE_FLAG(LEGACY_VECTOR_MATHS) GMQCC_DEFINE_FLAG(EXPRESSIONS_FOR_BUILTINS) + GMQCC_DEFINE_FLAG(RETURN_ASSIGNMENTS) #endif /* warning flags */ diff --git a/parser.c b/parser.c index 4824106..d0563c1 100644 --- a/parser.c +++ b/parser.c @@ -106,6 +106,13 @@ typedef struct parser_s { /* code generator */ code_t *code; + + /* vector of global return vars. + * for example, you can return string, float, vector, or other + * things, hese will be created as globals here instead of + * locals in a function (saves space). + */ + ast_value **returns; } parser_t; static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; @@ -345,6 +352,29 @@ static ast_expression* parser_find_global(parser_t *parser, const char *name) return (ast_expression*)util_htget(parser->htglobals, name); } +static ast_value* parser_find_returnvalue(parser_t *parser, int vtype) +{ + ast_value *out; + size_t i; + char *name = NULL; + + /* find existing global for the job */ + for (i = 0; i < vec_size(parser->returns); i++) + if (parser->returns[i]->expression.vtype == vtype) + return parser->returns[i]; + + util_asprintf(&name, "#ret_%s", type_name[vtype]); + + out = ast_value_new(parser_ctx(parser), name, vtype); + out->hasvalue = false; + out->isimm = false; + + vec_push(parser->returns, out); + + mem_d(name); + return out; +} + static ast_expression* parser_find_param(parser_t *parser, const char *name) { size_t i; @@ -2893,8 +2923,10 @@ onerr: static bool parse_return(parser_t *parser, ast_block *block, ast_expression **out) { - ast_expression *exp = NULL; - ast_return *ret = NULL; + ast_expression *exp = NULL; + ast_expression *var = NULL; + ast_return *ret = NULL; + ast_expression *find = NULL; ast_value *expected = parser->function->vtype; lex_ctx ctx = parser_ctx(parser); @@ -2906,6 +2938,44 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou return false; } + /* return assignments */ + if (parser->tok == '=') { + if (!OPTS_FLAG(RETURN_ASSIGNMENTS)) { + parseerror(parser, "return assignments not activated, try using -freturn-assigments"); + return false; + } + + if (!parser_next(parser)) { + parseerror(parser, "expected return assignment expression"); + return false; + } + + if (!(exp = parse_expression_leave(parser, false, false, false))) + return false; + + if (exp->vtype != TYPE_NIL && + exp->vtype != ((ast_expression*)expected)->next->vtype) + { + parseerror(parser, "return assignment with invalid expression"); + } + + /* store to 'return' local variable */ + var = (ast_expression*)ast_store_new( + ctx, + type_store_instr[exp->vtype], + (ast_expression*)parser_find_returnvalue(parser, exp->vtype), + (ast_expression*)exp + ); + + if (!var) { + ast_unref(exp); + return false; + } + + *out = var; + return true; + } + if (parser->tok != ';') { exp = parse_expression(parser, false, false); if (!exp) @@ -2925,10 +2995,16 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou } else { if (!parser_next(parser)) parseerror(parser, "parse error"); - if (expected->expression.next->vtype != TYPE_VOID) { + + /* build expression to return */ + if ((find = (ast_expression*)parser_find_returnvalue(parser, expected->expression.next->vtype)) && OPTS_FLAG(RETURN_ASSIGNMENTS)) + ret = ast_return_new(ctx, find); + + else if (expected->expression.next->vtype != TYPE_VOID) + { (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); + ret = ast_return_new(ctx, NULL); } - ret = ast_return_new(ctx, NULL); } *out = (ast_expression*)ret; return true; @@ -4276,6 +4352,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) } vec_push(func->blocks, block); + parser->function = old; if (!parser_leaveblock(parser)) @@ -6067,6 +6144,7 @@ parser_t *parser_create() parser->reserved_version = NULL; } + parser->returns = NULL; return parser; } @@ -6148,6 +6226,9 @@ void parser_cleanup(parser_t *parser) for (i = 0; i < vec_size(parser->globals); ++i) { ast_delete(parser->globals[i]); } + for (i = 0; i < vec_size(parser->returns); ++i) { + ast_delete(parser->returns[i]); + } vec_free(parser->accessors); vec_free(parser->functions); vec_free(parser->imm_vector); @@ -6339,6 +6420,13 @@ bool parser_finish(parser_t *parser, const char *output) return false; } } + for (i = 0; i < vec_size(parser->returns); ++i) { + if (!ast_global_codegen(parser->returns[i], ir, false)) { + con_out("internal error: failed to generate return assignment %s\n", parser->returns[i]->name); + ir_builder_delete(ir); + return false; + } + } if (parser->reserved_version && !ast_global_codegen(parser->reserved_version, ir, false)) { diff --git a/tests/rassign.qc b/tests/rassign.qc new file mode 100644 index 0000000..f734e7e --- /dev/null +++ b/tests/rassign.qc @@ -0,0 +1,23 @@ +float f_float() { + return = 100.0f; + return = 200.0f; + return; +} + +vector f_vector() { + return = '1 2 3'; + return = '2 3 4'; + return; +} + +string f_string() { + return = "hello"; + return = "world"; + return; +} + +void main() { + print(ftos(f_float()), "\n"); // 200.0f + print(vtos(f_vector()), "\n"); // '1 2 3' + print(f_string(), "\n"); // world +} diff --git a/tests/rassign.tmpl b/tests/rassign.tmpl new file mode 100644 index 0000000..6061b3d --- /dev/null +++ b/tests/rassign.tmpl @@ -0,0 +1,7 @@ +I: rassign.qc +D: test return assignments +T: -execute +C: -freturn-assignments +M: 200 +M: '2 3 4' +M: world From 1b71caa1fe1807f70debf7a555344cf6b9fc4961 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 29 May 2013 11:29:52 +0000 Subject: [PATCH 25/63] Update man page --- doc/gmqcc.1 | 12 ++++++++++++ tests/rassign.qc | 8 ++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/doc/gmqcc.1 b/doc/gmqcc.1 index 60257dc..6ede944 100644 --- a/doc/gmqcc.1 +++ b/doc/gmqcc.1 @@ -506,6 +506,18 @@ Example: void printA() = #1; // the usual way void printB() = #2-1; // with a constant expression .Ed +.It Fl f Ns Cm return-assignments +Enabiling this option will allow assigning values or expressions to the +return keyword as if it were a local variable of the same type as the +function's signature's return type. +.Pp +Example: +.Bd -literal -offset indent +float bar() { return 1024; } +float fun() { + return = bar(); + return; // returns value of bar +} .El .Sh OPTIMIZATIONS .Bl -tag -width Ds diff --git a/tests/rassign.qc b/tests/rassign.qc index f734e7e..7e3d0e6 100644 --- a/tests/rassign.qc +++ b/tests/rassign.qc @@ -5,8 +5,12 @@ float f_float() { } vector f_vector() { - return = '1 2 3'; - return = '2 3 4'; + vector foo; + foo.x = f_float(); + foo.y = f_float(); + foo.z = f_float(); + + return = foo; return; } From fd5506b3763818320a84e37d576dcfa0d6459abb Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 29 May 2013 11:30:26 +0000 Subject: [PATCH 26/63] Update test template. --- tests/rassign.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rassign.tmpl b/tests/rassign.tmpl index 6061b3d..63642aa 100644 --- a/tests/rassign.tmpl +++ b/tests/rassign.tmpl @@ -3,5 +3,5 @@ D: test return assignments T: -execute C: -freturn-assignments M: 200 -M: '2 3 4' +M: '200 200 200' M: world From db6ca6c5f8abb2272c9f72bd820fd650bed0783a Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 29 May 2013 11:32:42 +0000 Subject: [PATCH 27/63] Make static --- ast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ast.c b/ast.c index 41dfb29..5039653 100644 --- a/ast.c +++ b/ast.c @@ -1419,7 +1419,7 @@ error: /* clean up */ return false; } -bool ast_local_codegen(ast_value *self, ir_function *func, bool param) +static bool ast_local_codegen(ast_value *self, ir_function *func, bool param) { ir_value *v = NULL; From afdc0c9dc8c0e71130ee458136415dfd76ac6ab9 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 29 May 2013 16:51:59 +0200 Subject: [PATCH 28/63] assignable return value now lives in ast_function, as globals can get overwritten randomly; removed parser_find_retval; updated parse_return --- ast.c | 9 ++++++ ast.h | 1 + parser.c | 94 +++++++++++++++++++------------------------------------- 3 files changed, 41 insertions(+), 63 deletions(-) diff --git a/ast.c b/ast.c index 5039653..4af3e3c 100644 --- a/ast.c +++ b/ast.c @@ -1104,6 +1104,7 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype) self->varargs = NULL; self->argc = NULL; self->fixedparams = NULL; + self->return_value = NULL; return self; } @@ -1133,6 +1134,8 @@ void ast_function_delete(ast_function *self) ast_delete(self->argc); if (self->fixedparams) ast_unref(self->fixedparams); + if (self->return_value) + ast_unref(self->return_value); mem_d(self); } @@ -1625,6 +1628,12 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) return true; } + // have a local return value variable? + if (self->return_value) { + if (!ast_local_codegen(self->return_value, self->ir_func, false)) + return false; + } + if (!vec_size(self->blocks)) { compile_error(ast_ctx(self), "function `%s` has no body", self->name); return false; diff --git a/ast.h b/ast.h index c624a1f..a0fa14d 100644 --- a/ast.h +++ b/ast.h @@ -622,6 +622,7 @@ struct ast_function_s ast_value *varargs; ast_value *argc; ast_value *fixedparams; + ast_value *return_value; }; ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype); /* This will NOT delete the underlying ast_value */ diff --git a/parser.c b/parser.c index d0563c1..5823793 100644 --- a/parser.c +++ b/parser.c @@ -106,13 +106,6 @@ typedef struct parser_s { /* code generator */ code_t *code; - - /* vector of global return vars. - * for example, you can return string, float, vector, or other - * things, hese will be created as globals here instead of - * locals in a function (saves space). - */ - ast_value **returns; } parser_t; static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; @@ -352,29 +345,6 @@ static ast_expression* parser_find_global(parser_t *parser, const char *name) return (ast_expression*)util_htget(parser->htglobals, name); } -static ast_value* parser_find_returnvalue(parser_t *parser, int vtype) -{ - ast_value *out; - size_t i; - char *name = NULL; - - /* find existing global for the job */ - for (i = 0; i < vec_size(parser->returns); i++) - if (parser->returns[i]->expression.vtype == vtype) - return parser->returns[i]; - - util_asprintf(&name, "#ret_%s", type_name[vtype]); - - out = ast_value_new(parser_ctx(parser), name, vtype); - out->hasvalue = false; - out->isimm = false; - - vec_push(parser->returns, out); - - mem_d(name); - return out; -} - static ast_expression* parser_find_param(parser_t *parser, const char *name) { size_t i; @@ -2926,7 +2896,7 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou ast_expression *exp = NULL; ast_expression *var = NULL; ast_return *ret = NULL; - ast_expression *find = NULL; + ast_value *retval = parser->function->return_value; ast_value *expected = parser->function->vtype; lex_ctx ctx = parser_ctx(parser); @@ -2944,34 +2914,47 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou parseerror(parser, "return assignments not activated, try using -freturn-assigments"); return false; } - + + if (type_store_instr[expected->expression.next->vtype] == VINSTR_END) { + char ty1[1024]; + ast_type_to_string(expected->expression.next, ty1, sizeof(ty1)); + parseerror(parser, "invalid return type: `%s'", ty1); + return false; + } + if (!parser_next(parser)) { parseerror(parser, "expected return assignment expression"); return false; } - + if (!(exp = parse_expression_leave(parser, false, false, false))) return false; - - if (exp->vtype != TYPE_NIL && - exp->vtype != ((ast_expression*)expected)->next->vtype) - { - parseerror(parser, "return assignment with invalid expression"); + + /* prepare the return value */ + if (!retval) { + retval = ast_value_new(ctx, "#LOCAL_RETURN", TYPE_VOID); + ast_type_adopt(retval, expected->expression.next); + parser->function->return_value = retval; } - + + if (!ast_compare_type(exp, (ast_expression*)retval)) { + char ty1[1024], ty2[1024]; + ast_type_to_string(exp, ty1, sizeof(ty1)); + ast_type_to_string(&retval->expression, ty2, sizeof(ty2)); + parseerror(parser, "invalid type for return value: `%s', expected `%s'", ty1, ty2); + } + /* store to 'return' local variable */ var = (ast_expression*)ast_store_new( ctx, - type_store_instr[exp->vtype], - (ast_expression*)parser_find_returnvalue(parser, exp->vtype), - (ast_expression*)exp - ); - + type_store_instr[expected->expression.next->vtype], + (ast_expression*)retval, exp); + if (!var) { ast_unref(exp); return false; } - + *out = var; return true; } @@ -2995,16 +2978,12 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou } else { if (!parser_next(parser)) parseerror(parser, "parse error"); - - /* build expression to return */ - if ((find = (ast_expression*)parser_find_returnvalue(parser, expected->expression.next->vtype)) && OPTS_FLAG(RETURN_ASSIGNMENTS)) - ret = ast_return_new(ctx, find); - - else if (expected->expression.next->vtype != TYPE_VOID) + + if (!retval && expected->expression.next->vtype != TYPE_VOID) { (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); - ret = ast_return_new(ctx, NULL); } + ret = ast_return_new(ctx, (ast_expression*)retval); } *out = (ast_expression*)ret; return true; @@ -6144,7 +6123,6 @@ parser_t *parser_create() parser->reserved_version = NULL; } - parser->returns = NULL; return parser; } @@ -6226,9 +6204,6 @@ void parser_cleanup(parser_t *parser) for (i = 0; i < vec_size(parser->globals); ++i) { ast_delete(parser->globals[i]); } - for (i = 0; i < vec_size(parser->returns); ++i) { - ast_delete(parser->returns[i]); - } vec_free(parser->accessors); vec_free(parser->functions); vec_free(parser->imm_vector); @@ -6420,13 +6395,6 @@ bool parser_finish(parser_t *parser, const char *output) return false; } } - for (i = 0; i < vec_size(parser->returns); ++i) { - if (!ast_global_codegen(parser->returns[i], ir, false)) { - con_out("internal error: failed to generate return assignment %s\n", parser->returns[i]->name); - ir_builder_delete(ir); - return false; - } - } if (parser->reserved_version && !ast_global_codegen(parser->reserved_version, ir, false)) { From 9167de1631b078c44ac5d03e135d291ffb0a965a Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 29 May 2013 16:56:39 +0200 Subject: [PATCH 29/63] fixing that comment... --- ast.c | 2 +- parser.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ast.c b/ast.c index 4af3e3c..35b1a7d 100644 --- a/ast.c +++ b/ast.c @@ -1628,7 +1628,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) return true; } - // have a local return value variable? + /* have a local return value variable? */ if (self->return_value) { if (!ast_local_codegen(self->return_value, self->ir_func, false)) return false; diff --git a/parser.c b/parser.c index 5823793..27c694d 100644 --- a/parser.c +++ b/parser.c @@ -3731,7 +3731,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } return parse_typedef(parser); } - parseerror(parser, "Unexpected keyword"); + parseerror(parser, "Unexpected keyword: `%s'", parser_tokval(parser)); return false; } else if (parser->tok == '{') From 5aba29006bdd32442ee2ed3e4c9c6eaf911a806b Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 29 May 2013 16:58:18 +0200 Subject: [PATCH 30/63] return assignment factorial test --- parser.c | 5 +++++ tests/rassign.qc | 10 +++++++++- tests/rassign.tmpl | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/parser.c b/parser.c index 27c694d..d9be036 100644 --- a/parser.c +++ b/parser.c @@ -2955,6 +2955,11 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou return false; } + if (parser->tok != ';') + parseerror(parser, "missing semicolon after return assignment"); + else if (!parser_next(parser)) + parseerror(parser, "parse error after return assignment"); + *out = var; return true; } diff --git a/tests/rassign.qc b/tests/rassign.qc index 7e3d0e6..69ec31c 100644 --- a/tests/rassign.qc +++ b/tests/rassign.qc @@ -9,7 +9,7 @@ vector f_vector() { foo.x = f_float(); foo.y = f_float(); foo.z = f_float(); - + return = foo; return; } @@ -20,8 +20,16 @@ string f_string() { return; } +float factorial(float n) { + if (n == 0) return = 1; + else return = n * factorial(n - 1); + + return; +} + void main() { print(ftos(f_float()), "\n"); // 200.0f print(vtos(f_vector()), "\n"); // '1 2 3' print(f_string(), "\n"); // world + print(ftos(factorial(4)), "\n"); // 24 } diff --git a/tests/rassign.tmpl b/tests/rassign.tmpl index 63642aa..f169c82 100644 --- a/tests/rassign.tmpl +++ b/tests/rassign.tmpl @@ -5,3 +5,4 @@ C: -freturn-assignments M: 200 M: '200 200 200' M: world +M: 24 From a76702cb3631410194bf1e880c025e1255b81fa4 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 29 May 2013 17:01:26 +0200 Subject: [PATCH 31/63] make sure missing return values still warn --- tests/rassign.qc | 2 ++ tests/rassign.tmpl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/rassign.qc b/tests/rassign.qc index 69ec31c..f39b6ea 100644 --- a/tests/rassign.qc +++ b/tests/rassign.qc @@ -15,8 +15,10 @@ vector f_vector() { } string f_string() { +#ifndef FAIL_TEST return = "hello"; return = "world"; +#endif return; } diff --git a/tests/rassign.tmpl b/tests/rassign.tmpl index f169c82..948cb54 100644 --- a/tests/rassign.tmpl +++ b/tests/rassign.tmpl @@ -1,7 +1,7 @@ I: rassign.qc D: test return assignments T: -execute -C: -freturn-assignments +C: -fftepp -freturn-assignments M: 200 M: '200 200 200' M: world From ba781c53ef8722cf826607f8cd4c949febeab01d Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 29 May 2013 17:08:03 +0200 Subject: [PATCH 32/63] now a bare 'return;' is not required anymore if return has been assigned anywhere --- ast.c | 9 +++++++-- tests/rassign.qc | 2 -- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ast.c b/ast.c index 35b1a7d..81e1c12 100644 --- a/ast.c +++ b/ast.c @@ -1685,8 +1685,13 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) } else if (vec_size(self->curblock->entries) || self->curblock == irf->first) { - /* error("missing return"); */ - if (compile_warning(ast_ctx(self), WARN_MISSING_RETURN_VALUES, + if (self->return_value) { + cgen = self->return_value->expression.codegen; + if (!(*cgen)((ast_expression*)(self->return_value), self, false, &dummy)) + return false; + return ir_block_create_return(self->curblock, ast_ctx(self), dummy); + } + else if (compile_warning(ast_ctx(self), WARN_MISSING_RETURN_VALUES, "control reaches end of non-void function (`%s`) via %s", self->name, self->curblock->label)) { diff --git a/tests/rassign.qc b/tests/rassign.qc index f39b6ea..5c72e6f 100644 --- a/tests/rassign.qc +++ b/tests/rassign.qc @@ -25,8 +25,6 @@ string f_string() { float factorial(float n) { if (n == 0) return = 1; else return = n * factorial(n - 1); - - return; } void main() { From 0b6269f60712cb727956ad1be1114e7208a829a4 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Thu, 30 May 2013 19:36:01 +0000 Subject: [PATCH 33/63] column printing for warnings and errors now --- conout.c | 18 +++++++++--------- ftepp.c | 2 +- gmqcc.h | 5 +++-- lexer.c | 49 ++++++++++++++++++++++++++++++++----------------- lexer.h | 1 + opts.c | 2 +- test.c | 14 +++++++------- 7 files changed, 54 insertions(+), 37 deletions(-) diff --git a/conout.c b/conout.c index 2f72076..687fdf4 100644 --- a/conout.c +++ b/conout.c @@ -333,7 +333,7 @@ int con_out(const char *fmt, ...) { * for reporting of file:line based on lexer context, These are used * heavily in the parser/ir/ast. */ -static void con_vprintmsg_c(int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap, const char *condname) { +static void con_vprintmsg_c(int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap, const char *condname) { /* color selection table */ static int sel[] = { CON_WHITE, @@ -347,9 +347,9 @@ static void con_vprintmsg_c(int level, const char *name, size_t line, const char int (*vprint)(const char *, va_list) = (err) ? &con_verr : &con_vout; if (color) - print("\033[0;%dm%s:%d: \033[0;%dm%s: \033[0m", CON_CYAN, name, (int)line, sel[level], msgtype); + print("\033[0;%dm%s:%d:%d: \033[0;%dm%s: \033[0m", CON_CYAN, name, (int)line, (int)column, sel[level], msgtype); else - print("%s:%d: %s: ", name, (int)line, msgtype); + print("%s:%d:%d: %s: ", name, (int)line, (int)column, msgtype); vprint(msg, ap); if (condname) @@ -358,19 +358,19 @@ static void con_vprintmsg_c(int level, const char *name, size_t line, const char print("\n"); } -void con_vprintmsg(int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap) { - con_vprintmsg_c(level, name, line, msgtype, msg, ap, NULL); +void con_vprintmsg(int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap) { + con_vprintmsg_c(level, name, line, column, msgtype, msg, ap, NULL); } -void con_printmsg(int level, const char *name, size_t line, const char *msgtype, const char *msg, ...) { +void con_printmsg(int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...) { va_list va; va_start(va, msg); - con_vprintmsg(level, name, line, msgtype, msg, va); + con_vprintmsg(level, name, line, column, msgtype, msg, va); va_end (va); } void con_cvprintmsg(void *ctx, int lvl, const char *msgtype, const char *msg, va_list ap) { - con_vprintmsg(lvl, ((lex_ctx*)ctx)->file, ((lex_ctx*)ctx)->line, msgtype, msg, ap); + con_vprintmsg(lvl, ((lex_ctx*)ctx)->file, ((lex_ctx*)ctx)->line, ((lex_ctx*)ctx)->column, msgtype, msg, ap); } void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, ...) { @@ -432,7 +432,7 @@ bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_ lvl = LVL_ERROR; } - con_vprintmsg_c(lvl, ctx.file, ctx.line, msgtype, fmt, ap, warn_name); + con_vprintmsg_c(lvl, ctx.file, ctx.line, ctx.column, msgtype, fmt, ap, warn_name); return OPTS_WERROR(warntype) && OPTS_FLAG(BAIL_ON_WERROR); } diff --git a/ftepp.c b/ftepp.c index f8d41d9..5348dfb 100644 --- a/ftepp.c +++ b/ftepp.c @@ -1881,7 +1881,7 @@ ftepp_t *ftepp_create() void ftepp_add_define(ftepp_t *ftepp, const char *source, const char *name) { ppmacro *macro; - lex_ctx ctx = { "__builtin__", 0 }; + lex_ctx ctx = { "__builtin__", 0, 0 }; ctx.file = source; macro = ppmacro_new(ctx, name); /*vec_push(ftepp->macros, macro);*/ diff --git a/gmqcc.h b/gmqcc.h index 3b221e9..a92e109 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -749,6 +749,7 @@ void code_pop_statement (code_t *); typedef struct { const char *file; size_t line; + size_t column; } lex_ctx; /*===================================================================*/ @@ -775,8 +776,8 @@ enum { FILE *con_default_out(); FILE *con_default_err(); -void con_vprintmsg (int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap); -void con_printmsg (int level, const char *name, size_t line, const char *msgtype, const char *msg, ...); +void con_vprintmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap); +void con_printmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...); void con_cvprintmsg(void *ctx, int lvl, const char *msgtype, const char *msg, va_list ap); void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, ...); diff --git a/lexer.c b/lexer.c index 035dc1b..862131e 100644 --- a/lexer.c +++ b/lexer.c @@ -66,9 +66,9 @@ static void lexerror(lex_file *lex, const char *fmt, ...) va_start(ap, fmt); if (lex) - con_vprintmsg(LVL_ERROR, lex->name, lex->sline, "parse error", fmt, ap); + con_vprintmsg(LVL_ERROR, lex->name, lex->sline, lex->column, "parse error", fmt, ap); else - con_vprintmsg(LVL_ERROR, "", 0, "parse error", fmt, ap); + con_vprintmsg(LVL_ERROR, "", 0, 0, "parse error", fmt, ap); va_end(ap); } @@ -174,9 +174,11 @@ static void lex_token_new(lex_file *lex) #else if (lex->tok.value) vec_shrinkto(lex->tok.value, 0); + lex->tok.constval.t = 0; - lex->tok.ctx.line = lex->sline; - lex->tok.ctx.file = lex->name; + lex->tok.ctx.line = lex->sline; + lex->tok.ctx.file = lex->name; + lex->tok.ctx.column = lex->column; #endif } #endif @@ -200,12 +202,12 @@ lex_file* lex_open(const char *file) memset(lex, 0, sizeof(*lex)); - lex->file = in; - lex->name = util_strdup(file); - lex->line = 1; /* we start counting at 1 */ - + lex->file = in; + lex->name = util_strdup(file); + lex->line = 1; /* we start counting at 1 */ + lex->column = 0; lex->peekpos = 0; - lex->eof = false; + lex->eof = false; vec_push(lex_filenames, lex->name); return lex; @@ -228,11 +230,11 @@ lex_file* lex_open_string(const char *str, size_t len, const char *name) lex->open_string_length = len; lex->open_string_pos = 0; - lex->name = util_strdup(name ? name : ""); - lex->line = 1; /* we start counting at 1 */ - + lex->name = util_strdup(name ? name : ""); + lex->line = 1; /* we start counting at 1 */ lex->peekpos = 0; - lex->eof = false; + lex->eof = false; + lex->column = 0; vec_push(lex_filenames, lex->name); @@ -271,11 +273,14 @@ void lex_close(lex_file *lex) static int lex_fgetc(lex_file *lex) { - if (lex->file) + if (lex->file) { + lex->column++; return fs_file_getc(lex->file); + } if (lex->open_string) { if (lex->open_string_pos >= lex->open_string_length) return EOF; + lex->column++; return lex->open_string[lex->open_string_pos++]; } return EOF; @@ -291,16 +296,22 @@ static int lex_try_trigraph(lex_file *lex, int old) { int c2, c3; c2 = lex_fgetc(lex); - if (!lex->push_line && c2 == '\n') + if (!lex->push_line && c2 == '\n') { lex->line++; + lex->column = 0; + } + if (c2 != '?') { lex_ungetch(lex, c2); return old; } c3 = lex_fgetc(lex); - if (!lex->push_line && c3 == '\n') + if (!lex->push_line && c3 == '\n') { lex->line++; + lex->column = 0; + } + switch (c3) { case '=': return '#'; case '/': return '\\'; @@ -365,8 +376,11 @@ static int lex_getch(lex_file *lex) static void lex_ungetch(lex_file *lex, int ch) { lex->peek[lex->peekpos++] = ch; - if (!lex->push_line && ch == '\n') + lex->column--; + if (!lex->push_line && ch == '\n') { lex->line--; + lex->column = 0; + } } /* classify characters @@ -872,6 +886,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) ch = 0; else { --u8len; + lex->column += u8len; for (uc = 0; uc < u8len; ++uc) lex_tokench(lex, u8buf[uc]); /* the last character will be inserted with the tokench() call diff --git a/lexer.h b/lexer.h index 5f0bb63..cde0863 100644 --- a/lexer.h +++ b/lexer.h @@ -114,6 +114,7 @@ typedef struct lex_file_s { char *name; size_t line; size_t sline; /* line at the start of a token */ + size_t column; int peek[256]; size_t peekpos; diff --git a/opts.c b/opts.c index 77aa9c0..abd012f 100644 --- a/opts.c +++ b/opts.c @@ -361,7 +361,7 @@ void opts_ini_init(const char *file) { if ((line = opts_ini_parse(ini, &opts_ini_load, &error)) != 0) { /* there was a parse error with the ini file */ - con_printmsg(LVL_ERROR, file, line, "error", error); + con_printmsg(LVL_ERROR, file, line, 0 /*TODO: column for ini error*/, "error", error); vec_free(error); } diff --git a/test.c b/test.c index 2febbff..6682983 100644 --- a/test.c +++ b/test.c @@ -297,7 +297,7 @@ static bool task_template_generate(task_template_t *tmpl, char tag, const char * case 'I': destval = &tmpl->sourcefile; break; case 'F': destval = &tmpl->testflags; break; default: - con_printmsg(LVL_ERROR, __FILE__, __LINE__, "internal error", + con_printmsg(LVL_ERROR, __FILE__, __LINE__, 0, "internal error", "invalid tag `%c:` during code generation\n", tag ); @@ -309,7 +309,7 @@ static bool task_template_generate(task_template_t *tmpl, char tag, const char * * assigned value. */ if (*destval) { - con_printmsg(LVL_ERROR, file, line, "compile error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "compile error", "tag `%c:` already assigned value: %s\n", tag, *destval ); @@ -377,7 +377,7 @@ static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *f */ case '/': if (data[1] != '/') { - con_printmsg(LVL_ERROR, file, line, "tmpl parse error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error", "invalid character `/`, perhaps you meant `//` ?"); mem_d(back); @@ -407,14 +407,14 @@ static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *f case 'I': case 'F': if (data[1] != ':') { - con_printmsg(LVL_ERROR, file, line, "tmpl parse error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error", "expected `:` after `%c`", *data ); goto failure; } if (!task_template_generate(tmpl, *data, file, line, &data[3], pad)) { - con_printmsg(LVL_ERROR, file, line, "tmpl compile error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl compile error", "failed to generate for given task\n" ); goto failure; @@ -429,7 +429,7 @@ static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *f { char *value = &data[3]; if (data[1] != ':') { - con_printmsg(LVL_ERROR, file, line, "tmpl parse error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error", "expected `:` after `%c`", *data ); @@ -454,7 +454,7 @@ static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *f } default: - con_printmsg(LVL_ERROR, file, line, "tmpl parse error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error", "invalid tag `%c`", *data ); goto failure; From 062180e9a8578ffbbf941154f2c4fd43163d2ca4 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sat, 1 Jun 2013 20:18:53 +0000 Subject: [PATCH 34/63] Fix some possible memleaks. --- parser.c | 11 +++++++---- util.c | 3 +-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/parser.c b/parser.c index 97a3ccb..14d58b6 100644 --- a/parser.c +++ b/parser.c @@ -5060,6 +5060,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va /* parse on */ if (!parser_next(parser)) { ast_delete(var); + mem_d(name); parseerror(parser, "error after variable or field declaration"); return NULL; } @@ -5069,8 +5070,10 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va if (parser->tok == '[') { wasarray = true; var = parse_arraysize(parser, var); - if (!var) + if (!var) { + if (name) mem_d(name); return NULL; + } } /* This is the point where we can turn it into a field */ @@ -5089,8 +5092,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va while (parser->tok == '(') { var = parse_parameter_list(parser, var); if (!var) { - if (name) - mem_d((void*)name); + if (name) mem_d(name); return NULL; } } @@ -5099,11 +5101,12 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va if (name) { if (!ast_value_set_name(var, name)) { ast_delete(var); + mem_d(name); parseerror(parser, "internal error: failed to set name"); return NULL; } /* free the name, ast_value_set_name duplicates */ - mem_d((void*)name); + mem_d(name); } return var; diff --git a/util.c b/util.c index d695ae6..54f8d56 100644 --- a/util.c +++ b/util.c @@ -170,7 +170,6 @@ static void util_dumpmem(struct memblock_t *memory, uint16_t cols) { void util_meminfo() { struct memblock_t *info; - if (OPTS_OPTION_BOOL(OPTION_DEBUG)) { for (info = mem_start; info; info = info->next) { con_out("lost: %u (bytes) at %s:%u\n", @@ -178,7 +177,7 @@ void util_meminfo() { info->file, info->line); - util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)); + util_dumpmem(info + 1, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)); } } From 655822ec1a4024c7ae75433f6e75b20d07141d33 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sat, 1 Jun 2013 20:20:25 +0000 Subject: [PATCH 35/63] Doh --- util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.c b/util.c index 54f8d56..92e0133 100644 --- a/util.c +++ b/util.c @@ -177,7 +177,7 @@ void util_meminfo() { info->file, info->line); - util_dumpmem(info + 1, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)); + util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)); } } From d85e86141c3599004564475a6788db359d693be7 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Sat, 1 Jun 2013 22:25:58 +0200 Subject: [PATCH 36/63] fix a leak on a parse-error --- parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/parser.c b/parser.c index 14d58b6..bedef2b 100644 --- a/parser.c +++ b/parser.c @@ -4793,6 +4793,7 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) /* for the sake of less code we parse-in in this function */ if (!parser_next(parser)) { + ast_delete(var); parseerror(parser, "expected parameter list"); return NULL; } From 280dfdd3f807532935217722aa9ac74e8194ef5d Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 00:03:27 +0000 Subject: [PATCH 37/63] Add statistics for vector usage to the output. Step one in lowering memory usage. ONE FUCKING MILLION VECTORS for XONOTIC.. --- util.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/util.c b/util.c index 92e0133..891082b 100644 --- a/util.c +++ b/util.c @@ -166,7 +166,7 @@ static void util_dumpmem(struct memblock_t *memory, uint16_t cols) { } } } - +static uint64_t vectors = 0; void util_meminfo() { struct memblock_t *info; @@ -180,6 +180,10 @@ void util_meminfo() { util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)); } } + + con_out("Additional Statistics:\n Total vectors used: %lu\n", + vectors + ); if (OPTS_OPTION_BOOL(OPTION_DEBUG) || OPTS_OPTION_BOOL(OPTION_MEMCHK)) { @@ -434,13 +438,20 @@ size_t util_strtononcmd(const char *in, char *out, size_t outsz) { /* TODO: rewrite ... when I redo the ve cleanup */ void _util_vec_grow(void **a, size_t i, size_t s) { vector_t *d = vec_meta(*a); - size_t m = *a ? 2 * d->allocated +i : i+1; - void *p = mem_r((*a ? d : NULL), s * m + sizeof(vector_t)); + size_t m = 0; + void *p = NULL; - if (!*a) + if (*a) { + m = 2 * d->allocated + i; + p = mem_r(d, s * m + sizeof(vector_t)); + } else { + m = i + 1; + p = mem_a(s * m + sizeof(vector_t)); ((vector_t*)p)->used = 0; - *a = (vector_t*)p + 1; + vectors++; + } + *a = (vector_t*)p + 1; vec_meta(*a)->allocated = m; } From 121e0806979160e9236cd6cc6173fe76db3f2349 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 00:07:54 +0000 Subject: [PATCH 38/63] Guart statistics by option. --- main.c | 1 + opts.def | 1 + util.c | 8 +++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/main.c b/main.c index 840a6a7..4eb5eb3 100644 --- a/main.c +++ b/main.c @@ -173,6 +173,7 @@ static bool options_parse(int argc, char **argv) { OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_GMQCC; + OPTS_OPTION_BOOL(OPTION_STATISTICS) = true; } else if (!strcmp(argarg, "qcc")) { diff --git a/opts.def b/opts.def index 520f9b9..77a4094 100644 --- a/opts.def +++ b/opts.def @@ -121,6 +121,7 @@ GMQCC_DEFINE_FLAG(MAX_ARRAY_SIZE) GMQCC_DEFINE_FLAG(ADD_INFO) GMQCC_DEFINE_FLAG(CORRECTION) + GMQCC_DEFINE_FLAG(STATISTICS) #endif /* some cleanup so we don't have to */ diff --git a/util.c b/util.c index 891082b..c19bbaf 100644 --- a/util.c +++ b/util.c @@ -181,9 +181,11 @@ void util_meminfo() { } } - con_out("Additional Statistics:\n Total vectors used: %lu\n", - vectors - ); + if (OPTS_OPTION_BOOL(OPTION_STATISTICS)) { + con_out("Additional Statistics:\n Total vectors used: %lu\n", + vectors + ); + } if (OPTS_OPTION_BOOL(OPTION_DEBUG) || OPTS_OPTION_BOOL(OPTION_MEMCHK)) { From 166b79720cfaea0e361d052a9da35640b67cf327 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 04:29:53 +0000 Subject: [PATCH 39/63] Vector tracing, step two in determining how to lower memory usage. --- main.c | 2 + util.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 113 insertions(+), 11 deletions(-) diff --git a/main.c b/main.c index 4eb5eb3..3ac055d 100644 --- a/main.c +++ b/main.c @@ -797,5 +797,7 @@ cleanup: lex_cleanup(); util_meminfo(); + /*util_vecstats_destroy();*/ + return retval; } diff --git a/util.c b/util.c index c19bbaf..cc82569 100644 --- a/util.c +++ b/util.c @@ -166,7 +166,52 @@ static void util_dumpmem(struct memblock_t *memory, uint16_t cols) { } } } -static uint64_t vectors = 0; + +/* + * The following is a VERY tight, efficent, hashtable for integer + * values and keys, and for nothing more. We could make our existing + * hashtable support type-genericness through a void * pointer but, + * ideally that would make things more complicated. We also don't need + * that much of a bloat for something as basic as this. + */ +typedef struct { + size_t key; + size_t value; +} size_entry_t; +#define ST_SIZE 1024 + +typedef size_entry_t **size_table_t; + +size_table_t util_st_new() { + return (size_table_t)memset( + mem_a(sizeof(size_entry_t*) * ST_SIZE), + 0, ST_SIZE * sizeof(size_entry_t*) + ); +} +void util_st_del(size_table_t table) { + size_t i = 0; + for (; i < ST_SIZE; i++) if(table[i]) mem_d(table[i]); + mem_d(table); +} +size_entry_t *util_st_get(size_table_t table, size_t key) { + size_t hash = (key % ST_SIZE); + while (table[hash] && table[hash]->key != key) + hash = (hash + 1) % ST_SIZE; + return table[hash]; +} +void util_st_put(size_table_t table, size_t key, size_t value) { + size_t hash = (key % ST_SIZE); + while (table[hash] && table[hash]->key != key) + hash = (hash + 1) % ST_SIZE; + table[hash] = (size_entry_t*)mem_a(sizeof(size_entry_t)); + table[hash]->key = key; + table[hash]->value = value; +} + +static uint64_t vectors = 0; +static uint64_t vector_sizes = 0; +static size_table_t vector_usage = NULL; + void util_meminfo() { struct memblock_t *info; @@ -180,12 +225,6 @@ void util_meminfo() { util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)); } } - - if (OPTS_OPTION_BOOL(OPTION_STATISTICS)) { - con_out("Additional Statistics:\n Total vectors used: %lu\n", - vectors - ); - } if (OPTS_OPTION_BOOL(OPTION_DEBUG) || OPTS_OPTION_BOOL(OPTION_MEMCHK)) { @@ -207,6 +246,34 @@ void util_meminfo() { (mem_at - mem_dt) ); } + + if (OPTS_OPTION_BOOL(OPTION_STATISTICS) || + OPTS_OPTION_BOOL(OPTION_MEMCHK)) { + size_t i; + + con_out("Additional Statistics:\n\ + Total vectors used: %u\n\ + Total unique vector sizes: %u\n", + (unsigned)vectors, + (unsigned)vector_sizes + ); + + /* TODO: */ + for (i = 0; i < ST_SIZE; i++) { + size_entry_t *entry; + + if (!(entry = vector_usage[i])) + continue; + + con_out(" # of %3u (bytes) vectors: %u\n", + (unsigned)entry->key, + (unsigned)entry->value + ); + } + } + + if (vector_usage) + util_st_del(vector_usage); } /* @@ -439,10 +506,11 @@ size_t util_strtononcmd(const char *in, char *out, size_t outsz) { /* TODO: rewrite ... when I redo the ve cleanup */ void _util_vec_grow(void **a, size_t i, size_t s) { - vector_t *d = vec_meta(*a); - size_t m = 0; - void *p = NULL; - + vector_t *d = vec_meta(*a); + size_t m = 0; + size_entry_t *e = NULL; + void *p = NULL; + if (*a) { m = 2 * d->allocated + i; p = mem_r(d, s * m + sizeof(vector_t)); @@ -452,6 +520,16 @@ void _util_vec_grow(void **a, size_t i, size_t s) { ((vector_t*)p)->used = 0; vectors++; } + + if (!vector_usage) + vector_usage = util_st_new(); + + if ((e = util_st_get(vector_usage, s))) { + e->value ++; + } else { + util_st_put(vector_usage, s, 1); /* start off with 1 */ + vector_sizes++; + } *a = (vector_t*)p + 1; vec_meta(*a)->allocated = m; @@ -654,6 +732,28 @@ void util_htrem(hash_table_t *ht, void (*callback)(void *data)) { mem_d(ht); } +void util_htremkey(hash_table_t *ht, void (*callback)(void *data, const char *key)) { + size_t i = 0; + for (; i < ht->size; i++) { + hash_node_t *n = ht->table[i]; + hash_node_t *p; + + /* free in list */ + while (n) { + if (callback) + callback(n->value, n->key); + mem_d(n->key); + p = n; + n = n->next; + mem_d(p); + } + + } + /* free table */ + mem_d(ht->table); + mem_d(ht); +} + void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) { hash_node_t **pair = &ht->table[bin]; hash_node_t *tmp; From c8daf483f3453c4c57380d3530570abbb6b6173e Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 04:32:20 +0000 Subject: [PATCH 40/63] This was an experiment that snuk it's way inside that commit. --- util.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/util.c b/util.c index cc82569..3e81a51 100644 --- a/util.c +++ b/util.c @@ -732,28 +732,6 @@ void util_htrem(hash_table_t *ht, void (*callback)(void *data)) { mem_d(ht); } -void util_htremkey(hash_table_t *ht, void (*callback)(void *data, const char *key)) { - size_t i = 0; - for (; i < ht->size; i++) { - hash_node_t *n = ht->table[i]; - hash_node_t *p; - - /* free in list */ - while (n) { - if (callback) - callback(n->value, n->key); - mem_d(n->key); - p = n; - n = n->next; - mem_d(p); - } - - } - /* free table */ - mem_d(ht->table); - mem_d(ht); -} - void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) { hash_node_t **pair = &ht->table[bin]; hash_node_t *tmp; From 79a7aa70b9b09d54e2257afc0d9efea59a408849 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 04:38:20 +0000 Subject: [PATCH 41/63] Track strdups too in the statistics --- util.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/util.c b/util.c index 3e81a51..351aba6 100644 --- a/util.c +++ b/util.c @@ -208,6 +208,7 @@ void util_st_put(size_table_t table, size_t key, size_t value) { table[hash]->value = value; } +static uint64_t strdups = 0; static uint64_t vectors = 0; static uint64_t vector_sizes = 0; static size_table_t vector_usage = NULL; @@ -249,26 +250,30 @@ void util_meminfo() { if (OPTS_OPTION_BOOL(OPTION_STATISTICS) || OPTS_OPTION_BOOL(OPTION_MEMCHK)) { - size_t i; + size_t i=0; + size_t e=1; con_out("Additional Statistics:\n\ - Total vectors used: %u\n\ + Total vectors allocated: %u\n\ + Total string duplicates: %u\n\ Total unique vector sizes: %u\n", (unsigned)vectors, + (unsigned)strdups, (unsigned)vector_sizes ); - /* TODO: */ - for (i = 0; i < ST_SIZE; i++) { + for (; i < ST_SIZE; i++) { size_entry_t *entry; if (!(entry = vector_usage[i])) continue; - con_out(" # of %3u (bytes) vectors: %u\n", + con_out(" %u| # of %3u (bytes) vectors: %u\n", + (unsigned)e, (unsigned)entry->key, (unsigned)entry->value ); + e++; } } @@ -295,6 +300,7 @@ char *_util_Estrdup(const char *s, const char *file, size_t line) { memcpy(ptr, s, len); ptr[len] = '\0'; } + strdups++; return ptr; } @@ -314,6 +320,7 @@ char *_util_Estrdup_empty(const char *s, const char *file, size_t line) { memcpy(ptr, s, len); ptr[len] = '\0'; } + strdups++; return ptr; } From f884bd2217992c92f20b1bab5dcdbc20de3de068 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 04:45:04 +0000 Subject: [PATCH 42/63] Track hashtables too --- util.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/util.c b/util.c index 351aba6..2151547 100644 --- a/util.c +++ b/util.c @@ -211,6 +211,7 @@ void util_st_put(size_table_t table, size_t key, size_t value) { static uint64_t strdups = 0; static uint64_t vectors = 0; static uint64_t vector_sizes = 0; +static uint64_t hashtables = 0; static size_table_t vector_usage = NULL; void util_meminfo() { @@ -254,12 +255,14 @@ void util_meminfo() { size_t e=1; con_out("Additional Statistics:\n\ - Total vectors allocated: %u\n\ - Total string duplicates: %u\n\ - Total unique vector sizes: %u\n", - (unsigned)vectors, - (unsigned)strdups, - (unsigned)vector_sizes + Total vectors allocated: %llu\n\ + Total string duplicates: %llu\n\ + Total hashtables allocated: %llu\n\ + Total unique vector sizes: %llu\n", + vectors, + strdups, + hashtables, + vector_sizes ); for (; i < ST_SIZE; i++) { @@ -627,6 +630,7 @@ hash_table_t *util_htnew(size_t size) { hashtable->size = size; memset(hashtable->table, 0, sizeof(hash_node_t*) * size); + hashtables++; return hashtable; } From 1ce8d2ea6e9432cfddc4f78e711b9c8bcb8f3e0b Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 05:09:28 +0000 Subject: [PATCH 43/63] Hashtable statistics too --- util.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/util.c b/util.c index 2151547..ae95df5 100644 --- a/util.c +++ b/util.c @@ -208,11 +208,13 @@ void util_st_put(size_table_t table, size_t key, size_t value) { table[hash]->value = value; } -static uint64_t strdups = 0; -static uint64_t vectors = 0; -static uint64_t vector_sizes = 0; -static uint64_t hashtables = 0; -static size_table_t vector_usage = NULL; +static uint64_t strdups = 0; +static uint64_t vectors = 0; +static uint64_t vector_sizes = 0; +static uint64_t hashtables = 0; +static uint64_t hashtable_sizes = 0; +static size_table_t vector_usage = NULL; +static size_table_t hashtable_usage = NULL; void util_meminfo() { struct memblock_t *info; @@ -251,14 +253,15 @@ void util_meminfo() { if (OPTS_OPTION_BOOL(OPTION_STATISTICS) || OPTS_OPTION_BOOL(OPTION_MEMCHK)) { - size_t i=0; - size_t e=1; + size_t i = 0; + size_t e = 1; + uint64_t vectormem = 0; - con_out("Additional Statistics:\n\ - Total vectors allocated: %llu\n\ - Total string duplicates: %llu\n\ - Total hashtables allocated: %llu\n\ - Total unique vector sizes: %llu\n", + con_out("\nAdditional Statistics:\n\ + Total vectors allocated: %llu\n\ + Total string duplicates: %llu\n\ + Total hashtables allocated: %llu\n\ + Total unique vector sizes: %llu\n", vectors, strdups, hashtables, @@ -271,17 +274,44 @@ void util_meminfo() { if (!(entry = vector_usage[i])) continue; - con_out(" %u| # of %3u (bytes) vectors: %u\n", + con_out(" %2u| # of %4u byte vectors: %u\n", + (unsigned)e, + (unsigned)entry->key, + (unsigned)entry->value + ); + e++; + + vectormem += entry->key * entry->value; + } + + con_out("\ + Total unique hashtable sizes: %llu\n", + hashtable_sizes + ); + + for (i = 0, e = 1; i < ST_SIZE; i++) { + size_entry_t *entry; + + if (!(entry = hashtable_usage[i])) + continue; + + con_out(" %2u| # of %4u element hashtables: %u\n", (unsigned)e, (unsigned)entry->key, (unsigned)entry->value ); e++; } + + con_out(" Total vector memory: %f (MB)\n", + (float)(vectormem) / 1048576.0f + ); } - + if (vector_usage) util_st_del(vector_usage); + if (hashtable_usage) + util_st_del(hashtable_usage); } /* @@ -616,8 +646,13 @@ static hash_node_t *_util_htnewpair(const char *key, void *value) { */ hash_table_t *util_htnew(size_t size) { hash_table_t *hashtable = NULL; + size_entry_t *find; + if (size < 1) return NULL; + + if (!hashtable_usage) + hashtable_usage = util_st_new(); if (!(hashtable = (hash_table_t*)mem_a(sizeof(hash_table_t)))) return NULL; @@ -626,6 +661,13 @@ hash_table_t *util_htnew(size_t size) { mem_d(hashtable); return NULL; } + + if ((find = util_st_get(hashtable_usage, size))) + find->value++; + else { + hashtable_sizes++; + util_st_put(hashtable_usage, size, 1); + } hashtable->size = size; memset(hashtable->table, 0, sizeof(hash_node_t*) * size); From ec7bf4767aa30808b0b64be00d7455f3bcecde4b Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 05:32:37 +0000 Subject: [PATCH 44/63] Some static --- util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util.c b/util.c index ae95df5..3dcf873 100644 --- a/util.c +++ b/util.c @@ -182,24 +182,24 @@ typedef struct { typedef size_entry_t **size_table_t; -size_table_t util_st_new() { +static size_table_t util_st_new() { return (size_table_t)memset( mem_a(sizeof(size_entry_t*) * ST_SIZE), 0, ST_SIZE * sizeof(size_entry_t*) ); } -void util_st_del(size_table_t table) { +static void util_st_del(size_table_t table) { size_t i = 0; for (; i < ST_SIZE; i++) if(table[i]) mem_d(table[i]); mem_d(table); } -size_entry_t *util_st_get(size_table_t table, size_t key) { +static size_entry_t *util_st_get(size_table_t table, size_t key) { size_t hash = (key % ST_SIZE); while (table[hash] && table[hash]->key != key) hash = (hash + 1) % ST_SIZE; return table[hash]; } -void util_st_put(size_table_t table, size_t key, size_t value) { +static void util_st_put(size_table_t table, size_t key, size_t value) { size_t hash = (key % ST_SIZE); while (table[hash] && table[hash]->key != key) hash = (hash + 1) % ST_SIZE; From 9af3c502dae7420714519dd13dff6aba40fc1fa3 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 08:21:06 +0000 Subject: [PATCH 45/63] Major utility rewrite for compiler memory utilization statistics. Cleanups everywhere, no more NOTRACK stuff, all allocates are tracked. Major identifier cleanups as well. --- Makefile | 11 +- gmqcc.h | 57 +++--- main.c | 5 +- pak.c | 5 +- stat.c | 590 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ test.c | 2 +- util.c | 600 ------------------------------------------------------- 7 files changed, 636 insertions(+), 634 deletions(-) create mode 100644 stat.c diff --git a/Makefile b/Makefile index fea3356..a1c08f9 100644 --- a/Makefile +++ b/Makefile @@ -44,11 +44,11 @@ ifeq ($(track), no) CFLAGS += -DNOTRACK endif -OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o -OBJ_P = util.o fs.o conout.o opts.o pak.o -OBJ_T = test.o util.o conout.o fs.o -OBJ_C = main.o lexer.o parser.o fs.o -OBJ_X = exec-standalone.o util.o conout.o fs.o +OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o stat.o +OBJ_P = util.o fs.o conout.o opts.o pak.o stat.o +OBJ_T = test.o util.o conout.o fs.o stat.o +OBJ_C = main.o lexer.o parser.o fs.o stat.o +OBJ_X = exec-standalone.o util.o conout.o fs.o stat.o #we have duplicate object files when dealing with creating a simple list #for dependinces. To combat this we use some clever recrusive-make to @@ -244,6 +244,7 @@ opts.o: gmqcc.h opts.def fs.o: gmqcc.h opts.def utf8.o: gmqcc.h opts.def correct.o: gmqcc.h opts.def +stat.o: gmqcc.h opts.def pak.o: gmqcc.h opts.def test.o: gmqcc.h opts.def main.o: gmqcc.h opts.def lexer.h diff --git a/gmqcc.h b/gmqcc.h index a92e109..8edcbda 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -288,20 +288,47 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # include #endif /*! _WIN32 && !defined(__MINGW32__) */ +/*===================================================================*/ +/*=========================== stat.c ================================*/ +/*===================================================================*/ +typedef struct { + size_t key; + size_t value; +} stat_size_entry_t, **stat_size_table_t; + +void stat_info(); + +char *stat_mem_strdup (const char *, size_t, const char *, bool); +void *stat_mem_reallocate(void *, size_t, size_t, const char *); +void stat_mem_deallocate(void *); +void *stat_mem_allocate (size_t, size_t, const char *); + +stat_size_table_t stat_size_new(); +stat_size_entry_t *stat_size_get(stat_size_table_t, size_t); +void stat_size_del(stat_size_table_t); +void stat_size_put(stat_size_table_t, size_t, size_t); + +/* getters for hashtable: */ +stat_size_table_t *stat_size_hashtables_get(); +uint64_t *stat_type_hashtables_get(); +uint64_t *stat_used_hashtables_get(); +stat_size_table_t *stat_hashtables_init(); + +#define mem_a(SIZE) stat_mem_allocate ((SIZE), __LINE__, __FILE__) +#define mem_d(PTRN) stat_mem_deallocate((void*)(PTRN)) +#define mem_r(PTRN, SIZE) stat_mem_reallocate((void*)(PTRN), (SIZE), __LINE__, __FILE__) +#define mem_af(SIZE, FILE, LINE) stat_mem_allocate ((SIZE), (LINE), (FILE)) + +/* TODO: rename to mem variations */ +#define util_strdup(SRC) stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, false) +#define util_strdupe(SRC) stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, true) /*===================================================================*/ /*=========================== util.c ================================*/ /*===================================================================*/ -void *util_memory_a (size_t, /*****/ unsigned int, const char *); -void *util_memory_r (void *, size_t, unsigned int, const char *); -void util_memory_d (void *); -void util_meminfo (); - bool util_filexists (const char *); bool util_strupper (const char *); bool util_strdigit (const char *); -char *_util_Estrdup (const char *, const char *, size_t); -char *_util_Estrdup_empty(const char *, const char *, size_t); void util_debug (const char *, const char *, ...); void util_endianswap (void *, size_t, unsigned int); @@ -326,22 +353,6 @@ 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); - -#ifdef NOTRACK -# define mem_a(x) malloc (x) -# define mem_d(x) free ((void*)x) -# define mem_r(x, n) realloc((void*)x, n) -# define mem_af(x,f,l) malloc (x) -#else -# define mem_a(x) util_memory_a((x), __LINE__, __FILE__) -# define mem_d(x) util_memory_d((void*)(x)) -# define mem_r(x, n) util_memory_r((void*)(x), (n), __LINE__, __FILE__) -# define mem_af(x,f,l) util_memory_a((x), __LINE__, __FILE__) -#endif /*! NOTRACK */ - -#define util_strdup(X) _util_Estrdup((X), __FILE__, __LINE__) -#define util_strdupe(X) _util_Estrdup_empty((X), __FILE__, __LINE__) - /* * A flexible vector implementation: all vector pointers contain some * data about themselfs exactly - sizeof(vector_t) behind the pointer diff --git a/main.c b/main.c index 3ac055d..5717fb5 100644 --- a/main.c +++ b/main.c @@ -796,8 +796,7 @@ cleanup: mem_d((void*)operators); lex_cleanup(); - util_meminfo(); - /*util_vecstats_destroy();*/ - + stat_info(); + return retval; } diff --git a/pak.c b/pak.c index 9ff7e78..ac31bdf 100644 --- a/pak.c +++ b/pak.c @@ -552,7 +552,8 @@ int main(int argc, char **argv) { /* not possible */ pak_close(pak); vec_free(files); - util_meminfo(); + stat_info(); + return EXIT_SUCCESS; } @@ -575,6 +576,6 @@ int main(int argc, char **argv) { pak_close(pak); vec_free(files); - util_meminfo(); + stat_info(); return EXIT_SUCCESS; } diff --git a/stat.c b/stat.c new file mode 100644 index 0000000..7747763 --- /dev/null +++ b/stat.c @@ -0,0 +1,590 @@ +#include "gmqcc.h" + +/* + * GMQCC performs tons of allocations, constructions, and crazyness + * all around. When trying to optimizes systems, or just get fancy + * statistics out of the compiler, it's often printf mess. This file + * implements the statistics system of the compiler. I.E the allocator + * we use to track allocations, and other systems of interest. + */ +#define ST_SIZE 1024 + +typedef struct stat_mem_block_s { + const char *file; + size_t line; + size_t size; + struct stat_mem_block_s *next; + struct stat_mem_block_s *prev; +} stat_mem_block_t; + +static uint64_t stat_mem_allocated = 0; +static uint64_t stat_mem_deallocated = 0; +static uint64_t stat_mem_allocated_total = 0; +static uint64_t stat_mem_deallocated_total = 0; +static uint64_t stat_mem_high = 0; +static uint64_t stat_mem_peak = 0; +static uint64_t stat_used_strdups = 0; +static uint64_t stat_used_vectors = 0; +static uint64_t stat_used_hashtables = 0; +static uint64_t stat_type_vectors = 0; +static uint64_t stat_type_hashtables = 0; +static stat_size_table_t stat_size_vectors = NULL; +static stat_size_table_t stat_size_hashtables = NULL; +static stat_mem_block_t *stat_mem_block_root = NULL; + +/* + * A basic header of information wrapper allocator. Simply stores + * information as a header, returns the memory + 1 past it, can be + * retrieved again with - 1. Where type is stat_mem_block_t*. + */ +void *stat_mem_allocate(size_t size, size_t line, const char *file) { + stat_mem_block_t *info = (stat_mem_block_t*)malloc(sizeof(stat_mem_block_t) + size); + void *data = (void*)(info + 1); + + if(!info) + return NULL; + + info->line = line; + info->size = size; + info->file = file; + info->prev = NULL; + info->next = stat_mem_block_root; + + if (stat_mem_block_root) + stat_mem_block_root->prev = info; + + stat_mem_block_root = info; + stat_mem_allocated += size; + stat_mem_high += size; + stat_mem_allocated_total ++; + + if (stat_mem_high > stat_mem_peak) + stat_mem_peak = stat_mem_high; + + return data; +} + +void stat_mem_deallocate(void *ptr) { + stat_mem_block_t *info = NULL; + + if (!ptr) + return; + + info = ((stat_mem_block_t*)ptr - 1); + + stat_mem_deallocated += info->size; + stat_mem_high -= info->size; + stat_mem_deallocated_total ++; + + if (info->prev) info->prev->next = info->next; + if (info->next) info->next->prev = info->prev; + + /* move ahead */ + if (info == stat_mem_block_root) + stat_mem_block_root = info->next; +} + +void *stat_mem_reallocate(void *ptr, size_t size, size_t line, const char *file) { + stat_mem_block_t *oldinfo = NULL; + stat_mem_block_t *newinfo; + + if (!ptr) + return stat_mem_allocate(size, line, file); + + /* stay consistent with glic */ + if (!size) { + stat_mem_deallocate(ptr); + return NULL; + } + + oldinfo = ((stat_mem_block_t*)ptr - 1); + newinfo = ((stat_mem_block_t*)malloc(sizeof(stat_mem_block_t) + size)); + + if (!newinfo) { + stat_mem_deallocate(ptr); + return NULL; + } + + memcpy(newinfo+1, oldinfo+1, oldinfo->size); + + if (oldinfo->prev) oldinfo->prev->next = oldinfo->next; + if (oldinfo->next) oldinfo->next->prev = oldinfo->prev; + + /* move ahead */ + if (oldinfo == stat_mem_block_root) + stat_mem_block_root = oldinfo->next; + + newinfo->line = line; + newinfo->size = size; + newinfo->file = file; + newinfo->prev = NULL; + newinfo->next = stat_mem_block_root; + + if (stat_mem_block_root) + stat_mem_block_root->prev = newinfo; + + stat_mem_block_root = newinfo; + stat_mem_allocated -= oldinfo->size; + stat_mem_high -= oldinfo->size; + stat_mem_allocated += newinfo->size; + stat_mem_high += newinfo->size; + + if (stat_mem_high > stat_mem_peak) + stat_mem_peak = stat_mem_high; + + free(oldinfo); + + return newinfo + 1; +} + +/* + * strdup does it's own malloc, we need to track malloc. We don't want + * to overwrite malloc though, infact, we can't really hook it at all + * without library specific assumptions. So we re implement strdup. + */ +char *stat_mem_strdup(const char *src, size_t line, const char *file, bool empty) { + size_t len = 0; + char *ptr = NULL; + + if (!src) + return NULL; + + len = strlen(src); + if (((!empty) ? len : true) && (ptr = (char*)stat_mem_allocate(len + 1, line, file))) { + memcpy(ptr, src, len); + ptr[len] = '\0'; + } + + stat_used_strdups ++; + return ptr; +} + +/* + * The reallocate function for resizing vectors. + */ +void _util_vec_grow(void **a, size_t i, size_t s) { + vector_t *d = vec_meta(*a); + size_t m = 0; + stat_size_entry_t *e = NULL; + void *p = NULL; + + if (*a) { + m = 2 * d->allocated + i; + p = mem_r(d, s * m + sizeof(vector_t)); + } else { + m = i + 1; + p = mem_a(s * m + sizeof(vector_t)); + ((vector_t*)p)->used = 0; + stat_used_vectors++; + } + + if (!stat_size_vectors) + stat_size_vectors = stat_size_new(); + + if ((e = stat_size_get(stat_size_vectors, s))) { + e->value ++; + } else { + stat_size_put(stat_size_vectors, s, 1); /* start off with 1 */ + stat_type_vectors++; + } + + *a = (vector_t*)p + 1; + vec_meta(*a)->allocated = m; +} + +/* + * Hash table for generic data, based on dynamic memory allocations + * all around. This is the internal interface, please look for + * EXPOSED INTERFACE comment below + */ +typedef struct hash_node_t { + char *key; /* the key for this node in table */ + void *value; /* pointer to the data as void* */ + struct hash_node_t *next; /* next node (linked list) */ +} hash_node_t; + +GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) { + const uint32_t mix = 0x5BD1E995; + const uint32_t rot = 24; + size_t size = strlen(key); + uint32_t hash = 0x1EF0 /* LICRC TAB */ ^ size; + uint32_t alias = 0; + const unsigned char *data = (const unsigned char*)key; + + while (size >= 4) { + alias = (data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24)); + alias *= mix; + alias ^= alias >> rot; + alias *= mix; + + hash *= mix; + hash ^= alias; + + data += 4; + size -= 4; + } + + switch (size) { + case 3: hash ^= data[2] << 16; + case 2: hash ^= data[1] << 8; + case 1: hash ^= data[0]; + hash *= mix; + } + + hash ^= hash >> 13; + hash *= mix; + hash ^= hash >> 15; + + return (size_t) (hash % ht->size); +} + +static hash_node_t *_util_htnewpair(const char *key, void *value) { + hash_node_t *node; + if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t)))) + return NULL; + + if (!(node->key = util_strdupe(key))) { + mem_d(node); + return NULL; + } + + node->value = value; + node->next = NULL; + + return node; +} + +/* + * EXPOSED INTERFACE for the hashtable implementation + * util_htnew(size) -- to make a new hashtable + * util_htset(table, key, value, sizeof(value)) -- to set something in the table + * util_htget(table, key) -- to get something from the table + * util_htdel(table) -- to delete the table + */ +hash_table_t *util_htnew(size_t size) { + hash_table_t *hashtable = NULL; + stat_size_entry_t *find = NULL; + + if (size < 1) + return NULL; + + if (!stat_size_hashtables) + stat_size_hashtables = stat_size_new(); + + if (!(hashtable = (hash_table_t*)mem_a(sizeof(hash_table_t)))) + return NULL; + + if (!(hashtable->table = (hash_node_t**)mem_a(sizeof(hash_node_t*) * size))) { + mem_d(hashtable); + return NULL; + } + + if ((find = stat_size_get(stat_size_hashtables, size))) + find->value++; + else { + stat_used_hashtables++; + stat_size_put(stat_size_hashtables, size, 1); + } + + hashtable->size = size; + memset(hashtable->table, 0, sizeof(hash_node_t*) * size); + + stat_type_hashtables++; + return hashtable; +} + +void util_htseth(hash_table_t *ht, const char *key, size_t bin, void *value) { + hash_node_t *newnode = NULL; + hash_node_t *next = NULL; + hash_node_t *last = NULL; + + next = ht->table[bin]; + + while (next && next->key && strcmp(key, next->key) > 0) + last = next, next = next->next; + + /* already in table, do a replace */ + if (next && next->key && strcmp(key, next->key) == 0) { + next->value = value; + } else { + /* not found, grow a pair man :P */ + newnode = _util_htnewpair(key, value); + if (next == ht->table[bin]) { + newnode->next = next; + ht->table[bin] = newnode; + } else if (!next) { + last->next = newnode; + } else { + newnode->next = next; + last->next = newnode; + } + } +} + +void util_htset(hash_table_t *ht, const char *key, void *value) { + util_htseth(ht, key, util_hthash(ht, key), value); +} + +void *util_htgeth(hash_table_t *ht, const char *key, size_t bin) { + hash_node_t *pair = ht->table[bin]; + + while (pair && pair->key && strcmp(key, pair->key) > 0) + pair = pair->next; + + if (!pair || !pair->key || strcmp(key, pair->key) != 0) + return NULL; + + return pair->value; +} + +void *util_htget(hash_table_t *ht, const char *key) { + return util_htgeth(ht, key, util_hthash(ht, key)); +} + +void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin) { + hash_node_t *pair; + size_t len, keylen; + int cmp; + + keylen = strlen(key); + + pair = ht->table[bin]; + while (pair && pair->key) { + len = strlen(pair->key); + if (len < keylen) { + pair = pair->next; + continue; + } + if (keylen == len) { + cmp = strcmp(key, pair->key); + if (cmp == 0) + return pair->value; + if (cmp < 0) + return NULL; + pair = pair->next; + continue; + } + cmp = strcmp(key, pair->key + len - keylen); + if (cmp == 0) { + uintptr_t up = (uintptr_t)pair->value; + up += len - keylen; + return (void*)up; + } + pair = pair->next; + } + return NULL; +} + +/* + * Free all allocated data in a hashtable, this is quite the amount + * of work. + */ +void util_htrem(hash_table_t *ht, void (*callback)(void *data)) { + size_t i = 0; + for (; i < ht->size; i++) { + hash_node_t *n = ht->table[i]; + hash_node_t *p; + + /* free in list */ + while (n) { + if (n->key) + mem_d(n->key); + if (callback) + callback(n->value); + p = n; + n = n->next; + mem_d(p); + } + + } + /* free table */ + mem_d(ht->table); + mem_d(ht); +} + +void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) { + hash_node_t **pair = &ht->table[bin]; + hash_node_t *tmp; + + while (*pair && (*pair)->key && strcmp(key, (*pair)->key) > 0) + pair = &(*pair)->next; + + tmp = *pair; + if (!tmp || !tmp->key || strcmp(key, tmp->key) != 0) + return; + + if (cb) + (*cb)(tmp->value); + + *pair = tmp->next; + mem_d(tmp->key); + mem_d(tmp); +} + +void util_htrm(hash_table_t *ht, const char *key, void (*cb)(void*)) { + util_htrmh(ht, key, util_hthash(ht, key), cb); +} + +void util_htdel(hash_table_t *ht) { + util_htrem(ht, NULL); +} + +/* + * A tiny size_t key-value hashtbale for tracking vector and hashtable + * sizes. We can use it for other things too, if we need to. This is + * very TIGHT, and efficent in terms of space though. + */ +stat_size_table_t stat_size_new() { + return (stat_size_table_t)memset( + mem_a(sizeof(stat_size_entry_t*) * ST_SIZE), + 0, ST_SIZE * sizeof(stat_size_entry_t*) + ); +} + +void stat_size_del(stat_size_table_t table) { + size_t i = 0; + for (; i < ST_SIZE; i++) if(table[i]) mem_d(table[i]); + mem_d(table); +} + +stat_size_entry_t *stat_size_get(stat_size_table_t table, size_t key) { + size_t hash = (key % ST_SIZE); + while (table[hash] && table[hash]->key != key) + hash = (hash + 1) % ST_SIZE; + return table[hash]; +} +void stat_size_put(stat_size_table_t table, size_t key, size_t value) { + size_t hash = (key % ST_SIZE); + while (table[hash] && table[hash]->key != key) + hash = (hash + 1) % ST_SIZE; + table[hash] = (stat_size_entry_t*)mem_a(sizeof(stat_size_entry_t)); + table[hash]->key = key; + table[hash]->value = value; +} + +/* + * The following functions below implement printing / dumping of statistical + * information. + */ +static void stat_dump_mem_contents(stat_mem_block_t *memory, uint16_t cols) { + uint32_t i, j; + for (i = 0; i < memory->size + ((memory->size % cols) ? (cols - memory->size % cols) : 0); i++) { + if (i % cols == 0) con_out(" 0x%06X: ", i); + if (i < memory->size) con_out("%02X " , 0xFF & ((unsigned char*)(memory + 1))[i]); + else con_out(" "); + + if ((uint16_t)(i % cols) == (cols - 1)) { + for (j = i - (cols - 1); j <= i; j++) { + con_out("%c", + (j >= memory->size) + ? ' ' + : (isprint(((unsigned char*)(memory + 1))[j])) + ? 0xFF & ((unsigned char*)(memory + 1)) [j] + : '.' + ); + } + con_out("\n"); + } + } +} + +static void stat_dump_mem_leaks() { + stat_mem_block_t *info; + for (info = stat_mem_block_root; info; info = info->next) { + con_out("lost: %u (bytes) at %s:%u\n", + info->size, + info->file, + info->line + ); + + stat_dump_mem_contents(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)); + } +} + +static void stat_dump_mem_info() { + con_out("Memory information:\n\ + Total allocations: %llu\n\ + Total deallocations: %llu\n\ + Total allocated: %f (MB)\n\ + Total deallocated: %f (MB)\n\ + Total peak memory: %f (MB)\n\ + Total leaked memory: %f (MB) in %llu allocations\n", + stat_mem_allocated_total, + stat_mem_deallocated_total, + (float)(stat_mem_allocated) / 1048576.0f, + (float)(stat_mem_deallocated) / 1048576.0f, + (float)(stat_mem_high) / 1048576.0f, + (float)(stat_mem_allocated - stat_mem_deallocated) / 1048576.0f, + stat_mem_allocated_total - stat_mem_deallocated_total + ); +} + +static void stat_dump_stats_table(stat_size_table_t table, const char *string, uint64_t *size) { + size_t i,j; + + for (i = 0, j = 0; i < ST_SIZE; i++) { + stat_size_entry_t *entry; + + if (!(entry = table[i])) + continue; + + con_out(string, (unsigned)j, (unsigned)entry->key, (unsigned)entry->value); + j++; + + if (size) + *size += entry->key * entry->value; + } +} + +void stat_info() { + if (OPTS_OPTION_BOOL(OPTION_DEBUG)) + stat_dump_mem_leaks(); + + if (OPTS_OPTION_BOOL(OPTION_DEBUG) || + OPTS_OPTION_BOOL(OPTION_MEMCHK)) + stat_dump_mem_info(); + + if (OPTS_OPTION_BOOL(OPTION_MEMCHK) || + OPTS_OPTION_BOOL(OPTION_STATISTICS)) { + uint64_t mem; + + con_out("\nAdditional Statistics:\n\ + Total vectors allocated: %llu\n\ + Total string duplicates: %llu\n\ + Total hashtables allocated: %llu\n\ + Total unique vector sizes: %llu\n", + stat_used_vectors, + stat_used_strdups, + stat_used_hashtables, + stat_type_vectors + ); + + stat_dump_stats_table ( + stat_size_vectors, + " %2u| # of %4u byte vectors: %u\n", + &mem + ); + + con_out ( + " Total unique hashtable sizes: %llu\n", + stat_type_hashtables + ); + + stat_dump_stats_table ( + stat_size_hashtables, + " %2u| # of %4u element hashtables: %u\n", + NULL + ); + + con_out ( + " Total vector memory: %f (MB)\n", + (float)(mem) / 1048576.0f + ); + } + + if (stat_size_vectors) + stat_size_del(stat_size_vectors); + if (stat_size_hashtables) + stat_size_del(stat_size_hashtables); +} +#undef ST_SIZE diff --git a/test.c b/test.c index 6682983..7b9254d 100644 --- a/test.c +++ b/test.c @@ -1321,7 +1321,7 @@ int main(int argc, char **argv) { } con_change(redirout, redirerr); succeed = test_perform("tests", defs); - util_meminfo(); + stat_info(); return (succeed) ? EXIT_SUCCESS : EXIT_FAILURE; diff --git a/util.c b/util.c index 3dcf873..c6c8925 100644 --- a/util.c +++ b/util.c @@ -25,338 +25,6 @@ #include #include "gmqcc.h" -/* TODO: remove globals ... */ -static uint64_t mem_ab = 0; -static uint64_t mem_db = 0; -static uint64_t mem_at = 0; -static uint64_t mem_dt = 0; -static uint64_t mem_pk = 0; -static uint64_t mem_hw = 0; - -struct memblock_t { - const char *file; - unsigned int line; - size_t byte; - struct memblock_t *next; - struct memblock_t *prev; -}; - -#define PEAK_MEM \ - do { \ - if (mem_hw > mem_pk) \ - mem_pk = mem_hw; \ - } while (0) - -static struct memblock_t *mem_start = NULL; - -void *util_memory_a(size_t byte, unsigned int line, const char *file) { - struct memblock_t *info = (struct memblock_t*)malloc(sizeof(struct memblock_t) + byte); - void *data = (void*)(info+1); - if (!info) return NULL; - info->line = line; - info->byte = byte; - info->file = file; - info->prev = NULL; - info->next = mem_start; - if (mem_start) - mem_start->prev = info; - mem_start = info; - - mem_at++; - mem_ab += info->byte; - mem_hw += info->byte; - - PEAK_MEM; - - return data; -} - -void util_memory_d(void *ptrn) { - struct memblock_t *info = NULL; - - if (!ptrn) return; - info = ((struct memblock_t*)ptrn - 1); - - mem_db += info->byte; - mem_hw -= info->byte; - mem_dt++; - - if (info->prev) - info->prev->next = info->next; - if (info->next) - info->next->prev = info->prev; - if (info == mem_start) - mem_start = info->next; - - free(info); -} - -void *util_memory_r(void *ptrn, size_t byte, unsigned int line, const char *file) { - struct memblock_t *oldinfo = NULL; - - struct memblock_t *newinfo; - - if (!ptrn) - return util_memory_a(byte, line, file); - if (!byte) { - util_memory_d(ptrn); - return NULL; - } - - oldinfo = ((struct memblock_t*)ptrn - 1); - newinfo = ((struct memblock_t*)malloc(sizeof(struct memblock_t) + byte)); - - /* new data */ - if (!newinfo) { - util_memory_d(oldinfo+1); - return NULL; - } - - /* copy old */ - memcpy(newinfo+1, oldinfo+1, oldinfo->byte); - - /* free old */ - if (oldinfo->prev) - oldinfo->prev->next = oldinfo->next; - if (oldinfo->next) - oldinfo->next->prev = oldinfo->prev; - if (oldinfo == mem_start) - mem_start = oldinfo->next; - - /* fill info */ - newinfo->line = line; - newinfo->byte = byte; - newinfo->file = file; - newinfo->prev = NULL; - newinfo->next = mem_start; - if (mem_start) - mem_start->prev = newinfo; - mem_start = newinfo; - - mem_ab -= oldinfo->byte; - mem_hw -= oldinfo->byte; - mem_ab += newinfo->byte; - mem_hw += newinfo->byte; - - PEAK_MEM; - - free(oldinfo); - - return newinfo+1; -} - -static void util_dumpmem(struct memblock_t *memory, uint16_t cols) { - uint32_t i, j; - for (i = 0; i < memory->byte + ((memory->byte % cols) ? (cols - memory->byte % cols) : 0); i++) { - if (i % cols == 0) con_out(" 0x%06X: ", i); - if (i < memory->byte) con_out("%02X " , 0xFF & ((char*)(memory + 1))[i]); - else con_out(" "); - - if ((uint16_t)(i % cols) == (cols - 1)) { - for (j = i - (cols - 1); j <= i; j++) { - con_out("%c", - (j >= memory->byte) - ? ' ' - : (isprint(((char*)(memory + 1))[j])) - ? 0xFF & ((char*)(memory + 1)) [j] - : '.' - ); - } - con_out("\n"); - } - } -} - -/* - * The following is a VERY tight, efficent, hashtable for integer - * values and keys, and for nothing more. We could make our existing - * hashtable support type-genericness through a void * pointer but, - * ideally that would make things more complicated. We also don't need - * that much of a bloat for something as basic as this. - */ -typedef struct { - size_t key; - size_t value; -} size_entry_t; -#define ST_SIZE 1024 - -typedef size_entry_t **size_table_t; - -static size_table_t util_st_new() { - return (size_table_t)memset( - mem_a(sizeof(size_entry_t*) * ST_SIZE), - 0, ST_SIZE * sizeof(size_entry_t*) - ); -} -static void util_st_del(size_table_t table) { - size_t i = 0; - for (; i < ST_SIZE; i++) if(table[i]) mem_d(table[i]); - mem_d(table); -} -static size_entry_t *util_st_get(size_table_t table, size_t key) { - size_t hash = (key % ST_SIZE); - while (table[hash] && table[hash]->key != key) - hash = (hash + 1) % ST_SIZE; - return table[hash]; -} -static void util_st_put(size_table_t table, size_t key, size_t value) { - size_t hash = (key % ST_SIZE); - while (table[hash] && table[hash]->key != key) - hash = (hash + 1) % ST_SIZE; - table[hash] = (size_entry_t*)mem_a(sizeof(size_entry_t)); - table[hash]->key = key; - table[hash]->value = value; -} - -static uint64_t strdups = 0; -static uint64_t vectors = 0; -static uint64_t vector_sizes = 0; -static uint64_t hashtables = 0; -static uint64_t hashtable_sizes = 0; -static size_table_t vector_usage = NULL; -static size_table_t hashtable_usage = NULL; - -void util_meminfo() { - struct memblock_t *info; - - if (OPTS_OPTION_BOOL(OPTION_DEBUG)) { - for (info = mem_start; info; info = info->next) { - con_out("lost: %u (bytes) at %s:%u\n", - info->byte, - info->file, - info->line); - - util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)); - } - } - - if (OPTS_OPTION_BOOL(OPTION_DEBUG) || - OPTS_OPTION_BOOL(OPTION_MEMCHK)) { - con_out("Memory information:\n\ - Total allocations: %llu\n\ - Total deallocations: %llu\n\ - Total allocated: %f (MB)\n\ - Total deallocated: %f (MB)\n\ - Total peak memory: %f (MB)\n\ - Total leaked memory: %f (MB) in %llu allocations\n", - mem_at, - mem_dt, - (float)(mem_ab) / 1048576.0f, - (float)(mem_db) / 1048576.0f, - (float)(mem_pk) / 1048576.0f, - (float)(mem_ab - mem_db) / 1048576.0f, - - /* could be more clever */ - (mem_at - mem_dt) - ); - } - - if (OPTS_OPTION_BOOL(OPTION_STATISTICS) || - OPTS_OPTION_BOOL(OPTION_MEMCHK)) { - size_t i = 0; - size_t e = 1; - uint64_t vectormem = 0; - - con_out("\nAdditional Statistics:\n\ - Total vectors allocated: %llu\n\ - Total string duplicates: %llu\n\ - Total hashtables allocated: %llu\n\ - Total unique vector sizes: %llu\n", - vectors, - strdups, - hashtables, - vector_sizes - ); - - for (; i < ST_SIZE; i++) { - size_entry_t *entry; - - if (!(entry = vector_usage[i])) - continue; - - con_out(" %2u| # of %4u byte vectors: %u\n", - (unsigned)e, - (unsigned)entry->key, - (unsigned)entry->value - ); - e++; - - vectormem += entry->key * entry->value; - } - - con_out("\ - Total unique hashtable sizes: %llu\n", - hashtable_sizes - ); - - for (i = 0, e = 1; i < ST_SIZE; i++) { - size_entry_t *entry; - - if (!(entry = hashtable_usage[i])) - continue; - - con_out(" %2u| # of %4u element hashtables: %u\n", - (unsigned)e, - (unsigned)entry->key, - (unsigned)entry->value - ); - e++; - } - - con_out(" Total vector memory: %f (MB)\n", - (float)(vectormem) / 1048576.0f - ); - } - - if (vector_usage) - util_st_del(vector_usage); - if (hashtable_usage) - util_st_del(hashtable_usage); -} - -/* - * Some string utility functions, because strdup uses malloc, and we want - * to track all memory (without replacing malloc). - */ -char *_util_Estrdup(const char *s, const char *file, size_t line) { - size_t len = 0; - char *ptr = NULL; - - /* in case of -DNOTRACK */ - (void)file; - (void)line; - - if (!s) - return NULL; - - if ((len = strlen(s)) && (ptr = (char*)mem_af(len+1, line, file))) { - memcpy(ptr, s, len); - ptr[len] = '\0'; - } - strdups++; - return ptr; -} - -char *_util_Estrdup_empty(const char *s, const char *file, size_t line) { - size_t len = 0; - char *ptr = NULL; - - /* in case of -DNOTRACK */ - (void)file; - (void)line; - - if (!s) - return NULL; - - len = strlen(s); - if ((ptr = (char*)mem_af(len+1, line, file))) { - memcpy(ptr, s, len); - ptr[len] = '\0'; - } - strdups++; - return ptr; -} - void util_debug(const char *area, const char *ms, ...) { va_list va; if (!OPTS_OPTION_BOOL(OPTION_DEBUG)) @@ -544,274 +212,6 @@ size_t util_strtononcmd(const char *in, char *out, size_t outsz) { return sz-1; } -/* TODO: rewrite ... when I redo the ve cleanup */ -void _util_vec_grow(void **a, size_t i, size_t s) { - vector_t *d = vec_meta(*a); - size_t m = 0; - size_entry_t *e = NULL; - void *p = NULL; - - if (*a) { - m = 2 * d->allocated + i; - p = mem_r(d, s * m + sizeof(vector_t)); - } else { - m = i + 1; - p = mem_a(s * m + sizeof(vector_t)); - ((vector_t*)p)->used = 0; - vectors++; - } - - if (!vector_usage) - vector_usage = util_st_new(); - - if ((e = util_st_get(vector_usage, s))) { - e->value ++; - } else { - util_st_put(vector_usage, s, 1); /* start off with 1 */ - vector_sizes++; - } - - *a = (vector_t*)p + 1; - vec_meta(*a)->allocated = m; -} - -/* - * Hash table for generic data, based on dynamic memory allocations - * all around. This is the internal interface, please look for - * EXPOSED INTERFACE comment below - */ -typedef struct hash_node_t { - char *key; /* the key for this node in table */ - void *value; /* pointer to the data as void* */ - struct hash_node_t *next; /* next node (linked list) */ -} hash_node_t; - -GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) { - const uint32_t mix = 0x5BD1E995; - const uint32_t rot = 24; - size_t size = strlen(key); - uint32_t hash = 0x1EF0 /* LICRC TAB */ ^ size; - uint32_t alias = 0; - const unsigned char *data = (const unsigned char*)key; - - while (size >= 4) { - alias = (data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24)); - alias *= mix; - alias ^= alias >> rot; - alias *= mix; - - hash *= mix; - hash ^= alias; - - data += 4; - size -= 4; - } - - switch (size) { - case 3: hash ^= data[2] << 16; - case 2: hash ^= data[1] << 8; - case 1: hash ^= data[0]; - hash *= mix; - } - - hash ^= hash >> 13; - hash *= mix; - hash ^= hash >> 15; - - return (size_t) (hash % ht->size); -} - -static hash_node_t *_util_htnewpair(const char *key, void *value) { - hash_node_t *node; - if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t)))) - return NULL; - - if (!(node->key = util_strdupe(key))) { - mem_d(node); - return NULL; - } - - node->value = value; - node->next = NULL; - - return node; -} - -/* - * EXPOSED INTERFACE for the hashtable implementation - * util_htnew(size) -- to make a new hashtable - * util_htset(table, key, value, sizeof(value)) -- to set something in the table - * util_htget(table, key) -- to get something from the table - * util_htdel(table) -- to delete the table - */ -hash_table_t *util_htnew(size_t size) { - hash_table_t *hashtable = NULL; - size_entry_t *find; - - if (size < 1) - return NULL; - - if (!hashtable_usage) - hashtable_usage = util_st_new(); - - if (!(hashtable = (hash_table_t*)mem_a(sizeof(hash_table_t)))) - return NULL; - - if (!(hashtable->table = (hash_node_t**)mem_a(sizeof(hash_node_t*) * size))) { - mem_d(hashtable); - return NULL; - } - - if ((find = util_st_get(hashtable_usage, size))) - find->value++; - else { - hashtable_sizes++; - util_st_put(hashtable_usage, size, 1); - } - - hashtable->size = size; - memset(hashtable->table, 0, sizeof(hash_node_t*) * size); - - hashtables++; - return hashtable; -} - -void util_htseth(hash_table_t *ht, const char *key, size_t bin, void *value) { - hash_node_t *newnode = NULL; - hash_node_t *next = NULL; - hash_node_t *last = NULL; - - next = ht->table[bin]; - - while (next && next->key && strcmp(key, next->key) > 0) - last = next, next = next->next; - - /* already in table, do a replace */ - if (next && next->key && strcmp(key, next->key) == 0) { - next->value = value; - } else { - /* not found, grow a pair man :P */ - newnode = _util_htnewpair(key, value); - if (next == ht->table[bin]) { - newnode->next = next; - ht->table[bin] = newnode; - } else if (!next) { - last->next = newnode; - } else { - newnode->next = next; - last->next = newnode; - } - } -} - -void util_htset(hash_table_t *ht, const char *key, void *value) { - util_htseth(ht, key, util_hthash(ht, key), value); -} - -void *util_htgeth(hash_table_t *ht, const char *key, size_t bin) { - hash_node_t *pair = ht->table[bin]; - - while (pair && pair->key && strcmp(key, pair->key) > 0) - pair = pair->next; - - if (!pair || !pair->key || strcmp(key, pair->key) != 0) - return NULL; - - return pair->value; -} - -void *util_htget(hash_table_t *ht, const char *key) { - return util_htgeth(ht, key, util_hthash(ht, key)); -} - -void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin) { - hash_node_t *pair; - size_t len, keylen; - int cmp; - - keylen = strlen(key); - - pair = ht->table[bin]; - while (pair && pair->key) { - len = strlen(pair->key); - if (len < keylen) { - pair = pair->next; - continue; - } - if (keylen == len) { - cmp = strcmp(key, pair->key); - if (cmp == 0) - return pair->value; - if (cmp < 0) - return NULL; - pair = pair->next; - continue; - } - cmp = strcmp(key, pair->key + len - keylen); - if (cmp == 0) { - uintptr_t up = (uintptr_t)pair->value; - up += len - keylen; - return (void*)up; - } - pair = pair->next; - } - return NULL; -} - -/* - * Free all allocated data in a hashtable, this is quite the amount - * of work. - */ -void util_htrem(hash_table_t *ht, void (*callback)(void *data)) { - size_t i = 0; - for (; i < ht->size; i++) { - hash_node_t *n = ht->table[i]; - hash_node_t *p; - - /* free in list */ - while (n) { - if (n->key) - mem_d(n->key); - if (callback) - callback(n->value); - p = n; - n = n->next; - mem_d(p); - } - - } - /* free table */ - mem_d(ht->table); - mem_d(ht); -} - -void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) { - hash_node_t **pair = &ht->table[bin]; - hash_node_t *tmp; - - while (*pair && (*pair)->key && strcmp(key, (*pair)->key) > 0) - pair = &(*pair)->next; - - tmp = *pair; - if (!tmp || !tmp->key || strcmp(key, tmp->key) != 0) - return; - - if (cb) - (*cb)(tmp->value); - - *pair = tmp->next; - mem_d(tmp->key); - mem_d(tmp); -} - -void util_htrm(hash_table_t *ht, const char *key, void (*cb)(void*)) { - util_htrmh(ht, key, util_hthash(ht, key), cb); -} - -void util_htdel(hash_table_t *ht) { - util_htrem(ht, NULL); -} - /* * Portable implementation of vasprintf/asprintf. Assumes vsnprintf * exists, otherwise compiler error. From 7ea67748fab1a4aab21977cfd540df654316114d Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 08:25:00 +0000 Subject: [PATCH 46/63] Holy whoops --- stat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stat.c b/stat.c index 7747763..5c1a6f4 100644 --- a/stat.c +++ b/stat.c @@ -82,6 +82,8 @@ void stat_mem_deallocate(void *ptr) { /* move ahead */ if (info == stat_mem_block_root) stat_mem_block_root = info->next; + + free(info); } void *stat_mem_reallocate(void *ptr, size_t size, size_t line, const char *file) { From 564cac859a97977ebaee4da42f53a46bbc4aa8b3 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 08:28:56 +0000 Subject: [PATCH 47/63] Fix the peak --- stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stat.c b/stat.c index 5c1a6f4..372cc14 100644 --- a/stat.c +++ b/stat.c @@ -515,7 +515,7 @@ static void stat_dump_mem_info() { stat_mem_deallocated_total, (float)(stat_mem_allocated) / 1048576.0f, (float)(stat_mem_deallocated) / 1048576.0f, - (float)(stat_mem_high) / 1048576.0f, + (float)(stat_mem_peak) / 1048576.0f, (float)(stat_mem_allocated - stat_mem_deallocated) / 1048576.0f, stat_mem_allocated_total - stat_mem_deallocated_total ); From ee42d2a5701d5bdde900c10065ca8ac520224344 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 08:37:22 +0000 Subject: [PATCH 48/63] Some cleanups --- gmqcc.h | 17 -------------- stat.c | 72 +++++++++++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 50 deletions(-) diff --git a/gmqcc.h b/gmqcc.h index 8edcbda..5922b84 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -291,29 +291,12 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ /*===================================================================*/ /*=========================== stat.c ================================*/ /*===================================================================*/ -typedef struct { - size_t key; - size_t value; -} stat_size_entry_t, **stat_size_table_t; - void stat_info(); - char *stat_mem_strdup (const char *, size_t, const char *, bool); void *stat_mem_reallocate(void *, size_t, size_t, const char *); void stat_mem_deallocate(void *); void *stat_mem_allocate (size_t, size_t, const char *); -stat_size_table_t stat_size_new(); -stat_size_entry_t *stat_size_get(stat_size_table_t, size_t); -void stat_size_del(stat_size_table_t); -void stat_size_put(stat_size_table_t, size_t, size_t); - -/* getters for hashtable: */ -stat_size_table_t *stat_size_hashtables_get(); -uint64_t *stat_type_hashtables_get(); -uint64_t *stat_used_hashtables_get(); -stat_size_table_t *stat_hashtables_init(); - #define mem_a(SIZE) stat_mem_allocate ((SIZE), __LINE__, __FILE__) #define mem_d(PTRN) stat_mem_deallocate((void*)(PTRN)) #define mem_r(PTRN, SIZE) stat_mem_reallocate((void*)(PTRN), (SIZE), __LINE__, __FILE__) diff --git a/stat.c b/stat.c index 372cc14..7f8a498 100644 --- a/stat.c +++ b/stat.c @@ -17,6 +17,11 @@ typedef struct stat_mem_block_s { struct stat_mem_block_s *prev; } stat_mem_block_t; +typedef struct { + size_t key; + size_t value; +} stat_size_entry_t, **stat_size_table_t; + static uint64_t stat_mem_allocated = 0; static uint64_t stat_mem_deallocated = 0; static uint64_t stat_mem_allocated_total = 0; @@ -32,6 +37,40 @@ static stat_size_table_t stat_size_vectors = NULL; static stat_size_table_t stat_size_hashtables = NULL; static stat_mem_block_t *stat_mem_block_root = NULL; + +/* + * A tiny size_t key-value hashtbale for tracking vector and hashtable + * sizes. We can use it for other things too, if we need to. This is + * very TIGHT, and efficent in terms of space though. + */ +static stat_size_table_t stat_size_new() { + return (stat_size_table_t)memset( + mem_a(sizeof(stat_size_entry_t*) * ST_SIZE), + 0, ST_SIZE * sizeof(stat_size_entry_t*) + ); +} + +static void stat_size_del(stat_size_table_t table) { + size_t i = 0; + for (; i < ST_SIZE; i++) if(table[i]) mem_d(table[i]); + mem_d(table); +} + +static stat_size_entry_t *stat_size_get(stat_size_table_t table, size_t key) { + size_t hash = (key % ST_SIZE); + while (table[hash] && table[hash]->key != key) + hash = (hash + 1) % ST_SIZE; + return table[hash]; +} +static void stat_size_put(stat_size_table_t table, size_t key, size_t value) { + size_t hash = (key % ST_SIZE); + while (table[hash] && table[hash]->key != key) + hash = (hash + 1) % ST_SIZE; + table[hash] = (stat_size_entry_t*)mem_a(sizeof(stat_size_entry_t)); + table[hash]->key = key; + table[hash]->value = value; +} + /* * A basic header of information wrapper allocator. Simply stores * information as a header, returns the memory + 1 past it, can be @@ -431,39 +470,6 @@ void util_htdel(hash_table_t *ht) { util_htrem(ht, NULL); } -/* - * A tiny size_t key-value hashtbale for tracking vector and hashtable - * sizes. We can use it for other things too, if we need to. This is - * very TIGHT, and efficent in terms of space though. - */ -stat_size_table_t stat_size_new() { - return (stat_size_table_t)memset( - mem_a(sizeof(stat_size_entry_t*) * ST_SIZE), - 0, ST_SIZE * sizeof(stat_size_entry_t*) - ); -} - -void stat_size_del(stat_size_table_t table) { - size_t i = 0; - for (; i < ST_SIZE; i++) if(table[i]) mem_d(table[i]); - mem_d(table); -} - -stat_size_entry_t *stat_size_get(stat_size_table_t table, size_t key) { - size_t hash = (key % ST_SIZE); - while (table[hash] && table[hash]->key != key) - hash = (hash + 1) % ST_SIZE; - return table[hash]; -} -void stat_size_put(stat_size_table_t table, size_t key, size_t value) { - size_t hash = (key % ST_SIZE); - while (table[hash] && table[hash]->key != key) - hash = (hash + 1) % ST_SIZE; - table[hash] = (stat_size_entry_t*)mem_a(sizeof(stat_size_entry_t)); - table[hash]->key = key; - table[hash]->value = value; -} - /* * The following functions below implement printing / dumping of statistical * information. From c569e87bd0cae1373aee8b20af5af9016074186c Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 08:49:16 +0000 Subject: [PATCH 49/63] Fix two bugs --- stat.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/stat.c b/stat.c index 7f8a498..3d4d4a4 100644 --- a/stat.c +++ b/stat.c @@ -530,6 +530,9 @@ static void stat_dump_mem_info() { static void stat_dump_stats_table(stat_size_table_t table, const char *string, uint64_t *size) { size_t i,j; + if (!table) + return; + for (i = 0, j = 0; i < ST_SIZE; i++) { stat_size_entry_t *entry; @@ -554,7 +557,7 @@ void stat_info() { if (OPTS_OPTION_BOOL(OPTION_MEMCHK) || OPTS_OPTION_BOOL(OPTION_STATISTICS)) { - uint64_t mem; + uint64_t mem = 0; con_out("\nAdditional Statistics:\n\ Total vectors allocated: %llu\n\ From c1a9ce3404b9b2d1cc7bc5192a9c1ccc6fcafbbc Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 08:52:30 +0000 Subject: [PATCH 50/63] Fix output --- stat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stat.c b/stat.c index 3d4d4a4..0192a2f 100644 --- a/stat.c +++ b/stat.c @@ -323,14 +323,14 @@ hash_table_t *util_htnew(size_t size) { if ((find = stat_size_get(stat_size_hashtables, size))) find->value++; else { - stat_used_hashtables++; + stat_type_hashtables++; stat_size_put(stat_size_hashtables, size, 1); } hashtable->size = size; memset(hashtable->table, 0, sizeof(hash_node_t*) * size); - stat_type_hashtables++; + stat_used_hashtables++; return hashtable; } From 06cccbb646f50cc339c7c3a0713f5bc6fe668d7a Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Sun, 2 Jun 2013 09:50:39 +0000 Subject: [PATCH 51/63] Fix a divide by zero error --- test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test.c b/test.c index 7b9254d..e6567f0 100644 --- a/test.c +++ b/test.c @@ -1283,6 +1283,7 @@ int main(int argc, char **argv) { char *defs = NULL; con_init(); + OPTS_OPTION_U16(OPTION_MEMDUMPCOLS) = 16; /* * Command line option parsing commences now We only need to support From b2348e1de06ecbc6298c7caae7ac0deaa444dffb Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Sun, 2 Jun 2013 12:35:53 +0200 Subject: [PATCH 52/63] remove the ast tree earlier - saves over 3% peak memory usage --- parser.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/parser.c b/parser.c index bedef2b..cf69136 100644 --- a/parser.c +++ b/parser.c @@ -39,6 +39,8 @@ typedef struct parser_s { lex_file *lex; int tok; + bool ast_cleaned; + ast_expression **globals; ast_expression **fields; ast_function **functions; @@ -6189,9 +6191,12 @@ bool parser_compile_string(parser_t *parser, const char *name, const char *str, return parser_compile(parser); } -void parser_cleanup(parser_t *parser) +static void parser_remove_ast(parser_t *parser) { size_t i; + if (parser->ast_cleaned) + return; + parser->ast_cleaned = true; for (i = 0; i < vec_size(parser->accessors); ++i) { ast_delete(parser->accessors[i]->constval.vfunc); parser->accessors[i]->constval.vfunc = NULL; @@ -6260,9 +6265,12 @@ void parser_cleanup(parser_t *parser) ast_value_delete(parser->const_vec[2]); util_htdel(parser->aliases); - intrin_intrinsics_destroy(parser); +} +void parser_cleanup(parser_t *parser) +{ + parser_remove_ast(parser); code_cleanup(parser->code); mem_d(parser); @@ -6421,6 +6429,8 @@ bool parser_finish(parser_t *parser, const char *output) return false; } } + + generate_checksum(parser); if (OPTS_OPTION_BOOL(OPTION_DUMP)) ir_builder_dump(ir, con_out); for (i = 0; i < vec_size(parser->functions); ++i) { @@ -6430,6 +6440,7 @@ bool parser_finish(parser_t *parser, const char *output) return false; } } + parser_remove_ast(parser); if (compile_Werrors) { con_out("*** there were warnings treated as errors\n"); @@ -6441,15 +6452,12 @@ bool parser_finish(parser_t *parser, const char *output) if (OPTS_OPTION_BOOL(OPTION_DUMPFIN)) ir_builder_dump(ir, con_out); - generate_checksum(parser); - if (!ir_builder_generate(parser->code, ir, output)) { con_out("*** failed to generate output file\n"); ir_builder_delete(ir); return false; } } - ir_builder_delete(ir); return retval; } From 11179a2a71572972f0b19d8be5974ad338915b9f Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Tue, 4 Jun 2013 02:47:07 +0000 Subject: [PATCH 53/63] Major header reworking, this respects the namespaces properly. Makes object dependency more obvious, allows for better make caches, and prevents misuse of library features, i.e use con_* instead of printf. --- ast.c | 1 - code.c | 1 + conout.c | 1 - correct.c | 1 + exec.c | 1 + ftepp.c | 3 +++ gmqcc.h | 6 +----- ir.c | 1 + lexer.c | 6 ++---- lexer.h | 1 - main.c | 8 +++++++- opts.c | 5 +++++ pak.c | 3 +++ parser.c | 3 +-- stat.c | 11 ++++++++++- test.c | 5 ++++- util.c | 5 +++-- 17 files changed, 43 insertions(+), 19 deletions(-) diff --git a/ast.c b/ast.c index 81e1c12..d845eb2 100644 --- a/ast.c +++ b/ast.c @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include #include #include diff --git a/code.c b/code.c index 35f758a..c2838ef 100644 --- a/code.c +++ b/code.c @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include #include "gmqcc.h" /* diff --git a/conout.c b/conout.c index 687fdf4..80ec5e1 100644 --- a/conout.c +++ b/conout.c @@ -21,7 +21,6 @@ * SOFTWARE. */ #include "gmqcc.h" -#include /* * isatty/STDERR_FILENO/STDOUT_FILNO diff --git a/correct.c b/correct.c index 7e16608..f501817 100644 --- a/correct.c +++ b/correct.c @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include #include "gmqcc.h" /* diff --git a/exec.c b/exec.c index 49cff44..18b9f30 100644 --- a/exec.c +++ b/exec.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "gmqcc.h" diff --git a/ftepp.c b/ftepp.c index 5348dfb..0a9ff5b 100644 --- a/ftepp.c +++ b/ftepp.c @@ -22,7 +22,10 @@ * SOFTWARE. */ #include +#include +#include #include + #include "gmqcc.h" #include "lexer.h" diff --git a/gmqcc.h b/gmqcc.h index 5922b84..6dde0cd 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -23,12 +23,8 @@ */ #ifndef GMQCC_HDR #define GMQCC_HDR -#include -#include -#include #include -#include -#include +#include /* TODO: remove this */ /* * Disable some over protective warnings in visual studio because fixing them is a waste diff --git a/ir.c b/ir.c index 5dae734..fcf4caa 100644 --- a/ir.c +++ b/ir.c @@ -23,6 +23,7 @@ */ #include #include + #include "gmqcc.h" #include "ir.h" diff --git a/lexer.c b/lexer.c index 862131e..8289057 100644 --- a/lexer.c +++ b/lexer.c @@ -20,14 +20,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include -#include +#include #include -#include +#include #include "gmqcc.h" #include "lexer.h" - /* * List of Keywords */ diff --git a/lexer.h b/lexer.h index cde0863..f51d56e 100644 --- a/lexer.h +++ b/lexer.h @@ -22,7 +22,6 @@ */ #ifndef GMQCC_LEXER_HDR #define GMQCC_LEXER_HDR - typedef struct token_s token; struct token_s { diff --git a/main.c b/main.c index 5717fb5..cbcadf1 100644 --- a/main.c +++ b/main.c @@ -21,9 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include +#include +#include +#include +#include + + #include "gmqcc.h" #include "lexer.h" -#include /* TODO: cleanup this whole file .. it's a fuckign mess */ diff --git a/opts.c b/opts.c index abd012f..4cfa79c 100644 --- a/opts.c +++ b/opts.c @@ -21,7 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include +#include +#include + #include "gmqcc.h" + unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS]; opts_cmd_t opts; /* command lien options */ diff --git a/pak.c b/pak.c index ac31bdf..2371ee1 100644 --- a/pak.c +++ b/pak.c @@ -20,6 +20,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include +#include + #include "gmqcc.h" /* diff --git a/parser.c b/parser.c index cf69136..e92cb6e 100644 --- a/parser.c +++ b/parser.c @@ -21,8 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include -#include +#include #include #include "gmqcc.h" diff --git a/stat.c b/stat.c index 0192a2f..aecd7eb 100644 --- a/stat.c +++ b/stat.c @@ -1,3 +1,7 @@ +#include +#include +#include + #include "gmqcc.h" /* @@ -22,6 +26,12 @@ typedef struct { size_t value; } stat_size_entry_t, **stat_size_table_t; +typedef struct { + uint64_t used; + uint64_t type; + uint64_t size; +} stat_entry_t; + static uint64_t stat_mem_allocated = 0; static uint64_t stat_mem_deallocated = 0; static uint64_t stat_mem_allocated_total = 0; @@ -37,7 +47,6 @@ static stat_size_table_t stat_size_vectors = NULL; static stat_size_table_t stat_size_hashtables = NULL; static stat_mem_block_t *stat_mem_block_root = NULL; - /* * A tiny size_t key-value hashtbale for tracking vector and hashtable * sizes. We can use it for other things too, if we need to. This is diff --git a/test.c b/test.c index e6567f0..1ebb33a 100644 --- a/test.c +++ b/test.c @@ -20,10 +20,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "gmqcc.h" +#include +#include #include #include +#include "gmqcc.h" + opts_cmd_t opts; static const char *task_bins[] = { diff --git a/util.c b/util.c index c6c8925..5e234ae 100644 --- a/util.c +++ b/util.c @@ -21,8 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include -#include +#include +#include + #include "gmqcc.h" void util_debug(const char *area, const char *ms, ...) { From 77cf1f8685d564d22560efd3ae93bce37fa72d23 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Tue, 4 Jun 2013 02:49:49 +0000 Subject: [PATCH 54/63] Doh --- stat.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/stat.c b/stat.c index aecd7eb..eb197fb 100644 --- a/stat.c +++ b/stat.c @@ -26,12 +26,6 @@ typedef struct { size_t value; } stat_size_entry_t, **stat_size_table_t; -typedef struct { - uint64_t used; - uint64_t type; - uint64_t size; -} stat_entry_t; - static uint64_t stat_mem_allocated = 0; static uint64_t stat_mem_deallocated = 0; static uint64_t stat_mem_allocated_total = 0; From e29b4d35b3a19d0183c489ad8c7e446b0b7f8098 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Tue, 4 Jun 2013 02:53:44 +0000 Subject: [PATCH 55/63] Add license header --- stat.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/stat.c b/stat.c index eb197fb..1bfba84 100644 --- a/stat.c +++ b/stat.c @@ -1,3 +1,27 @@ +/* + * Copyright (C) 2012, 2013 + * Dale Weiler + * Wolfgang Bumiller + * + * 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 #include #include From af80d9956b09c43616c50b7253a0f2e05ba2c69b Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Tue, 4 Jun 2013 17:43:20 +0000 Subject: [PATCH 56/63] Gentoo ebuilds --- distro/gentoo/INSTALL | 35 ++++++++++++++++++++++++++++++++ distro/gentoo/gmqcc-0.3.0.ebuild | 20 ++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 distro/gentoo/INSTALL create mode 100644 distro/gentoo/gmqcc-0.3.0.ebuild diff --git a/distro/gentoo/INSTALL b/distro/gentoo/INSTALL new file mode 100644 index 0000000..8a3a950 --- /dev/null +++ b/distro/gentoo/INSTALL @@ -0,0 +1,35 @@ +To use the ebuilds provided in this gentoo directory you first must +create a directory in your overlay tree. + +If you don't already have your own directory for custom ebuilds, you can +create one. If you already have one, and that directory is set in your +/etc/make.conf for PORTDIR_OVERLAY, this step can be skiped. Otherwise +if you don't already, you can create one as such. + +# mkdir -p /usr/local/portage +# vim /etc/make.conf + Set PORTDIR_OVERLAY=/usr/local/portage + The save and exit + +Once that is completed, or you skiped that step, you need to create a +directory in your overlay tree for gmqcc, this can be done with. It should +(subsitute [[PORTDIR_OVERLAY]] with the one set in /etc/make.conf) + +# mkdir -p [[PORTDIR_OVERLAY]]/gmqcc + +After the directory is created you need to move the correct version ebuild +into that directory depending on which version of GMQCC you want. For +instance, if you want gmqcc 0.3.0, you move gmqcc-0.3.0.ebuild into that +directory. + +# mv gmqcc-{version}.ebuild [[PORTDIR_OVERLAY]]/gmqcc/ + +After the file is moved into your newly created portage overlay tree, you'll +need to build a digest for it with ebuild. A digest is simply a Manifest and +digital signature for the source files used. + +# ebuild gmqcc-0.3.0.ebuild digest + +After the digest is built, you can emerge gmqcc as usual. + +# emerge gmqcc diff --git a/distro/gentoo/gmqcc-0.3.0.ebuild b/distro/gentoo/gmqcc-0.3.0.ebuild new file mode 100644 index 0000000..28630d3 --- /dev/null +++ b/distro/gentoo/gmqcc-0.3.0.ebuild @@ -0,0 +1,20 @@ +EAPI=5 + +DESCRIPTION="An Improved Quake C Compiler" +HOMEPAGE="http://graphitemaster.github.com/gmqcc/" +SRC_URI="https://github.com/graphitemaster/${PN}/archive/${PV}.tar.gz -> ${P}.tar.gz" + +LICENSE="MIT" + +SLOT="0" +IUSE="" +KEYWORDS="~amd64 ~x86" + +src_prepare() { + sed -i -e "s:-Werror ::" Makefile || die +} + +src_install() { + emake install PREFIX="${D}/usr" + dodoc README +} From 0f98f0fd4ae3a53dd1c6946b1f0aa954f0b798c2 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Tue, 4 Jun 2013 17:44:45 +0000 Subject: [PATCH 57/63] Some typos. --- distro/gentoo/INSTALL | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/distro/gentoo/INSTALL b/distro/gentoo/INSTALL index 8a3a950..7a4f778 100644 --- a/distro/gentoo/INSTALL +++ b/distro/gentoo/INSTALL @@ -9,10 +9,10 @@ if you don't already, you can create one as such. # mkdir -p /usr/local/portage # vim /etc/make.conf Set PORTDIR_OVERLAY=/usr/local/portage - The save and exit + Then save and exit Once that is completed, or you skiped that step, you need to create a -directory in your overlay tree for gmqcc, this can be done with. It should +directory in your overlay tree for gmqcc, this can be done as such: (subsitute [[PORTDIR_OVERLAY]] with the one set in /etc/make.conf) # mkdir -p [[PORTDIR_OVERLAY]]/gmqcc From 0d52f1ae7cb6eff1897a075a1c71d213f56c5862 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Tue, 4 Jun 2013 18:02:02 +0000 Subject: [PATCH 58/63] Update changelog --- CHANGES | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 01af3ff..b38c587 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,24 @@ Release v0.3.0 - * to fill + * Language: + - Return assignments, the ability to assign to the return keyword + as if it were a local variable. + * Compilation: + - Optimized memory usage (now uses on average %3 less memory for + compilation). + - Fixed dotranslate (translatable strings) + * QCVM: + - Escape strings for -printdefs + * Commandline: + - Added statistic dumps, gives information about the number of used + hashtables, vectors, and number of unique sizes of vectors and + hashtables. The amount of memory used for vectors. As well as the + number of strdups used in total for compilation. + * Testsuite: + - Fixed a floating point exception rasied by modulo operation in + -memchk. + * Build: + - Added gentoo ebuilds. + - Added win32 Makefile for building win32 packages. 2012-04-27 v0.2.9 * Preprocessor: @@ -56,12 +75,12 @@ Release v0.3.0 - Added defs.qh (auto included) for qcvm definitions * Syntax Highlighting: - Added various syntax highlighting description files for - various text editors / integrated development envirorments, - including support for: geany, kate, kwrite, kdevelop, QtCreator, - gtksourceview, gedit, sany, nano, jedit + various text editors / integrated development envirorments, + including support for: geany, kate, kwrite, kdevelop, QtCreator, + gtksourceview, gedit, sany, nano, jedit * Build: - Build scripts for building debian, archlinux and archbsd - packages for x86, and x86_64. + packages for x86, and x86_64. - Makefile targets for gource visualization, and render of gource visualization. From 81b27ea84aa5460dbf4e777f22c4717ff188d95e Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Tue, 4 Jun 2013 18:07:18 +0000 Subject: [PATCH 59/63] Consistency --- AUTHORS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 472760f..16255d2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,6 +1,6 @@ Authors: - Dale Weiler - Charismatic Visionary / Programmer - Wolfgang Bumiller - Main Programmer + Dale `graphitemaster` Weiler - Charismatic Visionary / Programmer + Wolfgang `Blub\w` Bumiller - Main Programmer Thanks to: Forest `LordHavoc` Hale - Technical support and assistance From 52d39b726055fe269463ad47375a8fb68822efa6 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 4 Jun 2013 20:32:06 +0200 Subject: [PATCH 60/63] slackware pkg build files --- distro/slackware/this/Makefile | 35 ++++++++++++++++++++++++++++++++ distro/slackware/this/slack-desc | 12 +++++++++++ 2 files changed, 47 insertions(+) create mode 100644 distro/slackware/this/Makefile create mode 100644 distro/slackware/this/slack-desc diff --git a/distro/slackware/this/Makefile b/distro/slackware/this/Makefile new file mode 100644 index 0000000..3f70b8b --- /dev/null +++ b/distro/slackware/this/Makefile @@ -0,0 +1,35 @@ +BASEDIR := ../../../ +PREFIX := /usr +HEADER := $(BASEDIR)/gmqcc.h +MAJOR := $(shell sed -n -e '/GMQCC_VERSION_MAJOR/{s/.* .* //;p;q;}' $(HEADER)) +MINOR := $(shell sed -n -e '/GMQCC_VERSION_MINOR/{s/.* .* //;p;q;}' $(HEADER)) +PATCH := $(shell sed -n -e '/GMQCC_VERSION_PATCH/{s/.* .* //;p;q;}' $(HEADER)) +CARCH := $(shell uname -m) +PKGDIR := gmqcc-$(MAJOR).$(MINOR).$(PATCH)-$(CARCH)-git +PKG := $(PKGDIR).txz +PKGINFO := $(PKGDIR)/.PKGINFO +DESTDIR := distro/slackware/this/$(PKGDIR) +CFLAGS := + + +ifneq (, $(findstring i686, $(CARCH))) + CFLAGS += -m32 + LDFLAGS += -m32 +endif + +base: + $(MAKE) -C $(BASEDIR) clean + CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" \ + $(MAKE) -C $(BASEDIR) "DESTDIR=$(DESTDIR)" "PREFIX=$(PREFIX)" install + gzip -9 $(PKGDIR)/usr/share/man/man?/*.? + strip -s $(PKGDIR)/usr/bin/* + mkdir $(PKGDIR)/install + cp slack-desc $(PKGDIR)/install + @tar -cJvf $(PKG) -C $(PKGDIR)/ install/ usr/ + @rm -rf $(PKGDIR) + +clean: + $(MAKE) -C $(BASEDIR) clean + @rm -f *.txz + +all: base diff --git a/distro/slackware/this/slack-desc b/distro/slackware/this/slack-desc new file mode 100644 index 0000000..3384ef9 --- /dev/null +++ b/distro/slackware/this/slack-desc @@ -0,0 +1,12 @@ + |-----handy-ruler------------------------------------------------------| +gmqcc: gmqcc (Quake C compiler) +gmqcc: +gmqcc: A modern written-from-scratch compiler for the QuakeC language with +gmqcc: support for many common features found in other QC compilers. +gmqcc: Additionally contains a standalone QCVM executor, and a tool to deal +gmqcc: with .pak archive files. +gmqcc: +gmqcc: +gmqcc: github page: +gmqcc: http://github.com/graphitemaster/gmqcc +gmqcc: From 4f02d4b556b9f6e61b0deb3a18c8a8ecd1cd35e2 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Tue, 4 Jun 2013 18:38:16 +0000 Subject: [PATCH 61/63] Update --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index b38c587..b7499a1 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,7 @@ Release v0.3.0 * Build: - Added gentoo ebuilds. - Added win32 Makefile for building win32 packages. + - Added slackware pkg build files 2012-04-27 v0.2.9 * Preprocessor: From 144672fada7324651eabbbd0eaec68ed4dd031c1 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Thu, 6 Jun 2013 02:51:13 +0000 Subject: [PATCH 62/63] Strict prototyping --- Makefile | 5 +++-- conout.c | 2 +- exec.c | 4 ++-- ftepp.c | 2 +- gmqcc.h | 31 +++++++++++++++---------------- intrin.h | 2 +- main.c | 4 ++-- opts.c | 2 +- stat.c | 6 +++--- util.c | 2 +- 10 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index a1c08f9..2e5c1ee 100644 --- a/Makefile +++ b/Makefile @@ -29,12 +29,13 @@ ifeq ($(CC), clang) -Wno-conversion \ -Wno-missing-prototypes \ -Wno-float-equal \ - -Wno-unknown-warning-option + -Wno-unknown-warning-option \ + -Wstrict-prototypes else #Tiny C Compiler doesn't know what -pedantic-errors is # and instead of ignoring .. just errors. ifneq ($(CC), tcc) - CFLAGS += -pedantic-errors + CFLAGS += -Wstrict-prototypes -pedantic-errors else CFLAGS += -Wno-pointer-sign -fno-common endif diff --git a/conout.c b/conout.c index 80ec5e1..13a242f 100644 --- a/conout.c +++ b/conout.c @@ -197,7 +197,7 @@ static con_t console; * NOTE: This prevents colored output to piped stdout/err via isatty * checks. */ -static void con_enablecolor() { +static void con_enablecolor(void) { if (console.handle_err == stderr || console.handle_err == stdout) console.color_err = !!(isatty(STDERR_FILENO)); if (console.handle_out == stderr || console.handle_out == stdout) diff --git a/exec.c b/exec.c index 18b9f30..6934a0c 100644 --- a/exec.c +++ b/exec.c @@ -835,7 +835,7 @@ static size_t qc_builtins_count = sizeof(qc_builtins) / sizeof(qc_builtins[0]); static const char *arg0 = NULL; -static void version() { +static void version(void) { printf("GMQCC-QCVM %d.%d.%d Built %s %s\n", GMQCC_VERSION_MAJOR, GMQCC_VERSION_MINOR, @@ -845,7 +845,7 @@ static void version() { ); } -static void usage() { +static void usage(void) { printf("usage: %s [options] [parameters] file\n", arg0); printf("options:\n"); printf(" -h, --help print this message\n" diff --git a/ftepp.c b/ftepp.c index 0a9ff5b..55d4fff 100644 --- a/ftepp.c +++ b/ftepp.c @@ -316,7 +316,7 @@ static void ppmacro_delete(ppmacro *self) mem_d(self); } -static ftepp_t* ftepp_new() +static ftepp_t* ftepp_new(void) { ftepp_t *ftepp; diff --git a/gmqcc.h b/gmqcc.h index 6dde0cd..d6055db 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -287,7 +287,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ /*===================================================================*/ /*=========================== stat.c ================================*/ /*===================================================================*/ -void stat_info(); +void stat_info (void); char *stat_mem_strdup (const char *, size_t, const char *, bool); void *stat_mem_reallocate(void *, size_t, size_t, const char *); void stat_mem_deallocate(void *); @@ -317,7 +317,7 @@ size_t util_strtononcmd (const char *, char *, size_t); uint16_t util_crc16(uint16_t crc, const char *data, size_t len); void util_seed(uint32_t); -uint32_t util_rand(); +uint32_t util_rand(void); /* * String functions (formatting, copying, concatenating, errors). These are wrapped @@ -373,7 +373,7 @@ typedef struct trie_s { struct trie_s *entries; } correct_trie_t; -correct_trie_t* correct_trie_new(); +correct_trie_t* correct_trie_new(void); typedef struct hash_table_t { size_t size; @@ -763,17 +763,17 @@ enum { LVL_ERROR }; -FILE *con_default_out(); -FILE *con_default_err(); +FILE *con_default_out(void); +FILE *con_default_err(void); void con_vprintmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap); void con_printmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...); void con_cvprintmsg(void *ctx, int lvl, const char *msgtype, const char *msg, va_list ap); void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, ...); -void con_close (); -void con_init (); -void con_reset (); +void con_close (void); +void con_init (void); +void con_reset (void); void con_color (int); int con_change(const char *, const char *); int con_verr (const char *, va_list); @@ -790,7 +790,7 @@ void /********/ compile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, ... void /********/ vcompile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, va_list ap); bool GMQCC_WARN compile_warning (lex_ctx ctx, int warntype, const char *fmt, ...); bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list ap); -void compile_show_werrors(); +void compile_show_werrors(void); /*===================================================================*/ /*========================= assembler.c =============================*/ @@ -995,8 +995,7 @@ qcint prog_tempstring(qc_program *prog, const char *_str); /*===================== parser.c commandline ========================*/ /*===================================================================*/ struct parser_s; - -struct parser_s *parser_create (); +struct parser_s *parser_create (void); bool parser_compile_file (struct parser_s *parser, const char *); bool parser_compile_string(struct parser_s *parser, const char *, const char *, size_t); bool parser_finish (struct parser_s *parser, const char *); @@ -1006,7 +1005,7 @@ void parser_cleanup (struct parser_s *parser); /*====================== ftepp.c commandline ========================*/ /*===================================================================*/ struct ftepp_s; -struct ftepp_s *ftepp_create (); +struct ftepp_s *ftepp_create (void); bool ftepp_preprocess_file (struct ftepp_s *ftepp, const char *filename); bool ftepp_preprocess_string(struct ftepp_s *ftepp, const char *name, const char *str); void ftepp_finish (struct ftepp_s *ftepp); @@ -1066,10 +1065,10 @@ void opts_setoptimlevel(unsigned int); void opts_ini_init (const char *); /* Saner flag handling */ -void opts_backup_non_Wall(); -void opts_restore_non_Wall(); -void opts_backup_non_Werror_all(); -void opts_restore_non_Werror_all(); +void opts_backup_non_Wall(void); +void opts_restore_non_Wall(void); +void opts_backup_non_Werror_all(void); +void opts_restore_non_Werror_all(void); enum { # define GMQCC_TYPE_FLAGS diff --git a/intrin.h b/intrin.h index 81af620..00464aa 100644 --- a/intrin.h +++ b/intrin.h @@ -36,7 +36,7 @@ typedef struct { const char *alias; } intrin_t; -static ht intrin_intrinsics() { +static ht intrin_intrinsics(void) { static ht intrinsics = NULL; if (!intrinsics) intrinsics = util_htnew(PARSER_HT_SIZE); diff --git a/main.c b/main.c index cbcadf1..37638e9 100644 --- a/main.c +++ b/main.c @@ -50,7 +50,7 @@ static ppitem *ppems = NULL; static const char *app_name; -static void version() { +static void version(void) { con_out("GMQCC %d.%d.%d Built %s %s\n" GMQCC_DEV_VERSION_STRING, GMQCC_VERSION_MAJOR, GMQCC_VERSION_MINOR, @@ -60,7 +60,7 @@ static void version() { ); } -static int usage() { +static int usage(void) { con_out("usage: %s [options] [files...]", app_name); con_out("options:\n" " -h, --help show this help message\n" diff --git a/opts.c b/opts.c index 4cfa79c..e6ca420 100644 --- a/opts.c +++ b/opts.c @@ -30,7 +30,7 @@ unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS]; opts_cmd_t opts; /* command lien options */ -static void opts_setdefault() { +static void opts_setdefault(void) { memset(&opts, 0, sizeof(opts_cmd_t)); OPTS_OPTION_BOOL(OPTION_CORRECTION) = true; diff --git a/stat.c b/stat.c index 1bfba84..3f342d0 100644 --- a/stat.c +++ b/stat.c @@ -70,7 +70,7 @@ static stat_mem_block_t *stat_mem_block_root = NULL; * sizes. We can use it for other things too, if we need to. This is * very TIGHT, and efficent in terms of space though. */ -static stat_size_table_t stat_size_new() { +static stat_size_table_t stat_size_new(void) { return (stat_size_table_t)memset( mem_a(sizeof(stat_size_entry_t*) * ST_SIZE), 0, ST_SIZE * sizeof(stat_size_entry_t*) @@ -523,7 +523,7 @@ static void stat_dump_mem_contents(stat_mem_block_t *memory, uint16_t cols) { } } -static void stat_dump_mem_leaks() { +static void stat_dump_mem_leaks(void) { stat_mem_block_t *info; for (info = stat_mem_block_root; info; info = info->next) { con_out("lost: %u (bytes) at %s:%u\n", @@ -536,7 +536,7 @@ static void stat_dump_mem_leaks() { } } -static void stat_dump_mem_info() { +static void stat_dump_mem_info(void) { con_out("Memory information:\n\ Total allocations: %llu\n\ Total deallocations: %llu\n\ diff --git a/util.c b/util.c index 5e234ae..efed221 100644 --- a/util.c +++ b/util.c @@ -389,7 +389,7 @@ int util_asprintf(char **ret, const char *fmt, ...) { static uint32_t mt_state[MT_SIZE]; static size_t mt_index = 0; -static GMQCC_INLINE void mt_generate() { +static GMQCC_INLINE void mt_generate(void) { /* * The loop has been unrolled here: the original paper and implemenation * Called for the following code: From ad92a5f27d9ad056a0225f74f1c986bc179be064 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Thu, 6 Jun 2013 06:20:11 +0000 Subject: [PATCH 63/63] Fix indexing --- stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stat.c b/stat.c index 3f342d0..21447eb 100644 --- a/stat.c +++ b/stat.c @@ -560,7 +560,7 @@ static void stat_dump_stats_table(stat_size_table_t table, const char *string, u if (!table) return; - for (i = 0, j = 0; i < ST_SIZE; i++) { + for (i = 0, j = 1; i < ST_SIZE; i++) { stat_size_entry_t *entry; if (!(entry = table[i]))