Merge branch 'master' into test-suite

Conflicts:
	Makefile
	ir.c
This commit is contained in:
Dale Weiler 2012-11-19 02:13:46 +00:00
commit 61fa54318c
14 changed files with 1801 additions and 114 deletions

39
INSTALL Normal file
View file

@ -0,0 +1,39 @@
Installing gmqcc
1. Prerequisites
- A C-Compiler such as gcc or clang
- GNU Make. This document will assume GNU-Make to be executed via
`make'. On BSD systems you probably have to use `gmake' instead.
2. Compilation
Run the GNU make program `make' or `gmake'.
make
If no error appears, the following binary files will have been
created:
- gmqcc
- qcvm
3. Installation
The `install' target will install the 2 binaries to /usr/local/bin
by default.
The Makefile honors the following variables:
- DESTDIR: The installation directory root.
- PREFIX: The installation prefix, default: /usr/local
- BINDIR: Directory for binary executables,
deafult: $PREFIX/bin
To install to /usr/local run:
make install
To install to /usr run:
make PREFIX=/usr install
To install to a package-staging directory such as $pkgdir when
writing an ArchLinux PKGBUILD file:
make DESTDIR=$pkgdir install

19
LICENSE Normal file
View file

@ -0,0 +1,19 @@
Copyright (C) 2012 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.

View file

@ -28,8 +28,9 @@ OBJ = \
code.o \
ast.o \
ir.o \
con.o
con.o \
ftepp.o
OBJ_T = test.o util.o con.o
OBJ_C = main.o lexer.o parser.o
OBJ_X = exec-standalone.o util.o con.o

5
README Normal file
View file

@ -0,0 +1,5 @@
The gmqcc Quake C Compiler
For licensing, see the LICENSE file.
For installation notes, see the INSTALL file.

7
exec.c
View file

@ -334,16 +334,15 @@ static void trace_print_global(qc_program *prog, unsigned int glob, int vtype)
def = prog_getdef(prog, glob);
value = (qcany*)(&prog->globals[glob]);
len = printf("[@%u] ", glob);
if (def) {
const char *name = prog_getstring(prog, def->name);
if (name[0] == '#')
len = printf("$");
len += printf("$");
else
len = printf("%s ", name);
len += printf("%s ", name);
vtype = def->type & DEF_TYPEMASK;
}
else
len = printf("[@%u] ", glob);
switch (vtype) {
case TYPE_VOID:

1280
ftepp.c Normal file

File diff suppressed because it is too large Load diff

12
gmqcc.h
View file

@ -752,6 +752,18 @@ bool parser_compile_file (const char *filename);
bool parser_compile_string(const char *name, const char *str);
bool parser_finish (const char *output);
void parser_cleanup ();
/* There's really no need to strlen() preprocessed files */
bool parser_compile_string_len(const char *name, const char *str, size_t len);
/*===================================================================*/
/*====================== ftepp.c commandline ========================*/
/*===================================================================*/
bool ftepp_init ();
bool ftepp_preprocess_file (const char *filename);
bool ftepp_preprocess_string(const char *name, const char *str);
void ftepp_finish ();
const char *ftepp_get ();
void ftepp_flush ();
/*===================================================================*/
/*======================= main.c commandline ========================*/

105
ir.c
View file

@ -259,6 +259,7 @@ ir_builder* ir_builder_new(const char *modulename)
self->functions = NULL;
self->globals = NULL;
self->fields = NULL;
self->extparams = NULL;
self->filenames = NULL;
self->filestrings = NULL;
@ -280,6 +281,10 @@ void ir_builder_delete(ir_builder* self)
ir_function_delete_quick(self->functions[i]);
}
vec_free(self->functions);
for (i = 0; i != vec_size(self->extparams); ++i) {
ir_value_delete(self->extparams[i]);
}
vec_free(self->extparams);
for (i = 0; i != vec_size(self->globals); ++i) {
ir_value_delete(self->globals[i]);
}
@ -2500,10 +2505,13 @@ tailcall:
* generation already. This would even include later
* reuse.... probably... :)
*/
size_t p;
size_t p, first;
ir_value *retvalue;
for (p = 0; p < vec_size(instr->params); ++p)
first = vec_size(instr->params);
if (first > 8)
first = 8;
for (p = 0; p < first; ++p)
{
ir_value *param = instr->params[p];
@ -2518,6 +2526,33 @@ tailcall:
stmt.o2.u1 = OFS_PARM0 + 3 * p;
vec_push(code_statements, stmt);
}
/* No whandle extparams */
first = vec_size(instr->params);
for (; p < first; ++p)
{
ir_builder *ir = func->owner;
ir_value *param = instr->params[p];
ir_value *target;
if (p-8 >= vec_size(ir->extparams)) {
irerror(instr->context, "Not enough extparam-globals have been created");
return false;
}
target = ir->extparams[p-8];
stmt.opcode = INSTR_STORE_F;
stmt.o3.u1 = 0;
if (param->vtype == TYPE_FIELD)
stmt.opcode = field_store_instr[param->fieldtype];
else
stmt.opcode = type_store_instr[param->vtype];
stmt.o1.u1 = ir_value_code_addr(param);
stmt.o2.u1 = ir_value_code_addr(target);
vec_push(code_statements, stmt);
}
stmt.opcode = INSTR_CALL0 + vec_size(instr->params);
if (stmt.opcode > INSTR_CALL8)
stmt.opcode = INSTR_CALL8;
@ -2652,6 +2687,8 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
fun.file = ir_builder_filestring(ir, global->context.file);
fun.profile = 0; /* always 0 */
fun.nargs = vec_size(irfun->params);
if (fun.nargs > 8)
fun.nargs = 8;
for (i = 0;i < 8; ++i) {
if (i >= fun.nargs)
@ -2698,6 +2735,63 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
return true;
}
static void ir_gen_extparam(ir_builder *ir)
{
prog_section_def def;
ir_value *global;
char name[128];
snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparams)+8));
global = ir_value_var(name, store_global, TYPE_VECTOR);
def.name = code_genstring(name);
def.type = TYPE_VECTOR;
def.offset = vec_size(code_globals);
vec_push(code_defs, def);
ir_value_code_setaddr(global, def.offset);
vec_push(code_globals, 0);
vec_push(code_globals, 0);
vec_push(code_globals, 0);
vec_push(ir->extparams, global);
}
static bool gen_function_extparam_copy(ir_function *self)
{
size_t i, ext, numparams;
ir_builder *ir = self->owner;
ir_value *ep;
prog_section_statement stmt;
numparams = vec_size(self->params);
if (!numparams)
return true;
stmt.opcode = INSTR_STORE_F;
stmt.o3.s1 = 0;
for (i = 8; i < numparams; ++i) {
ext = i - 8;
if (ext >= vec_size(ir->extparams))
ir_gen_extparam(ir);
ep = ir->extparams[ext];
stmt.opcode = type_store_instr[self->locals[i]->vtype];
if (self->locals[i]->vtype == TYPE_FIELD &&
self->locals[i]->fieldtype == TYPE_VECTOR)
{
stmt.opcode = INSTR_STORE_V;
}
stmt.o1.u1 = ir_value_code_addr(ep);
stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
vec_push(code_statements, stmt);
}
return true;
}
static bool gen_global_function_code(ir_builder *ir, ir_value *global)
{
prog_section_function *fundef;
@ -2721,6 +2815,10 @@ static bool gen_global_function_code(ir_builder *ir, ir_value *global)
fundef = &code_functions[irfun->code_function_def];
fundef->entry = vec_size(code_statements);
if (!gen_function_extparam_copy(irfun)) {
irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name);
return false;
}
if (!gen_function_code(irfun)) {
irerror(irfun->context, "Failed to generate code for function %s", irfun->name);
return false;
@ -2972,7 +3070,8 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
stmt.o3.u1 = 0;
vec_push(code_statements, stmt);
con_out("writing '%s'...\n", filename);
if (!opts_pp_only)
con_out("writing '%s'...\n", filename);
return code_write(filename);
}

2
ir.h
View file

@ -290,6 +290,8 @@ typedef struct ir_builder_s
ir_value **globals;
ir_value **fields;
ir_value **extparams;
const char **filenames;
qcint *filestrings;
/* we cache the #IMMEDIATE string here */

186
lexer.c
View file

@ -10,32 +10,32 @@ char* *lex_filenames;
void lexerror(lex_file *lex, const char *fmt, ...)
{
va_list ap;
va_list ap;
va_start(ap, fmt);
if (lex)
va_start(ap, fmt);
if (lex)
con_vprintmsg(LVL_ERROR, lex->name, lex->sline, "parse error", fmt, ap);
else
con_vprintmsg(LVL_ERROR, "", 0, "parse error", fmt, ap);
va_end(ap);
va_end(ap);
}
bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...)
{
va_list ap;
int lvl = LVL_WARNING;
va_list ap;
int lvl = LVL_WARNING;
if (!OPTS_WARN(warntype))
return false;
if (opts_werror)
lvl = LVL_ERROR;
lvl = LVL_ERROR;
va_start(ap, fmt);
va_start(ap, fmt);
con_vprintmsg(lvl, lex->name, lex->sline, "warning", fmt, ap);
va_end(ap);
va_end(ap);
return opts_werror;
return opts_werror;
}
@ -289,13 +289,13 @@ static int lex_getch(lex_file *lex)
if (lex->peekpos) {
lex->peekpos--;
if (lex->peek[lex->peekpos] == '\n')
if (!lex->push_line && lex->peek[lex->peekpos] == '\n')
lex->line++;
return lex->peek[lex->peekpos];
}
ch = lex_fgetc(lex);
if (ch == '\n')
if (!lex->push_line && ch == '\n')
lex->line++;
else if (ch == '?')
return lex_try_trigraph(lex, ch);
@ -307,7 +307,7 @@ static int lex_getch(lex_file *lex)
static void lex_ungetch(lex_file *lex, int ch)
{
lex->peek[lex->peekpos++] = ch;
if (ch == '\n')
if (!lex->push_line && ch == '\n')
lex->line--;
}
@ -347,6 +347,115 @@ static void lex_endtoken(lex_file *lex)
vec_shrinkby(lex->tok.value, 1);
}
static bool lex_try_pragma(lex_file *lex)
{
int ch;
char *pragma = NULL;
char *command = NULL;
char *param = NULL;
size_t line;
if (lex->flags.preprocessing)
return false;
line = lex->line;
ch = lex_getch(lex);
if (ch != '#') {
lex_ungetch(lex, ch);
return false;
}
for (ch = lex_getch(lex); vec_size(pragma) < 8 && ch >= 'a' && ch <= 'z'; ch = lex_getch(lex))
vec_push(pragma, ch);
vec_push(pragma, 0);
if (ch != ' ' || strcmp(pragma, "pragma")) {
lex_ungetch(lex, ch);
goto unroll;
}
for (ch = lex_getch(lex); vec_size(command) < 32 && ch >= 'a' && ch <= 'z'; ch = lex_getch(lex))
vec_push(command, ch);
vec_push(command, 0);
if (ch != '(') {
lex_ungetch(lex, ch);
goto unroll;
}
for (ch = lex_getch(lex); vec_size(param) < 32 && ch != ')' && ch != '\n'; ch = lex_getch(lex))
vec_push(param, ch);
vec_push(param, 0);
if (ch != ')') {
lex_ungetch(lex, ch);
goto unroll;
}
if (!strcmp(command, "push")) {
if (!strcmp(param, "line")) {
lex->push_line++;
--line;
}
else
goto unroll;
}
else if (!strcmp(command, "pop")) {
if (!strcmp(param, "line")) {
if (lex->push_line)
lex->push_line--;
--line;
}
else
goto unroll;
}
else if (!strcmp(command, "file")) {
lex->name = util_strdup(param);
vec_push(lex_filenames, lex->name);
}
else if (!strcmp(command, "line")) {
line = strtol(param, NULL, 0)-1;
}
else
goto unroll;
lex->line = line;
while (ch != '\n' && ch != EOF)
ch = lex_getch(lex);
return true;
unroll:
if (command) {
vec_pop(command);
while (vec_size(command)) {
lex_ungetch(lex, vec_last(command));
vec_pop(command);
}
vec_free(command);
}
if (command) {
vec_pop(command);
while (vec_size(command)) {
lex_ungetch(lex, vec_last(command));
vec_pop(command);
}
vec_free(command);
}
if (pragma) {
vec_pop(pragma);
while (vec_size(pragma)) {
lex_ungetch(lex, vec_last(pragma));
vec_pop(pragma);
}
vec_free(pragma);
}
lex_ungetch(lex, '#');
lex->line = line;
return false;
}
/* Skip whitespace and comments and return the first
* non-white character.
* As this makes use of the above getch() ungetch() functions,
@ -388,6 +497,10 @@ static int lex_skipwhite(lex_file *lex)
{
ch = lex_getch(lex);
while (ch != EOF && isspace(ch)) {
if (ch == '\n') {
if (lex_try_pragma(lex))
continue;
}
if (lex->flags.preprocessing) {
if (ch == '\n') {
/* end-of-line */
@ -415,13 +528,17 @@ static int lex_skipwhite(lex_file *lex)
if (lex->flags.preprocessing) {
haswhite = true;
/*
lex_tokench(lex, '/');
lex_tokench(lex, '/');
*/
lex_tokench(lex, ' ');
lex_tokench(lex, ' ');
}
while (ch != EOF && ch != '\n') {
if (lex->flags.preprocessing)
lex_tokench(lex, ch);
lex_tokench(lex, ' '); /* ch); */
ch = lex_getch(lex);
}
if (lex->flags.preprocessing) {
@ -436,8 +553,12 @@ static int lex_skipwhite(lex_file *lex)
/* multiline comment */
if (lex->flags.preprocessing) {
haswhite = true;
/*
lex_tokench(lex, '/');
lex_tokench(lex, '*');
*/
lex_tokench(lex, ' ');
lex_tokench(lex, ' ');
}
while (ch != EOF)
@ -447,14 +568,18 @@ static int lex_skipwhite(lex_file *lex)
ch = lex_getch(lex);
if (ch == '/') {
if (lex->flags.preprocessing) {
/*
lex_tokench(lex, '*');
lex_tokench(lex, '/');
*/
lex_tokench(lex, ' ');
lex_tokench(lex, ' ');
}
break;
}
}
if (lex->flags.preprocessing) {
lex_tokench(lex, ch);
lex_tokench(lex, ' '); /* ch); */
}
}
ch = ' '; /* cause TRUE in the isspace check */
@ -561,7 +686,17 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
if (ch == quote)
return TOKEN_STRINGCONST;
if (!lex->flags.preprocessing && ch == '\\') {
if (lex->flags.preprocessing && ch == '\\') {
lex_tokench(lex, ch);
ch = lex_getch(lex);
if (ch == EOF) {
lexerror(lex, "unexpected end of file");
lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
return (lex->tok.ttype = TOKEN_ERROR);
}
lex_tokench(lex, ch);
}
else if (ch == '\\') {
ch = lex_getch(lex);
if (ch == EOF) {
lexerror(lex, "unexpected end of file");
@ -571,6 +706,8 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
switch (ch) {
case '\\': break;
case '\'': break;
case '"': break;
case 'a': ch = '\a'; break;
case 'b': ch = '\b'; break;
case 'r': ch = '\r'; break;
@ -678,7 +815,21 @@ int lex_do(lex_file *lex)
return TOKEN_FATAL;
#endif
ch = lex_skipwhite(lex);
while (true) {
ch = lex_skipwhite(lex);
if (!lex->flags.mergelines || ch != '\\')
break;
ch = lex_getch(lex);
if (ch != '\n') {
lex_ungetch(lex, ch);
ch = '\\';
break;
}
/* we reached a linemerge */
lex_tokench(lex, '\n');
continue;
}
lex->sline = lex->line;
lex->tok.ctx.line = lex->sline;
lex->tok.ctx.file = lex->name;
@ -851,6 +1002,7 @@ int lex_do(lex_file *lex)
return (lex->tok.ttype = TOKEN_OPERATOR);
case ')':
case ';':
case ':':
case '{':
case '}':
case ']':

View file

@ -119,11 +119,14 @@ typedef struct {
bool noops;
bool nodigraphs; /* used when lexing string constants */
bool preprocessing; /* whitespace and EOLs become actual tokens */
bool mergelines; /* backslash at the end of a line escapes the newline */
} flags;
int framevalue;
frame_macro *frames;
char *modelname;
size_t push_line;
} lex_file;
lex_file* lex_open (const char *file);

177
main.c
View file

@ -1,6 +1,7 @@
/*
* Copyright (C) 2012
* 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
@ -57,28 +58,28 @@ static const char *app_name;
static int usage() {
con_out("usage: %s [options] [files...]", app_name);
con_out("options:\n"
" -h, --help show this help message\n"
" -debug turns on compiler debug messages\n"
" -memchk turns on compiler memory leak check\n");
" -h, --help show this help message\n"
" -debug turns on compiler debug messages\n"
" -memchk turns on compiler memory leak check\n");
con_out(" -o, --output=file output file, defaults to progs.dat\n"
" -a filename add an asm file to be assembled\n"
" -s filename add a progs.src file to be used\n");
" -a filename add an asm file to be assembled\n"
" -s filename add a progs.src file to be used\n");
con_out(" -E stop after preprocessing\n");
con_out(" -f<flag> enable a flag\n"
" -fno-<flag> disable a flag\n"
" -std standard select one of the following standards\n"
" -std=qcc original QuakeC\n"
" -std=fteqcc fteqcc QuakeC\n"
" -std=gmqcc this compiler (default)\n");
" -fno-<flag> disable a flag\n"
" -std standard select one of the following standards\n"
" -std=qcc original QuakeC\n"
" -std=fteqcc fteqcc QuakeC\n"
" -std=gmqcc this compiler (default)\n");
con_out(" -W<warning> enable a warning\n"
" -Wno-<warning> disable a warning\n"
" -Wall enable all warnings\n"
" -Werror treat warnings as errors\n");
" -Wno-<warning> disable a warning\n"
" -Wall enable all warnings\n"
" -Werror treat warnings as errors\n");
con_out(" -force-crc=num force a specific checksum into the header\n");
con_out("\n");
con_out("flags:\n"
" -fadjust-vector-fields\n"
" when assigning a vector field, its _y and _z fields also get assigned\n"
" -fadjust-vector-fields\n"
" when assigning a vector field, its _y and _z fields also get assigned\n"
);
return -1;
}
@ -202,6 +203,7 @@ static bool options_parse(int argc, char **argv) {
options_set(opts_flags, ADJUST_VECTOR_FIELDS, false);
opts_standard = COMPILER_QCC;
} else if (!strcmp(argarg, "fte") || !strcmp(argarg, "fteqcc")) {
options_set(opts_flags, FTEPP, true);
options_set(opts_flags, ADJUST_VECTOR_FIELDS, false);
opts_standard = COMPILER_FTEQCC;
} else if (!strcmp(argarg, "qccx")) {
@ -416,6 +418,8 @@ int main(int argc, char **argv) {
size_t itr;
int retval = 0;
bool opts_output_free = false;
bool progs_src = false;
FILE *outfile = NULL;
app_name = argv[0];
con_init();
@ -436,8 +440,11 @@ int main(int argc, char **argv) {
options_set(opts_warn, WARN_EFFECTLESS_STATEMENT, true);
options_set(opts_warn, WARN_END_SYS_FIELDS, true);
options_set(opts_warn, WARN_ASSIGN_FUNCTION_TYPES, true);
options_set(opts_warn, WARN_PREPROCESSOR, true);
options_set(opts_warn, WARN_MULTIFILE_IF, true);
options_set(opts_flags, ADJUST_VECTOR_FIELDS, true);
options_set(opts_flags, FTEPP, false);
if (!options_parse(argc, argv)) {
return usage();
@ -464,53 +471,53 @@ int main(int argc, char **argv) {
con_out("standard = %i\n", opts_standard);
}
if (!parser_init()) {
con_out("failed to initialize parser\n");
retval = 1;
goto cleanup;
if (opts_pp_only) {
if (opts_output_wasset) {
outfile = util_fopen(opts_output, "wb");
if (!outfile) {
con_err("failed to open `%s` for writing\n", opts_output);
retval = 1;
goto cleanup;
}
}
else
outfile = stdout;
}
if (!opts_pp_only) {
if (!parser_init()) {
con_err("failed to initialize parser\n");
retval = 1;
goto cleanup;
}
}
if (opts_pp_only || OPTS_FLAG(FTEPP)) {
if (!ftepp_init()) {
con_err("failed to initialize parser\n");
retval = 1;
goto cleanup;
}
}
util_debug("COM", "starting ...\n");
if (vec_size(items)) {
con_out("Mode: manual\n");
con_out("There are %lu items to compile:\n", (unsigned long)vec_size(items));
for (itr = 0; itr < vec_size(items); ++itr) {
con_out(" item: %s (%s)\n",
items[itr].filename,
( (items[itr].type == TYPE_QC ? "qc" :
(items[itr].type == TYPE_ASM ? "asm" :
(items[itr].type == TYPE_SRC ? "progs.src" :
("unknown"))))));
if (!parser_compile_file(items[itr].filename))
{
retval = 1;
goto cleanup;
}
}
if (!parser_finish(opts_output)) {
retval = 1;
goto cleanup;
}
} else {
if (!vec_size(items)) {
FILE *src;
char *line;
size_t linelen = 0;
con_out("Mode: progs.src\n");
progs_src = true;
src = util_fopen("progs.src", "rb");
if (!src) {
con_out("failed to open `progs.src` for reading\n");
con_err("failed to open `progs.src` for reading\n");
retval = 1;
goto cleanup;
}
line = NULL;
if (!progs_nextline(&line, &linelen, src) || !line[0]) {
con_out("illformatted progs.src file: expected output filename in first line\n");
con_err("illformatted progs.src file: expected output filename in first line\n");
retval = 1;
goto srcdone;
}
@ -521,30 +528,92 @@ int main(int argc, char **argv) {
}
while (progs_nextline(&line, &linelen, src)) {
argitem item;
if (!line[0] || (line[0] == '/' && line[1] == '/'))
continue;
con_out(" src: %s\n", line);
if (!parser_compile_file(line)) {
retval = 1;
goto srcdone;
}
item.filename = util_strdup(line);
item.type = TYPE_QC;
vec_push(items, item);
}
parser_finish(opts_output);
srcdone:
fclose(src);
mem_d(line);
}
if (retval)
goto cleanup;
if (vec_size(items)) {
if (!opts_pp_only) {
con_out("Mode: %s\n", (progs_src ? "progs.src" : "manual"));
con_out("There are %lu items to compile:\n", (unsigned long)vec_size(items));
}
for (itr = 0; itr < vec_size(items); ++itr) {
if (!opts_pp_only) {
con_out(" item: %s (%s)\n",
items[itr].filename,
( (items[itr].type == TYPE_QC ? "qc" :
(items[itr].type == TYPE_ASM ? "asm" :
(items[itr].type == TYPE_SRC ? "progs.src" :
("unknown"))))));
}
if (opts_pp_only) {
if (!ftepp_preprocess_file(items[itr].filename)) {
retval = 1;
goto cleanup;
}
fprintf(outfile, "%s", ftepp_get());
ftepp_flush();
}
else {
if (OPTS_FLAG(FTEPP)) {
const char *data;
if (!ftepp_preprocess_file(items[itr].filename)) {
retval = 1;
goto cleanup;
}
data = ftepp_get();
if (!parser_compile_string_len(items[itr].filename, data, vec_size(data)-1)) {
retval = 1;
goto cleanup;
}
ftepp_flush();
}
else {
if (!parser_compile_file(items[itr].filename)) {
retval = 1;
goto cleanup;
}
}
}
if (progs_src) {
mem_d(items[itr].filename);
items[itr].filename = NULL;
}
}
ftepp_finish();
if (!opts_pp_only) {
if (!parser_finish(opts_output)) {
retval = 1;
goto cleanup;
}
}
}
/* stuff */
cleanup:
util_debug("COM", "cleaning ...\n");
ftepp_finish();
con_close();
vec_free(items);
parser_cleanup();
if (!opts_pp_only)
parser_cleanup();
if (opts_output_free)
mem_d((char*)opts_output);

View file

@ -31,6 +31,7 @@
GMQCC_DEFINE_FLAG(DARKPLACES_STRING_TABLE_BUG)
GMQCC_DEFINE_FLAG(OMIT_NULL_BYTES)
GMQCC_DEFINE_FLAG(ADJUST_VECTOR_FIELDS)
GMQCC_DEFINE_FLAG(FTEPP)
#endif
/* warning flags */
@ -52,6 +53,8 @@
GMQCC_DEFINE_FLAG(EFFECTLESS_STATEMENT)
GMQCC_DEFINE_FLAG(END_SYS_FIELDS)
GMQCC_DEFINE_FLAG(ASSIGN_FUNCTION_TYPES)
GMQCC_DEFINE_FLAG(PREPROCESSOR)
GMQCC_DEFINE_FLAG(MULTIFILE_IF)
#endif
/* some cleanup so we don't have to */

View file

@ -20,6 +20,9 @@ typedef struct {
ast_value **imm_string;
ast_value **imm_vector;
/* must be deleted first, they reference immediates and values */
ast_value **accessors;
ast_value *imm_float_zero;
ast_value *imm_vector_zero;
@ -2396,6 +2399,7 @@ static bool parser_create_array_accessor(parser_t *parser, ast_value *array, con
{
ast_function *func = NULL;
ast_value *fval = NULL;
ast_block *body = NULL;
fval = ast_value_new(ast_ctx(array), funcname, TYPE_FUNCTION);
if (!fval) {
@ -2410,15 +2414,25 @@ static bool parser_create_array_accessor(parser_t *parser, ast_value *array, con
return false;
}
body = ast_block_new(ast_ctx(array));
if (!body) {
parseerror(parser, "failed to create block for array accessor");
ast_delete(fval);
ast_delete(func);
return false;
}
vec_push(func->blocks, body);
*out = fval;
vec_push(parser->accessors, fval);
return true;
}
static bool parser_create_array_setter(parser_t *parser, ast_value *array, const char *funcname)
{
ast_expression *root = NULL;
ast_block *body = NULL;
ast_value *index = NULL;
ast_value *value = NULL;
ast_function *func;
@ -2434,12 +2448,6 @@ static bool parser_create_array_setter(parser_t *parser, ast_value *array, const
func = fval->constval.vfunc;
fval->expression.next = (ast_expression*)ast_value_new(ast_ctx(array), "<void>", TYPE_VOID);
body = ast_block_new(ast_ctx(array));
if (!body) {
parseerror(parser, "failed to create block for array accessor");
goto cleanup;
}
index = ast_value_new(ast_ctx(array), "index", TYPE_FLOAT);
value = ast_value_copy((ast_value*)array->expression.next);
@ -2457,12 +2465,10 @@ static bool parser_create_array_setter(parser_t *parser, ast_value *array, const
goto cleanup;
}
vec_push(body->exprs, root);
vec_push(func->blocks, body);
vec_push(func->blocks[0]->exprs, root);
array->setter = fval;
return true;
cleanup:
if (body) ast_delete(body);
if (index) ast_delete(index);
if (value) ast_delete(value);
if (root) ast_delete(root);
@ -2474,7 +2480,6 @@ cleanup:
static bool parser_create_array_field_setter(parser_t *parser, ast_value *array, const char *funcname)
{
ast_expression *root = NULL;
ast_block *body = NULL;
ast_value *entity = NULL;
ast_value *index = NULL;
ast_value *value = NULL;
@ -2491,12 +2496,6 @@ static bool parser_create_array_field_setter(parser_t *parser, ast_value *array,
func = fval->constval.vfunc;
fval->expression.next = (ast_expression*)ast_value_new(ast_ctx(array), "<void>", TYPE_VOID);
body = ast_block_new(ast_ctx(array));
if (!body) {
parseerror(parser, "failed to create block for array accessor");
goto cleanup;
}
entity = ast_value_new(ast_ctx(array), "entity", TYPE_ENTITY);
index = ast_value_new(ast_ctx(array), "index", TYPE_FLOAT);
value = ast_value_copy((ast_value*)array->expression.next);
@ -2515,12 +2514,10 @@ static bool parser_create_array_field_setter(parser_t *parser, ast_value *array,
goto cleanup;
}
vec_push(body->exprs, root);
vec_push(func->blocks, body);
vec_push(func->blocks[0]->exprs, root);
array->setter = fval;
return true;
cleanup:
if (body) ast_delete(body);
if (entity) ast_delete(entity);
if (index) ast_delete(index);
if (value) ast_delete(value);
@ -2533,7 +2530,6 @@ cleanup:
static bool parser_create_array_getter(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname)
{
ast_expression *root = NULL;
ast_block *body = NULL;
ast_value *index = NULL;
ast_value *fval;
ast_function *func;
@ -2551,12 +2547,6 @@ static bool parser_create_array_getter(parser_t *parser, ast_value *array, const
func = fval->constval.vfunc;
fval->expression.next = ast_type_copy(ast_ctx(array), elemtype);
body = ast_block_new(ast_ctx(array));
if (!body) {
parseerror(parser, "failed to create block for array accessor");
goto cleanup;
}
index = ast_value_new(ast_ctx(array), "index", TYPE_FLOAT);
if (!index) {
@ -2571,12 +2561,10 @@ static bool parser_create_array_getter(parser_t *parser, ast_value *array, const
goto cleanup;
}
vec_push(body->exprs, root);
vec_push(func->blocks, body);
vec_push(func->blocks[0]->exprs, root);
array->getter = fval;
return true;
cleanup:
if (body) ast_delete(body);
if (index) ast_delete(index);
if (root) ast_delete(root);
ast_delete(func);
@ -2649,8 +2637,8 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
}
/* sanity check */
if (vec_size(params) > 8)
parseerror(parser, "more than 8 parameters are currently not supported");
if (vec_size(params) > 8 && opts_standard == COMPILER_QCC)
(void)!parsewarning(parser, WARN_EXTENSIONS, "more than 8 parameters are not supported by this standard");
/* parse-out */
if (!parser_next(parser)) {
@ -3431,7 +3419,17 @@ bool parser_compile_file(const char *filename)
{
parser->lex = lex_open(filename);
if (!parser->lex) {
con_out("failed to open file \"%s\"\n", filename);
con_err("failed to open file \"%s\"\n", filename);
return false;
}
return parser_compile();
}
bool parser_compile_string_len(const char *name, const char *str, size_t len)
{
parser->lex = lex_open_string(str, len, name);
if (!parser->lex) {
con_err("failed to create lexer for string \"%s\"\n", name);
return false;
}
return parser_compile();
@ -3441,7 +3439,7 @@ bool parser_compile_string(const char *name, const char *str)
{
parser->lex = lex_open_string(str, strlen(str), name);
if (!parser->lex) {
con_out("failed to create lexer for string \"%s\"\n", name);
con_err("failed to create lexer for string \"%s\"\n", name);
return false;
}
return parser_compile();
@ -3450,6 +3448,11 @@ bool parser_compile_string(const char *name, const char *str)
void parser_cleanup()
{
size_t i;
for (i = 0; i < vec_size(parser->accessors); ++i) {
ast_delete(parser->accessors[i]->constval.vfunc);
parser->accessors[i]->constval.vfunc = NULL;
ast_delete(parser->accessors[i]);
}
for (i = 0; i < vec_size(parser->functions); ++i) {
ast_delete(parser->functions[i]);
}
@ -3470,6 +3473,7 @@ void parser_cleanup()
ast_delete(parser->globals[i].var);
mem_d(parser->globals[i].name);
}
vec_free(parser->accessors);
vec_free(parser->functions);
vec_free(parser->imm_vector);
vec_free(parser->imm_string);