mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2024-11-24 12:51:04 +00:00
Merge branch 'cooking'
This commit is contained in:
commit
462c06d56b
49 changed files with 2075 additions and 583 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -7,10 +7,12 @@
|
||||||
testsuite
|
testsuite
|
||||||
qcvm
|
qcvm
|
||||||
gmqcc
|
gmqcc
|
||||||
|
pak
|
||||||
|
|
||||||
distro/arch/*
|
distro/archlinux/*
|
||||||
|
distro/archbsd/*
|
||||||
!distro/archlinux/git/PKGBUILD
|
!distro/archlinux/git/PKGBUILD
|
||||||
!distro/archlinux/release/PKGBUILD
|
!distro/archlinux/release/PKGBUILD
|
||||||
!distro/archbsd/release/PKGBUILD
|
!distro/archbsd/release/PKGBUILD
|
||||||
!distro/archbsd/git/PKGBUILD
|
!distro/archbsd/git/PKGBUILD
|
||||||
!distro/arch/this/Makefile
|
!distro/archlinux/this/Makefile
|
||||||
|
|
27
CHANGES
27
CHANGES
|
@ -1,10 +1,12 @@
|
||||||
Release v0.2.4
|
Release v0.2.9
|
||||||
* Preprocessor:
|
* Preprocessor:
|
||||||
- __VA_ARGS__ support
|
- __VA_ARGS__ support
|
||||||
|
_ __VA_ARGS__ indexing
|
||||||
- Predefined macros like __DATE__, __TIME__, ...
|
- Predefined macros like __DATE__, __TIME__, ...
|
||||||
(check the manpage for a full list)
|
(check the manpage for a full list)
|
||||||
- Signed numbers as single token in the
|
- Signed numbers as single token in the
|
||||||
- Fixes some issues with #if operations on macros.
|
- Fixes some issues with #if operations on macros.
|
||||||
|
- Speed improvements
|
||||||
* Language:
|
* Language:
|
||||||
- Untyped `nil` keyword.
|
- Untyped `nil` keyword.
|
||||||
- Removed the `noreturn` keyword.
|
- Removed the `noreturn` keyword.
|
||||||
|
@ -21,6 +23,8 @@ Release v0.2.4
|
||||||
- Type restricted variadict parameters:
|
- Type restricted variadict parameters:
|
||||||
ie: void print(string...);
|
ie: void print(string...);
|
||||||
- Accessing varargs from QC via: ...(index, type)
|
- Accessing varargs from QC via: ...(index, type)
|
||||||
|
- New operators: ** (exponentiation), % (modulo), etc
|
||||||
|
- Enumeration attributes: flag, reverse
|
||||||
* Compilation:
|
* Compilation:
|
||||||
- Various optimizations and progs-size reductions.
|
- Various optimizations and progs-size reductions.
|
||||||
- A new spell-checking algorithm tries to hint you at existing
|
- A new spell-checking algorithm tries to hint you at existing
|
||||||
|
@ -29,16 +33,35 @@ Release v0.2.4
|
||||||
have been solved in both DP and our own executor. A new
|
have been solved in both DP and our own executor. A new
|
||||||
compatbility option (enabled by default) has been added for
|
compatbility option (enabled by default) has been added for
|
||||||
now: -flegacy-vector-maths
|
now: -flegacy-vector-maths
|
||||||
* qcvm:
|
- Compiler intrinsics: __builtin_floor, __builtin_mod,
|
||||||
|
__builtin_exp, __builtin_isnan
|
||||||
|
- Improved memory tracing
|
||||||
|
- Speed improvements
|
||||||
|
* QCVM:
|
||||||
- Improved commandline argument handling.
|
- Improved commandline argument handling.
|
||||||
- More builtins: sqrt(), normalize()
|
- More builtins: sqrt(), normalize()
|
||||||
* Commandline:
|
* Commandline:
|
||||||
|
- Nicer memory dumps
|
||||||
- Support for making individual warnings an error
|
- Support for making individual warnings an error
|
||||||
- via -Werror-<warning>
|
- via -Werror-<warning>
|
||||||
- added --add-info
|
- added --add-info
|
||||||
* Testsuite:
|
* Testsuite:
|
||||||
- Support for QCFLAGS to run tests with several additional
|
- Support for QCFLAGS to run tests with several additional
|
||||||
flags.
|
flags.
|
||||||
|
- Added support for preprocessor tests
|
||||||
|
- Added preprocessor tests
|
||||||
|
- 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
|
||||||
|
* Build:
|
||||||
|
- Build scripts for building debian, archlinux and archbsd
|
||||||
|
packages for x86, and x86_64.
|
||||||
|
- Makefile targets for gource visualization, and render of
|
||||||
|
gource visualization.
|
||||||
|
|
||||||
|
|
||||||
2012-12-27 Hotfix v0.2.2
|
2012-12-27 Hotfix v0.2.2
|
||||||
* Liferanges
|
* Liferanges
|
||||||
|
|
76
Makefile
76
Makefile
|
@ -1,4 +1,5 @@
|
||||||
DESTDIR :=
|
DESTDIR :=
|
||||||
|
OPTIONAL:=
|
||||||
PREFIX := /usr/local
|
PREFIX := /usr/local
|
||||||
BINDIR := $(PREFIX)/bin
|
BINDIR := $(PREFIX)/bin
|
||||||
DATADIR := $(PREFIX)/share
|
DATADIR := $(PREFIX)/share
|
||||||
|
@ -9,7 +10,7 @@ CYGWIN = $(findstring CYGWIN, $(UNAME))
|
||||||
MINGW = $(findstring MINGW32, $(UNAME))
|
MINGW = $(findstring MINGW32, $(UNAME))
|
||||||
|
|
||||||
CC ?= clang
|
CC ?= clang
|
||||||
CFLAGS += -Wall -Wextra -Werror -I. -fno-strict-aliasing -fsigned-char
|
CFLAGS += -Wall -Wextra -Werror -I. -fno-strict-aliasing -fsigned-char $(OPTIONAL)
|
||||||
ifneq ($(shell git describe --always 2>/dev/null),)
|
ifneq ($(shell git describe --always 2>/dev/null),)
|
||||||
CFLAGS += -DGMQCC_GITINFO="\"$(shell git describe --always)\""
|
CFLAGS += -DGMQCC_GITINFO="\"$(shell git describe --always)\""
|
||||||
endif
|
endif
|
||||||
|
@ -17,28 +18,28 @@ endif
|
||||||
# but also turn off the STUPID ONES
|
# but also turn off the STUPID ONES
|
||||||
ifeq ($(CC), clang)
|
ifeq ($(CC), clang)
|
||||||
CFLAGS += \
|
CFLAGS += \
|
||||||
-Weverything \
|
-Weverything \
|
||||||
-Wno-padded \
|
-Wno-padded \
|
||||||
-Wno-format-nonliteral \
|
-Wno-format-nonliteral \
|
||||||
-Wno-disabled-macro-expansion \
|
-Wno-disabled-macro-expansion \
|
||||||
-Wno-conversion \
|
-Wno-conversion \
|
||||||
-Wno-missing-prototypes \
|
-Wno-missing-prototypes \
|
||||||
-Wno-float-equal \
|
-Wno-float-equal \
|
||||||
-Wno-cast-align \
|
-Wno-cast-align \
|
||||||
-Wno-missing-variable-declarations \
|
-Wno-missing-variable-declarations \
|
||||||
-Wno-unknown-warning-option
|
-Wno-unknown-warning-option
|
||||||
else
|
else
|
||||||
#Tiny C Compiler doesn't know what -pedantic-errors is
|
#Tiny C Compiler doesn't know what -pedantic-errors is
|
||||||
# and instead of ignoring .. just errors.
|
# and instead of ignoring .. just errors.
|
||||||
ifneq ($(CC), tcc)
|
ifneq ($(CC), tcc)
|
||||||
CFLAGS +=-pedantic-errors
|
CFLAGS +=-pedantic-errors -ffunction-sections -fdata-sections -Wl,-gc-sections
|
||||||
else
|
else
|
||||||
CFLAGS += -Wno-pointer-sign -fno-common
|
CFLAGS += -Wno-pointer-sign -fno-common
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(track), no)
|
ifeq ($(track), no)
|
||||||
CFLAGS += -DNOTRACK
|
CFLAGS += -DNOTRACK
|
||||||
endif
|
endif
|
||||||
|
|
||||||
OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o
|
OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o
|
||||||
|
@ -84,6 +85,36 @@ else
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
#gource flags
|
||||||
|
GOURCEFLAGS= \
|
||||||
|
--date-format "%d %B, %Y" \
|
||||||
|
--seconds-per-day 0.01 \
|
||||||
|
--auto-skip-seconds 1 \
|
||||||
|
--title "GMQCC" \
|
||||||
|
--key \
|
||||||
|
--camera-mode overview \
|
||||||
|
--highlight-all-users \
|
||||||
|
--file-idle-time 0 \
|
||||||
|
--hide progress,mouse \
|
||||||
|
--stop-at-end \
|
||||||
|
--max-files 99999999999 \
|
||||||
|
--max-file-lag 0.000001 \
|
||||||
|
--bloom-multiplier 1.3 \
|
||||||
|
-1280x720
|
||||||
|
|
||||||
|
#ffmpeg flags for gource
|
||||||
|
FFMPEGFLAGS= \
|
||||||
|
-y \
|
||||||
|
-r 60 \
|
||||||
|
-f image2pipe \
|
||||||
|
-vcodec ppm \
|
||||||
|
-i - \
|
||||||
|
-vcodec libx264 \
|
||||||
|
-preset ultrafast \
|
||||||
|
-crf 1 \
|
||||||
|
-threads 0 \
|
||||||
|
-bf 0
|
||||||
|
|
||||||
#splint flags
|
#splint flags
|
||||||
SPLINTFLAGS = \
|
SPLINTFLAGS = \
|
||||||
-redef \
|
-redef \
|
||||||
|
@ -119,7 +150,6 @@ SPLINTFLAGS = \
|
||||||
-kepttrans \
|
-kepttrans \
|
||||||
-unqualifiedtrans \
|
-unqualifiedtrans \
|
||||||
+matchanyintegral \
|
+matchanyintegral \
|
||||||
-bufferoverflowhigh \
|
|
||||||
+voidabstract \
|
+voidabstract \
|
||||||
-nullassign \
|
-nullassign \
|
||||||
-unrecog \
|
-unrecog \
|
||||||
|
@ -147,7 +177,7 @@ $(QCVM): $(OBJ_X)
|
||||||
$(CC) -o $@ $^ $(CFLAGS) -lm
|
$(CC) -o $@ $^ $(CFLAGS) -lm
|
||||||
|
|
||||||
$(GMQCC): $(OBJ_C) $(OBJ_D)
|
$(GMQCC): $(OBJ_C) $(OBJ_D)
|
||||||
$(CC) -o $@ $^ $(CFLAGS)
|
$(CC) -o $@ $^ $(CFLAGS) -lm
|
||||||
|
|
||||||
$(TESTSUITE): $(OBJ_T)
|
$(TESTSUITE): $(OBJ_T)
|
||||||
$(CC) -o $@ $^ $(CFLAGS) -lm
|
$(CC) -o $@ $^ $(CFLAGS) -lm
|
||||||
|
@ -163,11 +193,17 @@ test: all
|
||||||
@ ./$(TESTSUITE)
|
@ ./$(TESTSUITE)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat
|
rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat gource.mp4
|
||||||
|
|
||||||
splint:
|
splint:
|
||||||
@ splint $(SPLINTFLAGS) *.c *.h
|
@ splint $(SPLINTFLAGS) *.c *.h
|
||||||
|
|
||||||
|
gource:
|
||||||
|
@ gource $(GOURCEFLAGS)
|
||||||
|
|
||||||
|
gource-record:
|
||||||
|
@ gource $(GOURCEFLAGS) -o - | ffmpeg $(FFMPEGFLAGS) gource.mp4
|
||||||
|
|
||||||
depend:
|
depend:
|
||||||
@makedepend -Y -w 65536 2> /dev/null \
|
@makedepend -Y -w 65536 2> /dev/null \
|
||||||
$(subst .o,.c,$(OBJ_D))
|
$(subst .o,.c,$(OBJ_D))
|
||||||
|
@ -219,9 +255,15 @@ fs.o: gmqcc.h opts.def
|
||||||
|
|
||||||
main.o: gmqcc.h opts.def lexer.h
|
main.o: gmqcc.h opts.def lexer.h
|
||||||
lexer.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
|
parser.o: gmqcc.h opts.def lexer.h ast.h ir.h intrin.h
|
||||||
fs.o: gmqcc.h opts.def
|
fs.o: gmqcc.h opts.def
|
||||||
|
|
||||||
util.o: gmqcc.h opts.def
|
util.o: gmqcc.h opts.def
|
||||||
conout.o: gmqcc.h opts.def
|
conout.o: gmqcc.h opts.def
|
||||||
fs.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
|
||||||
|
|
12
README
12
README
|
@ -1,10 +1,14 @@
|
||||||
GMQCC: An improved Quake C compiler
|
GMQCC: An improved Quake C compiler
|
||||||
|
|
||||||
For licensing: see the LICENSE file.
|
For licensing: see the LICENSE file.
|
||||||
For installation notes: see the INSTALL file.
|
For installation notes: see the INSTALL file.
|
||||||
For a list of authors: see the AUTHORS file.
|
For a list of authors: see the AUTHORS file.
|
||||||
For a list of changes: see the CHANGES file.
|
For a list of changes: see the CHANGES file.
|
||||||
|
|
||||||
For documentation:
|
For documentation:
|
||||||
See the manpages, or visit the documentation online at
|
See the manpages, or visit the documentation online at
|
||||||
http://graphitemaster.github.com/gmqcc/doc.html
|
http://graphitemaster.github.com/gmqcc/doc.html
|
||||||
|
|
||||||
|
For syntax highlighting description files, or information
|
||||||
|
regarding how to install them:
|
||||||
|
See the README in syntax directory
|
||||||
|
|
24
ast.c
24
ast.c
|
@ -42,7 +42,7 @@ static GMQCC_NORETURN void _ast_node_destroy(ast_node *self)
|
||||||
{
|
{
|
||||||
(void)self;
|
(void)self;
|
||||||
con_err("ast node missing destroy()\n");
|
con_err("ast node missing destroy()\n");
|
||||||
abort();
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize main ast node aprts */
|
/* Initialize main ast node aprts */
|
||||||
|
@ -87,6 +87,8 @@ static void ast_expression_delete(ast_expression *self)
|
||||||
ast_delete(self->expression.params[i]);
|
ast_delete(self->expression.params[i]);
|
||||||
}
|
}
|
||||||
vec_free(self->expression.params);
|
vec_free(self->expression.params);
|
||||||
|
if (self->expression.varparam)
|
||||||
|
ast_delete(self->expression.varparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ast_expression_delete_full(ast_expression *self)
|
static void ast_expression_delete_full(ast_expression *self)
|
||||||
|
@ -218,7 +220,7 @@ static size_t ast_type_to_string_impl(ast_expression *e, char *buf, size_t bufsi
|
||||||
if (!e) {
|
if (!e) {
|
||||||
if (pos + 6 >= bufsize)
|
if (pos + 6 >= bufsize)
|
||||||
goto full;
|
goto full;
|
||||||
strcpy(buf + pos, "(null)");
|
strncpy(buf + pos, "(null)", 6);
|
||||||
return pos + 6;
|
return pos + 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +229,7 @@ static size_t ast_type_to_string_impl(ast_expression *e, char *buf, size_t bufsi
|
||||||
|
|
||||||
switch (e->expression.vtype) {
|
switch (e->expression.vtype) {
|
||||||
case TYPE_VARIANT:
|
case TYPE_VARIANT:
|
||||||
strcpy(buf + pos, "(variant)");
|
strncpy(buf + pos, "(variant)", 9);
|
||||||
return pos + 9;
|
return pos + 9;
|
||||||
|
|
||||||
case TYPE_FIELD:
|
case TYPE_FIELD:
|
||||||
|
@ -284,7 +286,7 @@ static size_t ast_type_to_string_impl(ast_expression *e, char *buf, size_t bufsi
|
||||||
typelen = strlen(typestr);
|
typelen = strlen(typestr);
|
||||||
if (pos + typelen >= bufsize)
|
if (pos + typelen >= bufsize)
|
||||||
goto full;
|
goto full;
|
||||||
strcpy(buf + pos, typestr);
|
strncpy(buf + pos, typestr, typelen);
|
||||||
return pos + typelen;
|
return pos + typelen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,6 +586,7 @@ void ast_member_delete(ast_member *self)
|
||||||
* purpose that is not garbage-collected.
|
* purpose that is not garbage-collected.
|
||||||
*/
|
*/
|
||||||
ast_expression_delete((ast_expression*)self);
|
ast_expression_delete((ast_expression*)self);
|
||||||
|
mem_d(self->name);
|
||||||
mem_d(self);
|
mem_d(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1216,7 +1219,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
|
||||||
|
|
||||||
namelen = strlen(self->name);
|
namelen = strlen(self->name);
|
||||||
name = (char*)mem_a(namelen + 16);
|
name = (char*)mem_a(namelen + 16);
|
||||||
strcpy(name, self->name);
|
strncpy(name, self->name, namelen);
|
||||||
|
|
||||||
array->ir_values = (ir_value**)mem_a(sizeof(array->ir_values[0]) * array->expression.count);
|
array->ir_values = (ir_value**)mem_a(sizeof(array->ir_values[0]) * array->expression.count);
|
||||||
array->ir_values[0] = v;
|
array->ir_values[0] = v;
|
||||||
|
@ -1274,7 +1277,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
|
||||||
|
|
||||||
namelen = strlen(self->name);
|
namelen = strlen(self->name);
|
||||||
name = (char*)mem_a(namelen + 16);
|
name = (char*)mem_a(namelen + 16);
|
||||||
strcpy(name, self->name);
|
strncpy(name, self->name, namelen);
|
||||||
|
|
||||||
self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->expression.count);
|
self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->expression.count);
|
||||||
self->ir_values[0] = v;
|
self->ir_values[0] = v;
|
||||||
|
@ -1407,7 +1410,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
|
||||||
|
|
||||||
v = ir_function_create_local(func, self->name, vtype, param);
|
v = ir_function_create_local(func, self->name, vtype, param);
|
||||||
if (!v) {
|
if (!v) {
|
||||||
compile_error(ast_ctx(self), "ir_function_create_local failed");
|
compile_error(ast_ctx(self), "internal error: ir_function_create_local failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
v->context = ast_ctx(self);
|
v->context = ast_ctx(self);
|
||||||
|
@ -1416,20 +1419,21 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
|
||||||
|
|
||||||
namelen = strlen(self->name);
|
namelen = strlen(self->name);
|
||||||
name = (char*)mem_a(namelen + 16);
|
name = (char*)mem_a(namelen + 16);
|
||||||
strcpy(name, self->name);
|
strncpy(name, self->name, namelen);
|
||||||
|
|
||||||
self->ir_values[0] = v;
|
self->ir_values[0] = v;
|
||||||
for (ai = 1; ai < self->expression.count; ++ai) {
|
for (ai = 1; ai < self->expression.count; ++ai) {
|
||||||
snprintf(name + namelen, 16, "[%u]", (unsigned int)ai);
|
snprintf(name + namelen, 16, "[%u]", (unsigned int)ai);
|
||||||
self->ir_values[ai] = ir_function_create_local(func, name, vtype, param);
|
self->ir_values[ai] = ir_function_create_local(func, name, vtype, param);
|
||||||
if (!self->ir_values[ai]) {
|
if (!self->ir_values[ai]) {
|
||||||
compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
|
compile_error(ast_ctx(self), "internal_error: ir_builder_create_global failed on `%s`", name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
self->ir_values[ai]->context = ast_ctx(self);
|
self->ir_values[ai]->context = ast_ctx(self);
|
||||||
self->ir_values[ai]->unique_life = true;
|
self->ir_values[ai]->unique_life = true;
|
||||||
self->ir_values[ai]->locked = true;
|
self->ir_values[ai]->locked = true;
|
||||||
}
|
}
|
||||||
|
mem_d(name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1538,7 +1542,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
|
||||||
|
|
||||||
irf = self->ir_func;
|
irf = self->ir_func;
|
||||||
if (!irf) {
|
if (!irf) {
|
||||||
compile_error(ast_ctx(self), "ast_function's related ast_value was not generated yet");
|
compile_error(ast_ctx(self), "internal error: ast_function's related ast_value was not generated yet");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
conout.c
6
conout.c
|
@ -168,7 +168,7 @@ static int win_fputs(FILE *h, const char *str) {
|
||||||
state = -1;
|
state = -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fs_file_putc(h, *str);
|
fs_file_write(str, 1, 1, stdout);
|
||||||
length ++;
|
length ++;
|
||||||
}
|
}
|
||||||
str++;
|
str++;
|
||||||
|
@ -282,10 +282,6 @@ int con_change(const char *out, const char *err) {
|
||||||
con_enablecolor();
|
con_enablecolor();
|
||||||
} else if (!(console.handle_err = fs_file_open(err, "w"))) return 0;
|
} else if (!(console.handle_err = fs_file_open(err, "w"))) return 0;
|
||||||
|
|
||||||
/* no buffering */
|
|
||||||
setvbuf(console.handle_out, NULL, _IONBF, 0);
|
|
||||||
setvbuf(console.handle_err, NULL, _IONBF, 0);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
distro/Makefile
Normal file
34
distro/Makefile
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
DROPBOX := dropbox_uploader.sh
|
||||||
|
UNAME := $(shell uname -m)
|
||||||
|
ifneq ($(shell uname -m), x86_64)
|
||||||
|
$(error Cannot build packages without an x86_64 capable CPU)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.NOTPARALLEL: base
|
||||||
|
.NOTPARALLEL: upload
|
||||||
|
|
||||||
|
base:
|
||||||
|
$(MAKE) -C deb/
|
||||||
|
$(MAKE) -C deb/ CARCH=i686
|
||||||
|
$(MAKE) -C archlinux/this/
|
||||||
|
$(MAKE) -C archlinux/this/ CARCH=i686
|
||||||
|
@mv deb/*.deb ./
|
||||||
|
@mv archlinux/this/*pkg.tar.xz ./
|
||||||
|
|
||||||
|
upload:
|
||||||
|
@echo "APPKEY:76vh3q42hnvmzm3" > dropbox_config
|
||||||
|
@echo "APPSECRET:tmeecht2cmh72xa" >> dropbox_config
|
||||||
|
@echo "ACCESS_LEVEL:sandbox" >> dropbox_config
|
||||||
|
@echo "OAUTH_ACCESS_TOKEN:w0bxzf0dft8edfq" >> dropbox_config
|
||||||
|
@echo "OAUTH_ACCESS_TOKEN_SECRET:9vosx7x8gy4kgjk" >> dropbox_config
|
||||||
|
@wget -q "http://raw.github.com/andreafabrizi/Dropbox-Uploader/master/dropbox_uploader.sh"
|
||||||
|
@chmod +x dropbox_uploader.sh
|
||||||
|
@sed -i -e "s/~\/.dropbox_uploader/.\/dropbox_config/g" $$(basename $(DROPBOX))
|
||||||
|
@find . -type f -regex ".*/.*\.\(xz\|deb\)" -exec ./$$(basename $(DROPBOX)) upload {} \;
|
||||||
|
@rm dropbox_config dropbox_uploader.sh
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f *.deb
|
||||||
|
@rm -f *.pkg.tar.xz
|
||||||
|
|
||||||
|
all: base upload
|
|
@ -47,9 +47,9 @@ check() {
|
||||||
package() {
|
package() {
|
||||||
cd "$srcdir"/"$_gitname"
|
cd "$srcdir"/"$_gitname"
|
||||||
msg "Compiling and installing to pkgdir this time..."
|
msg "Compiling and installing to pkgdir this time..."
|
||||||
gmake install DESTDIR=$pkgdir PREFIX=/usr/local MANDIR=/usr/local/man
|
gmake install DESTDIR=$pkgdir PREFIX=/usr
|
||||||
msg "Compiling done."
|
msg "Compiling done."
|
||||||
|
|
||||||
install -dm755 ${pkgdir}/usr/local/share/licenses/gmqcc
|
install -dm755 ${pkgdir}/usr/share/licenses/gmqcc
|
||||||
install -m644 LICENSE ${pkgdir}/usr/local/share/licenses/gmqcc/LICENSE
|
install -m644 LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,9 @@ check() {
|
||||||
package() {
|
package() {
|
||||||
cd "$srcdir"/"$_gitname"
|
cd "$srcdir"/"$_gitname"
|
||||||
msg "Compiling and installing to pkgdir this time..."
|
msg "Compiling and installing to pkgdir this time..."
|
||||||
gmake install DESTDIR=$pkgdir PREFIX=/usr/local MANDIR=/usr/local/man
|
gmake install DESTDIR=$pkgdir PREFIX=/usr
|
||||||
msg "Compiling done."
|
msg "Compiling done."
|
||||||
|
|
||||||
install -dm755 ${pkgdir}/usr/local/share/licenses/gmqcc
|
install -dm755 ${pkgdir}/usr/share/licenses/gmqcc
|
||||||
install -m644 LICENSE ${pkgdir}/usr/local/share/licenses/gmqcc/LICENSE
|
install -m644 LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
|
# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
|
||||||
|
|
||||||
pkgname=gmqcc-git
|
pkgname=gmqcc-git
|
||||||
pkgver=20130127
|
pkgver=0.2.524.gc6bd5e6
|
||||||
|
pkgver(){
|
||||||
|
cd gmqcc
|
||||||
|
git describe --tags | sed -e 's/^gmqcc\-//' -e 's/-/./g'
|
||||||
|
}
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="An Improved Quake C Compiler"
|
pkgdesc="An Improved Quake C Compiler"
|
||||||
arch=('i686' 'x86_64')
|
arch=('i686' 'x86_64')
|
||||||
|
@ -11,40 +15,25 @@ provides=('gmqcc=0.2.4')
|
||||||
makedepends=('git')
|
makedepends=('git')
|
||||||
url="https://github.com/graphitemaster/gmqcc.git"
|
url="https://github.com/graphitemaster/gmqcc.git"
|
||||||
license=('MIT')
|
license=('MIT')
|
||||||
|
source=('gmqcc::git://github.com/graphitemaster/gmqcc.git')
|
||||||
|
sha1sums=('SKIP')
|
||||||
|
|
||||||
_gitroot="git://github.com/graphitemaster/gmqcc.git"
|
|
||||||
_gitname="gmqcc"
|
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd $srcdir
|
|
||||||
msg "Connecting to the GIT server..."
|
|
||||||
if [[ -d $srcdir/$_gitname ]] ; then
|
|
||||||
cd $_gitname
|
|
||||||
msg "Removing build files..."
|
|
||||||
git clean -dfx
|
|
||||||
msg "Updating..."
|
|
||||||
git pull --no-tags
|
|
||||||
msg "The local files are updated."
|
|
||||||
else
|
|
||||||
msg "Cloning..."
|
|
||||||
git clone $_gitroot $_gitname --depth 1
|
|
||||||
msg "Clone done."
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg "Starting compilation..."
|
msg "Starting compilation..."
|
||||||
cd "$srcdir"/"$_gitname"
|
cd "$srcdir"/"gmqcc"
|
||||||
|
|
||||||
msg "Compiling..."
|
msg "Compiling..."
|
||||||
make
|
make
|
||||||
}
|
}
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
cd "$srcdir"/"$_gitname"
|
cd "$srcdir"/"gmqcc"
|
||||||
make check
|
make check
|
||||||
}
|
}
|
||||||
|
|
||||||
package() {
|
package() {
|
||||||
cd "$srcdir"/"$_gitname"
|
cd "$srcdir"/"gmqcc"
|
||||||
msg "Compiling and installing to pkgdir this time..."
|
msg "Compiling and installing to pkgdir this time..."
|
||||||
make install DESTDIR=$pkgdir PREFIX=/usr
|
make install DESTDIR=$pkgdir PREFIX=/usr
|
||||||
msg "Compiling done."
|
msg "Compiling done."
|
||||||
|
|
|
@ -9,7 +9,7 @@ depends=('glibc')
|
||||||
url="https://github.com/graphitemaster/gmqcc.git"
|
url="https://github.com/graphitemaster/gmqcc.git"
|
||||||
license=('MIT')
|
license=('MIT')
|
||||||
source=(gmqcc-$pkgver.zip::https://github.com/graphitemaster/gmqcc/zipball/$pkgver)
|
source=(gmqcc-$pkgver.zip::https://github.com/graphitemaster/gmqcc/zipball/$pkgver)
|
||||||
sha1sums=('8cd91dc13f70cd9d3767602bf3eb47a1906d9353')
|
sha1sums=('e0fe99af9a55d36cd9e0909a96d1b14f2db8b757')
|
||||||
|
|
||||||
_gitname=graphitemaster-gmqcc-de24486/
|
_gitname=graphitemaster-gmqcc-de24486/
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,17 @@ CARCH := $(shell uname -m)
|
||||||
PKGDIR := gmqcc-$(MAJOR).$(MINOR).$(PATCH)-$(PKGREL)-$(CARCH)
|
PKGDIR := gmqcc-$(MAJOR).$(MINOR).$(PATCH)-$(PKGREL)-$(CARCH)
|
||||||
PKG := $(PKGDIR).pkg.tar.xz
|
PKG := $(PKGDIR).pkg.tar.xz
|
||||||
PKGINFO := $(PKGDIR)/.PKGINFO
|
PKGINFO := $(PKGDIR)/.PKGINFO
|
||||||
|
DESTDIR := distro/archlinux/this/$(PKGDIR)
|
||||||
|
CFLAGS :=
|
||||||
|
|
||||||
base: clean
|
|
||||||
$(MAKE) -C $(BASEDIR) DESTDIR=distro/archlinux/this/$(PKGDIR) PREFIX=$(PREFIX) install
|
ifneq (, $(findstring i686, $(CARCH)))
|
||||||
|
CFLAGS := -m32
|
||||||
|
endif
|
||||||
|
|
||||||
|
base:
|
||||||
|
$(MAKE) -C $(BASEDIR) clean
|
||||||
|
$(MAKE) -C $(BASEDIR) OPTIONAL=$(CFLAGS) DESTDIR=$(DESTDIR) PREFIX=$(PREFIX) install
|
||||||
@echo "pkgname = gmqcc" > $(PKGINFO)
|
@echo "pkgname = gmqcc" > $(PKGINFO)
|
||||||
@echo "pkgver = $(MAJOR).$(MINOR).$(PATCH)-$(PKGREL)" >> $(PKGINFO)
|
@echo "pkgver = $(MAJOR).$(MINOR).$(PATCH)-$(PKGREL)" >> $(PKGINFO)
|
||||||
@echo "pkgdesc = An Improved Quake C Compiler" >> $(PKGINFO)
|
@echo "pkgdesc = An Improved Quake C Compiler" >> $(PKGINFO)
|
||||||
|
@ -34,7 +42,7 @@ base: clean
|
||||||
@rm -rf $(PKGDIR)
|
@rm -rf $(PKGDIR)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -f $(PKG)
|
$(MAKE) -C $(BASEDIR) clean
|
||||||
|
@rm -f *.pkg.tar.xz
|
||||||
|
|
||||||
all: base
|
all: base
|
||||||
|
|
|
@ -5,19 +5,39 @@ MAJOR := `sed -n -e '/GMQCC_VERSION_MAJOR/{s/.* .* //;p;q;}' $(HEADER)`
|
||||||
MINOR := `sed -n -e '/GMQCC_VERSION_MINOR/{s/.* .* //;p;q;}' $(HEADER)`
|
MINOR := `sed -n -e '/GMQCC_VERSION_MINOR/{s/.* .* //;p;q;}' $(HEADER)`
|
||||||
PATCH := `sed -n -e '/GMQCC_VERSION_PATCH/{s/.* .* //;p;q;}' $(HEADER)`
|
PATCH := `sed -n -e '/GMQCC_VERSION_PATCH/{s/.* .* //;p;q;}' $(HEADER)`
|
||||||
DEBDIR := gmqcc-$(MAJOR).$(MINOR).$(PATCH)
|
DEBDIR := gmqcc-$(MAJOR).$(MINOR).$(PATCH)
|
||||||
DEB := $(DEBDIR).deb
|
CARCH := $(shell uname -m)
|
||||||
|
DEB := $(DEBDIR)-$(CARCH).deb
|
||||||
|
CONTROL := $(DEBDIR)/DEBIAN/control
|
||||||
|
|
||||||
|
ifneq (, $(findstring i686, $(CARCH)))
|
||||||
|
CFLAGS := -m32
|
||||||
|
endif
|
||||||
|
|
||||||
base:
|
base:
|
||||||
|
$(MAKE) -C $(BASEDIR) clean
|
||||||
$(MAKE) -C $(BASEDIR) DESTDIR=distro/deb/$(DEBDIR) PREFIX=$(PREFIX) install
|
$(MAKE) -C $(BASEDIR) DESTDIR=distro/deb/$(DEBDIR) PREFIX=$(PREFIX) install
|
||||||
@install -d -m755 $(DEBDIR)/DEBIAN
|
@install -d -m755 $(DEBDIR)/DEBIAN
|
||||||
@cp control $(DEBDIR)/DEBIAN/control
|
@echo "Package: gmqcc" > $(CONTROL)
|
||||||
|
@echo "Version: $(MAJOR).$(MINOR).$(PATCH)" >> $(CONTROL)
|
||||||
|
@echo "Section: user/hidden" >> $(CONTROL)
|
||||||
|
@echo "Priority: optional" >> $(CONTROL)
|
||||||
|
@echo "Architecture: $(CARCH)" >> $(CONTROL)
|
||||||
|
@echo "Installed-Size: `du -ks $($(DEBDIR)/usr) | cut -f 1`" >> $(CONTROL)
|
||||||
|
@echo "Maintainer: Dale Weiler <killfieldengine@gmail.com>" >> $(CONTROL)
|
||||||
|
@echo "Description: An improved Quake C Compiler" >> $(CONTROL)
|
||||||
|
@echo " For an enduring period of time the options for a decent compiler for the Quake C programming language" >> $(CONTROL)
|
||||||
|
@echo " were confined to a specific compiler known as QCC. Attempts were made to extend and improve upon the" >> $(CONTROL)
|
||||||
|
@echo " design of QCC, but many foreseen the consequences of building on a broken foundation. The solution" >> $(CONTROL)
|
||||||
|
@echo " was obvious, a new compiler; one born from the NIH realm of sarcastic wit. We welcome you. You won't" >> $(CONTROL)
|
||||||
|
@echo " find a better Quake C compiler." >> $(CONTROL)
|
||||||
@tar czf data.tar.gz -C $(DEBDIR)/ . --exclude=DEBIAN
|
@tar czf data.tar.gz -C $(DEBDIR)/ . --exclude=DEBIAN
|
||||||
@tar czf control.tar.gz -C $(DEBDIR)/DEBIAN/ .
|
@tar czf control.tar.gz -C $(DEBDIR)/DEBIAN/ .
|
||||||
@echo 2.0 > debian-binary
|
@echo 2.0 > debian-binary
|
||||||
@ar r $(DEB) debian-binary control.tar.gz data.tar.gz
|
@ar r $(DEB) debian-binary control.tar.gz data.tar.gz
|
||||||
@rm -rf debian-binary control.tar.gz data.tar.gz $(DEBDIR)
|
@rm -rf debian-binary control.tar.gz data.tar.gz $(DEBDIR)
|
||||||
clean:
|
|
||||||
@rm -f $(DEB)
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C $(BASEDIR) clean
|
||||||
|
@rm -f *.deb
|
||||||
|
|
||||||
all: base
|
all: base
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
Package: gmqcc
|
|
||||||
Version: 0.3.0
|
|
||||||
Section: user/hidden
|
|
||||||
Priority: optional
|
|
||||||
Architecture: i386
|
|
||||||
Installed-Size: `du -ks usr|cut -f 1`
|
|
||||||
Maintainer: Dale Weiler <killfieldengine@gmail.com>
|
|
||||||
Description: An improved Quake C Compiler
|
|
||||||
For an enduring period of time the options for a decent compiler for the Quake C programming language
|
|
||||||
were confined to a specific compiler known as QCC. Attempts were made to extend and improve upon the
|
|
||||||
design of QCC, but many foreseen the consequences of building on a broken foundation. The solution
|
|
||||||
was obvious, a new compiler; one born from the NIH realm of sarcastic wit. We welcome you. You won't
|
|
||||||
find a better Quake C compiler.
|
|
14
exec.c
14
exec.c
|
@ -455,7 +455,6 @@ static void prog_print_statement(qc_program *prog, prog_section_statement *st)
|
||||||
else printf("(none)");
|
else printf("(none)");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static qcint prog_enterfunction(qc_program *prog, prog_section_function *func)
|
static qcint prog_enterfunction(qc_program *prog, prog_section_function *func)
|
||||||
|
@ -825,6 +824,16 @@ static int qc_strcmp(qc_program *prog)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qc_floor(qc_program *prog)
|
||||||
|
{
|
||||||
|
qcany *num, out;
|
||||||
|
CheckArgs(1);
|
||||||
|
num = GetArg(0);
|
||||||
|
out._float = floor(num->_float);
|
||||||
|
Return(out);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static prog_builtin qc_builtins[] = {
|
static prog_builtin qc_builtins[] = {
|
||||||
NULL,
|
NULL,
|
||||||
&qc_print, /* 1 */
|
&qc_print, /* 1 */
|
||||||
|
@ -839,7 +848,8 @@ static prog_builtin qc_builtins[] = {
|
||||||
&qc_strcat, /* 10 */
|
&qc_strcat, /* 10 */
|
||||||
&qc_strcmp, /* 11 */
|
&qc_strcmp, /* 11 */
|
||||||
&qc_normalize, /* 12 */
|
&qc_normalize, /* 12 */
|
||||||
&qc_sqrt /* 13 */
|
&qc_sqrt, /* 13 */
|
||||||
|
&qc_floor /* 14 */
|
||||||
};
|
};
|
||||||
static size_t qc_builtins_count = sizeof(qc_builtins) / sizeof(qc_builtins[0]);
|
static size_t qc_builtins_count = sizeof(qc_builtins) / sizeof(qc_builtins[0]);
|
||||||
|
|
||||||
|
|
23
fs.c
23
fs.c
|
@ -53,7 +53,7 @@
|
||||||
) {
|
) {
|
||||||
wprintf(L"Invalid parameter dectected %s:%d %s [%s]\n", file, line, function, expression);
|
wprintf(L"Invalid parameter dectected %s:%d %s [%s]\n", file, line, function, expression);
|
||||||
wprintf(L"Aborting ...\n");
|
wprintf(L"Aborting ...\n");
|
||||||
abort();
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void file_init() {
|
static void file_init() {
|
||||||
|
@ -165,16 +165,6 @@ int fs_file_seek(FILE *fp, long int off, int whence) {
|
||||||
return fseek(fp, off, whence);
|
return fseek(fp, off, whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fs_file_putc(FILE *fp, int ch) {
|
|
||||||
/* Invokes file_exception on windows if fp is null */
|
|
||||||
return fputc(ch, fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fs_file_flush(FILE *fp) {
|
|
||||||
/* Invokes file_exception on windows if fp is null */
|
|
||||||
return fflush(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
long int fs_file_tell(FILE *fp) {
|
long int fs_file_tell(FILE *fp) {
|
||||||
/* Invokes file_exception on windows if fp is null */
|
/* Invokes file_exception on windows if fp is null */
|
||||||
return ftell(fp);
|
return ftell(fp);
|
||||||
|
@ -238,7 +228,7 @@ int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
strcpy(dir->dd_name, name);
|
strncpy(dir->dd_name, name, strlen(name));
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,8 +248,8 @@ int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
|
||||||
if (*dir->dd_name) {
|
if (*dir->dd_name) {
|
||||||
size_t n = strlen(dir->dd_name);
|
size_t n = strlen(dir->dd_name);
|
||||||
if ((dirname = (char*)mem_a(n + 5) /* 4 + 1 */)) {
|
if ((dirname = (char*)mem_a(n + 5) /* 4 + 1 */)) {
|
||||||
strcpy(dirname, dir->dd_name);
|
strncpy(dirname, dir->dd_name, n);
|
||||||
strcpy(dirname + n, "\\*.*"); /* 4 + 1 */
|
strncpy(dirname + n, "\\*.*", 4); /* 4 + 1 */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!(dirname = util_strdup("\\*.*")))
|
if (!(dirname = util_strdup("\\*.*")))
|
||||||
|
@ -303,7 +293,6 @@ int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
|
||||||
#else
|
#else
|
||||||
# if !defined(__MINGW32__)
|
# if !defined(__MINGW32__)
|
||||||
# include <sys/stat.h> /* mkdir */
|
# include <sys/stat.h> /* mkdir */
|
||||||
# include <unistd.h> /* chdir */
|
|
||||||
|
|
||||||
int fs_dir_make(const char *path) {
|
int fs_dir_make(const char *path) {
|
||||||
return mkdir(path, 0700);
|
return mkdir(path, 0700);
|
||||||
|
@ -326,8 +315,4 @@ struct dirent *fs_dir_read(DIR *dir) {
|
||||||
return readdir(dir);
|
return readdir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fs_dir_change(const char *path) {
|
|
||||||
return chdir(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /*! defined(_WIN32) && !defined(__MINGW32__) */
|
#endif /*! defined(_WIN32) && !defined(__MINGW32__) */
|
||||||
|
|
123
ftepp.c
123
ftepp.c
|
@ -25,6 +25,7 @@
|
||||||
#include "gmqcc.h"
|
#include "gmqcc.h"
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
|
||||||
|
#define HT_MACROS 1024
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool on;
|
bool on;
|
||||||
bool was_on;
|
bool was_on;
|
||||||
|
@ -55,14 +56,15 @@ typedef struct {
|
||||||
pptoken **output;
|
pptoken **output;
|
||||||
} ppmacro;
|
} ppmacro;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct ftepp_s {
|
||||||
lex_file *lex;
|
lex_file *lex;
|
||||||
int token;
|
int token;
|
||||||
unsigned int errors;
|
unsigned int errors;
|
||||||
|
|
||||||
bool output_on;
|
bool output_on;
|
||||||
ppcondition *conditions;
|
ppcondition *conditions;
|
||||||
ppmacro **macros;
|
/*ppmacro **macros;*/
|
||||||
|
ht macros; /* hashtable<string, ppmacro*> */
|
||||||
|
|
||||||
char *output_string;
|
char *output_string;
|
||||||
|
|
||||||
|
@ -124,7 +126,7 @@ char *ftepp_predef_line(lex_file *context) {
|
||||||
char *ftepp_predef_file(lex_file *context) {
|
char *ftepp_predef_file(lex_file *context) {
|
||||||
size_t length = strlen(context->name) + 3; /* two quotes and a terminator */
|
size_t length = strlen(context->name) + 3; /* two quotes and a terminator */
|
||||||
char *value = (char*)mem_a(length);
|
char *value = (char*)mem_a(length);
|
||||||
sprintf(value, "\"%s\"", context->name);
|
snprintf(value, length, "\"%s\"", context->name);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -225,7 +227,7 @@ static pptoken *pptoken_make(ftepp_t *ftepp)
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pptoken_delete(pptoken *self)
|
static GMQCC_INLINE void pptoken_delete(pptoken *self)
|
||||||
{
|
{
|
||||||
mem_d(self->value);
|
mem_d(self->value);
|
||||||
mem_d(self);
|
mem_d(self);
|
||||||
|
@ -261,27 +263,27 @@ static ftepp_t* ftepp_new()
|
||||||
ftepp = (ftepp_t*)mem_a(sizeof(*ftepp));
|
ftepp = (ftepp_t*)mem_a(sizeof(*ftepp));
|
||||||
memset(ftepp, 0, sizeof(*ftepp));
|
memset(ftepp, 0, sizeof(*ftepp));
|
||||||
|
|
||||||
|
ftepp->macros = util_htnew(HT_MACROS);
|
||||||
ftepp->output_on = true;
|
ftepp->output_on = true;
|
||||||
|
|
||||||
return ftepp;
|
return ftepp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ftepp_flush_do(ftepp_t *self)
|
static GMQCC_INLINE void ftepp_flush_do(ftepp_t *self)
|
||||||
{
|
{
|
||||||
vec_free(self->output_string);
|
vec_free(self->output_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ftepp_delete(ftepp_t *self)
|
static void ftepp_delete(ftepp_t *self)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
ftepp_flush_do(self);
|
ftepp_flush_do(self);
|
||||||
if (self->itemname)
|
if (self->itemname)
|
||||||
mem_d(self->itemname);
|
mem_d(self->itemname);
|
||||||
if (self->includename)
|
if (self->includename)
|
||||||
vec_free(self->includename);
|
vec_free(self->includename);
|
||||||
for (i = 0; i < vec_size(self->macros); ++i)
|
|
||||||
ppmacro_delete(self->macros[i]);
|
util_htrem(self->macros, (void (*)(void*))&ppmacro_delete);
|
||||||
vec_free(self->macros);
|
|
||||||
vec_free(self->conditions);
|
vec_free(self->conditions);
|
||||||
if (self->lex)
|
if (self->lex)
|
||||||
lex_close(self->lex);
|
lex_close(self->lex);
|
||||||
|
@ -300,7 +302,7 @@ static void ftepp_out(ftepp_t *ftepp, const char *str, bool ignore_cond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ftepp_update_output_condition(ftepp_t *ftepp)
|
static GMQCC_INLINE void ftepp_update_output_condition(ftepp_t *ftepp)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
ftepp->output_on = true;
|
ftepp->output_on = true;
|
||||||
|
@ -308,25 +310,14 @@ static void ftepp_update_output_condition(ftepp_t *ftepp)
|
||||||
ftepp->output_on = ftepp->output_on && ftepp->conditions[i].on;
|
ftepp->output_on = ftepp->output_on && ftepp->conditions[i].on;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ppmacro* ftepp_macro_find(ftepp_t *ftepp, const char *name)
|
static GMQCC_INLINE ppmacro* ftepp_macro_find(ftepp_t *ftepp, const char *name)
|
||||||
{
|
{
|
||||||
size_t i;
|
return util_htget(ftepp->macros, name);
|
||||||
for (i = 0; i < vec_size(ftepp->macros); ++i) {
|
|
||||||
if (!strcmp(name, ftepp->macros[i]->name))
|
|
||||||
return ftepp->macros[i];
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ftepp_macro_delete(ftepp_t *ftepp, const char *name)
|
static GMQCC_INLINE void ftepp_macro_delete(ftepp_t *ftepp, const char *name)
|
||||||
{
|
{
|
||||||
size_t i;
|
util_htrm(ftepp->macros, name, NULL);
|
||||||
for (i = 0; i < vec_size(ftepp->macros); ++i) {
|
|
||||||
if (!strcmp(name, ftepp->macros[i]->name)) {
|
|
||||||
vec_remove(ftepp->macros, i, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GMQCC_INLINE int ftepp_next(ftepp_t *ftepp)
|
static GMQCC_INLINE int ftepp_next(ftepp_t *ftepp)
|
||||||
|
@ -394,6 +385,7 @@ static bool ftepp_define_params(ftepp_t *ftepp, ppmacro *macro)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} while (ftepp->token == ',');
|
} while (ftepp->token == ',');
|
||||||
|
|
||||||
if (ftepp->token != ')') {
|
if (ftepp->token != ')') {
|
||||||
ftepp_error(ftepp, "expected closing paren after macro parameter list");
|
ftepp_error(ftepp, "expected closing paren after macro parameter list");
|
||||||
return false;
|
return false;
|
||||||
|
@ -422,7 +414,7 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = atoi(ftepp_tokval(ftepp));
|
index = (int)strtol(ftepp_tokval(ftepp), NULL, 10);
|
||||||
|
|
||||||
if (ftepp_next(ftepp) != ']') {
|
if (ftepp_next(ftepp) != ']') {
|
||||||
ftepp_error(ftepp, "expected `]` in __VA_ARGS__ subscript");
|
ftepp_error(ftepp, "expected `]` in __VA_ARGS__ subscript");
|
||||||
|
@ -471,7 +463,7 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
|
||||||
|
|
||||||
static bool ftepp_define(ftepp_t *ftepp)
|
static bool ftepp_define(ftepp_t *ftepp)
|
||||||
{
|
{
|
||||||
ppmacro *macro;
|
ppmacro *macro = NULL;
|
||||||
size_t l = ftepp_ctx(ftepp).line;
|
size_t l = ftepp_ctx(ftepp).line;
|
||||||
|
|
||||||
(void)ftepp_next(ftepp);
|
(void)ftepp_next(ftepp);
|
||||||
|
@ -499,18 +491,28 @@ static bool ftepp_define(ftepp_t *ftepp)
|
||||||
|
|
||||||
if (ftepp->token == '(') {
|
if (ftepp->token == '(') {
|
||||||
macro->has_params = true;
|
macro->has_params = true;
|
||||||
if (!ftepp_define_params(ftepp, macro))
|
if (!ftepp_define_params(ftepp, macro)) {
|
||||||
|
ppmacro_delete(macro);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ftepp_skipspace(ftepp))
|
if (!ftepp_skipspace(ftepp)) {
|
||||||
|
ppmacro_delete(macro);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ftepp_define_body(ftepp, macro))
|
if (!ftepp_define_body(ftepp, macro)) {
|
||||||
|
ppmacro_delete(macro);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (ftepp->output_on)
|
if (ftepp->output_on)
|
||||||
vec_push(ftepp->macros, macro);
|
vec_push(ftepp->macros, macro);
|
||||||
|
#endif
|
||||||
|
if (ftepp->output_on)
|
||||||
|
util_htset(ftepp->macros, macro->name, (void*)macro);
|
||||||
else {
|
else {
|
||||||
ppmacro_delete(macro);
|
ppmacro_delete(macro);
|
||||||
}
|
}
|
||||||
|
@ -830,7 +832,7 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
|
||||||
|
|
||||||
if (resetline && !ftepp->in_macro) {
|
if (resetline && !ftepp->in_macro) {
|
||||||
char lineno[128];
|
char lineno[128];
|
||||||
sprintf(lineno, "\n#pragma line(%lu)\n", (unsigned long)(old_lexer->sline));
|
snprintf(lineno, 128, "\n#pragma line(%lu)\n", (unsigned long)(old_lexer->sline));
|
||||||
ftepp_out(ftepp, lineno, false);
|
ftepp_out(ftepp, lineno, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1706,9 +1708,7 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
|
||||||
/* Like in parser.c - files keep the previous state so we have one global
|
/* Like in parser.c - files keep the previous state so we have one global
|
||||||
* preprocessor. Except here we will want to warn about dangling #ifs.
|
* preprocessor. Except here we will want to warn about dangling #ifs.
|
||||||
*/
|
*/
|
||||||
static ftepp_t *ftepp;
|
static bool ftepp_preprocess_done(ftepp_t *ftepp)
|
||||||
|
|
||||||
static bool ftepp_preprocess_done()
|
|
||||||
{
|
{
|
||||||
bool retval = true;
|
bool retval = true;
|
||||||
if (vec_size(ftepp->conditions)) {
|
if (vec_size(ftepp->conditions)) {
|
||||||
|
@ -1724,7 +1724,7 @@ static bool ftepp_preprocess_done()
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ftepp_preprocess_file(const char *filename)
|
bool ftepp_preprocess_file(ftepp_t *ftepp, const char *filename)
|
||||||
{
|
{
|
||||||
ftepp->lex = lex_open(filename);
|
ftepp->lex = lex_open(filename);
|
||||||
ftepp->itemname = util_strdup(filename);
|
ftepp->itemname = util_strdup(filename);
|
||||||
|
@ -1734,10 +1734,10 @@ bool ftepp_preprocess_file(const char *filename)
|
||||||
}
|
}
|
||||||
if (!ftepp_preprocess(ftepp))
|
if (!ftepp_preprocess(ftepp))
|
||||||
return false;
|
return false;
|
||||||
return ftepp_preprocess_done();
|
return ftepp_preprocess_done(ftepp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ftepp_preprocess_string(const char *name, const char *str)
|
bool ftepp_preprocess_string(ftepp_t *ftepp, const char *name, const char *str)
|
||||||
{
|
{
|
||||||
ftepp->lex = lex_open_string(str, strlen(str), name);
|
ftepp->lex = lex_open_string(str, strlen(str), name);
|
||||||
ftepp->itemname = util_strdup(name);
|
ftepp->itemname = util_strdup(name);
|
||||||
|
@ -1747,16 +1747,16 @@ bool ftepp_preprocess_string(const char *name, const char *str)
|
||||||
}
|
}
|
||||||
if (!ftepp_preprocess(ftepp))
|
if (!ftepp_preprocess(ftepp))
|
||||||
return false;
|
return false;
|
||||||
return ftepp_preprocess_done();
|
return ftepp_preprocess_done(ftepp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ftepp_add_macro(const char *name, const char *value) {
|
void ftepp_add_macro(ftepp_t *ftepp, const char *name, const char *value) {
|
||||||
char *create = NULL;
|
char *create = NULL;
|
||||||
|
|
||||||
/* use saner path for empty macros */
|
/* use saner path for empty macros */
|
||||||
if (!value) {
|
if (!value) {
|
||||||
ftepp_add_define("__builtin__", name);
|
ftepp_add_define(ftepp, "__builtin__", name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1766,26 +1766,27 @@ void ftepp_add_macro(const char *name, const char *value) {
|
||||||
vec_upload(create, value, strlen(value));
|
vec_upload(create, value, strlen(value));
|
||||||
vec_push (create, 0);
|
vec_push (create, 0);
|
||||||
|
|
||||||
ftepp_preprocess_string("__builtin__", create);
|
ftepp_preprocess_string(ftepp, "__builtin__", create);
|
||||||
vec_free (create);
|
vec_free (create);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ftepp_init()
|
ftepp_t *ftepp_create()
|
||||||
{
|
{
|
||||||
|
ftepp_t *ftepp;
|
||||||
char minor[32];
|
char minor[32];
|
||||||
char major[32];
|
char major[32];
|
||||||
|
|
||||||
ftepp = ftepp_new();
|
ftepp = ftepp_new();
|
||||||
if (!ftepp)
|
if (!ftepp)
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
memset(minor, 0, sizeof(minor));
|
memset(minor, 0, sizeof(minor));
|
||||||
memset(major, 0, sizeof(major));
|
memset(major, 0, sizeof(major));
|
||||||
|
|
||||||
/* set the right macro based on the selected standard */
|
/* set the right macro based on the selected standard */
|
||||||
ftepp_add_define(NULL, "GMQCC");
|
ftepp_add_define(ftepp, NULL, "GMQCC");
|
||||||
if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC) {
|
if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC) {
|
||||||
ftepp_add_define(NULL, "__STD_FTEQCC__");
|
ftepp_add_define(ftepp, NULL, "__STD_FTEQCC__");
|
||||||
/* 1.00 */
|
/* 1.00 */
|
||||||
major[0] = '"';
|
major[0] = '"';
|
||||||
major[1] = '1';
|
major[1] = '1';
|
||||||
|
@ -1795,15 +1796,15 @@ bool ftepp_init()
|
||||||
minor[1] = '0';
|
minor[1] = '0';
|
||||||
minor[2] = '"';
|
minor[2] = '"';
|
||||||
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
|
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
|
||||||
ftepp_add_define(NULL, "__STD_GMQCC__");
|
ftepp_add_define(ftepp, NULL, "__STD_GMQCC__");
|
||||||
sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR);
|
snprintf(major, 32, "\"%d\"", GMQCC_VERSION_MAJOR);
|
||||||
sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR);
|
snprintf(minor, 32, "\"%d\"", GMQCC_VERSION_MINOR);
|
||||||
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCCX) {
|
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCCX) {
|
||||||
ftepp_add_define(NULL, "__STD_QCCX__");
|
ftepp_add_define(ftepp, NULL, "__STD_QCCX__");
|
||||||
sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR);
|
snprintf(major, 32, "\"%d\"", GMQCC_VERSION_MAJOR);
|
||||||
sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR);
|
snprintf(minor, 32, "\"%d\"", GMQCC_VERSION_MINOR);
|
||||||
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
|
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
|
||||||
ftepp_add_define(NULL, "__STD_QCC__");
|
ftepp_add_define(ftepp, NULL, "__STD_QCC__");
|
||||||
/* 1.0 */
|
/* 1.0 */
|
||||||
major[0] = '"';
|
major[0] = '"';
|
||||||
major[1] = '1';
|
major[1] = '1';
|
||||||
|
@ -1814,35 +1815,35 @@ bool ftepp_init()
|
||||||
minor[2] = '"';
|
minor[2] = '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
ftepp_add_macro("__STD_VERSION_MINOR__", minor);
|
ftepp_add_macro(ftepp, "__STD_VERSION_MINOR__", minor);
|
||||||
ftepp_add_macro("__STD_VERSION_MAJOR__", major);
|
ftepp_add_macro(ftepp, "__STD_VERSION_MAJOR__", major);
|
||||||
|
|
||||||
return true;
|
return ftepp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ftepp_add_define(const char *source, const char *name)
|
void ftepp_add_define(ftepp_t *ftepp, const char *source, const char *name)
|
||||||
{
|
{
|
||||||
ppmacro *macro;
|
ppmacro *macro;
|
||||||
lex_ctx ctx = { "__builtin__", 0 };
|
lex_ctx ctx = { "__builtin__", 0 };
|
||||||
ctx.file = source;
|
ctx.file = source;
|
||||||
macro = ppmacro_new(ctx, name);
|
macro = ppmacro_new(ctx, name);
|
||||||
vec_push(ftepp->macros, macro);
|
/*vec_push(ftepp->macros, macro);*/
|
||||||
|
util_htset(ftepp->macros, name, macro);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *ftepp_get()
|
const char *ftepp_get(ftepp_t *ftepp)
|
||||||
{
|
{
|
||||||
return ftepp->output_string;
|
return ftepp->output_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ftepp_flush()
|
void ftepp_flush(ftepp_t *ftepp)
|
||||||
{
|
{
|
||||||
ftepp_flush_do(ftepp);
|
ftepp_flush_do(ftepp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ftepp_finish()
|
void ftepp_finish(ftepp_t *ftepp)
|
||||||
{
|
{
|
||||||
if (!ftepp)
|
if (!ftepp)
|
||||||
return;
|
return;
|
||||||
ftepp_delete(ftepp);
|
ftepp_delete(ftepp);
|
||||||
ftepp = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
103
gmqcc.h
103
gmqcc.h
|
@ -300,7 +300,8 @@ void util_meminfo ();
|
||||||
bool util_filexists (const char *);
|
bool util_filexists (const char *);
|
||||||
bool util_strupper (const char *);
|
bool util_strupper (const char *);
|
||||||
bool util_strdigit (const char *);
|
bool util_strdigit (const char *);
|
||||||
char *util_strdup (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_debug (const char *, const char *, ...);
|
||||||
void util_endianswap (void *, size_t, unsigned int);
|
void util_endianswap (void *, size_t, unsigned int);
|
||||||
|
|
||||||
|
@ -317,15 +318,20 @@ int util_asprintf (char **ret, const char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
#ifdef NOTRACK
|
#ifdef NOTRACK
|
||||||
# define mem_a(x) malloc (x)
|
# define mem_a(x) malloc (x)
|
||||||
# define mem_d(x) free ((void*)x)
|
# define mem_d(x) free ((void*)x)
|
||||||
# define mem_r(x, n) realloc((void*)x, n)
|
# define mem_r(x, n) realloc((void*)x, n)
|
||||||
|
# define mem_af(x,f,l) malloc (x)
|
||||||
#else
|
#else
|
||||||
# define mem_a(x) util_memory_a((x), __LINE__, __FILE__)
|
# define mem_a(x) util_memory_a((x), __LINE__, __FILE__)
|
||||||
# define mem_d(x) util_memory_d((void*)(x))
|
# define mem_d(x) util_memory_d((void*)(x))
|
||||||
# define mem_r(x, n) util_memory_r((void*)(x), (n), __LINE__, __FILE__)
|
# 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 */
|
#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
|
* A flexible vector implementation: all vector pointers contain some
|
||||||
* data about themselfs exactly - sizeof(vector_t) behind the pointer
|
* data about themselfs exactly - sizeof(vector_t) behind the pointer
|
||||||
|
@ -374,14 +380,6 @@ typedef struct hash_table_t {
|
||||||
struct hash_node_t **table;
|
struct hash_node_t **table;
|
||||||
} hash_table_t, *ht;
|
} hash_table_t, *ht;
|
||||||
|
|
||||||
typedef struct hash_set_t {
|
|
||||||
size_t bits;
|
|
||||||
size_t mask;
|
|
||||||
size_t capacity;
|
|
||||||
size_t *items;
|
|
||||||
size_t total;
|
|
||||||
} hash_set_t, *hs;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hashtable implementation:
|
* hashtable implementation:
|
||||||
*
|
*
|
||||||
|
@ -413,52 +411,17 @@ typedef struct hash_set_t {
|
||||||
* util_htdel(foo);
|
* util_htdel(foo);
|
||||||
*/
|
*/
|
||||||
hash_table_t *util_htnew (size_t size);
|
hash_table_t *util_htnew (size_t size);
|
||||||
|
void util_htrem (hash_table_t *ht, void (*callback)(void *data));
|
||||||
void util_htset (hash_table_t *ht, const char *key, void *value);
|
void util_htset (hash_table_t *ht, const char *key, void *value);
|
||||||
void util_htdel (hash_table_t *ht);
|
void util_htdel (hash_table_t *ht);
|
||||||
size_t util_hthash(hash_table_t *ht, const char *key);
|
size_t util_hthash(hash_table_t *ht, const char *key);
|
||||||
void util_htseth(hash_table_t *ht, const char *key, size_t hash, void *value);
|
void util_htseth(hash_table_t *ht, const char *key, size_t hash, void *value);
|
||||||
|
void util_htrmh (hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*));
|
||||||
|
void util_htrm (hash_table_t *ht, const char *key, void (*cb)(void*));
|
||||||
|
|
||||||
void *util_htget (hash_table_t *ht, const char *key);
|
void *util_htget (hash_table_t *ht, const char *key);
|
||||||
void *util_htgeth(hash_table_t *ht, const char *key, size_t hash);
|
void *util_htgeth(hash_table_t *ht, const char *key, size_t hash);
|
||||||
|
|
||||||
/*
|
|
||||||
* hashset implementation:
|
|
||||||
* This was designed for pointers: you manage the life of the object yourself
|
|
||||||
* if you do use this for non-pointers please be warned that the object may not
|
|
||||||
* be valid if the duration of it exceeds (i.e on stack). So you need to allocate
|
|
||||||
* yourself, or put those in global scope to ensure duration is for the whole
|
|
||||||
* runtime.
|
|
||||||
*
|
|
||||||
* util_hsnew() -- to make a new hashset
|
|
||||||
* util_hsadd(set, key) -- to add something in the set
|
|
||||||
* util_hshas(set, key) -- to check if something is in the set
|
|
||||||
* util_hsrem(set, key) -- to remove something in the set
|
|
||||||
* util_hsdel(set) -- to delete the set
|
|
||||||
*
|
|
||||||
* example of use:
|
|
||||||
*
|
|
||||||
* hs foo = util_hsnew();
|
|
||||||
* char *bar = "hello blub\n";
|
|
||||||
* char *baz = "hello dale\n";
|
|
||||||
*
|
|
||||||
* util_hsadd(foo, bar);
|
|
||||||
* util_hsadd(foo, baz);
|
|
||||||
* util_hsrem(foo, baz);
|
|
||||||
*
|
|
||||||
* printf("bar %d | baz %d\n",
|
|
||||||
* util_hshas(foo, bar),
|
|
||||||
* util_hshad(foo, baz)
|
|
||||||
* );
|
|
||||||
*
|
|
||||||
* util_hsdel(foo);
|
|
||||||
*/
|
|
||||||
|
|
||||||
hash_set_t *util_hsnew(void);
|
|
||||||
int util_hsadd(hash_set_t *, void *);
|
|
||||||
int util_hshas(hash_set_t *, void *);
|
|
||||||
int util_hsrem(hash_set_t *, void *);
|
|
||||||
void util_hsdel(hash_set_t *);
|
|
||||||
|
|
||||||
/*===================================================================*/
|
/*===================================================================*/
|
||||||
/*============================ file.c ===============================*/
|
/*============================ file.c ===============================*/
|
||||||
/*===================================================================*/
|
/*===================================================================*/
|
||||||
|
@ -466,10 +429,8 @@ void util_hsdel(hash_set_t *);
|
||||||
void fs_file_close (FILE *);
|
void fs_file_close (FILE *);
|
||||||
int fs_file_error (FILE *);
|
int fs_file_error (FILE *);
|
||||||
int fs_file_getc (FILE *);
|
int fs_file_getc (FILE *);
|
||||||
int fs_file_flush (FILE *);
|
|
||||||
int fs_file_printf (FILE *, const char *, ...);
|
int fs_file_printf (FILE *, const char *, ...);
|
||||||
int fs_file_puts (FILE *, const char *);
|
int fs_file_puts (FILE *, const char *);
|
||||||
int fs_file_putc (FILE *, int);
|
|
||||||
int fs_file_seek (FILE *, long int, int);
|
int fs_file_seek (FILE *, long int, int);
|
||||||
long int fs_file_tell (FILE *);
|
long int fs_file_tell (FILE *);
|
||||||
|
|
||||||
|
@ -480,11 +441,10 @@ FILE *fs_file_open (const char *, const char *);
|
||||||
int fs_file_getline(char **, size_t *, FILE *);
|
int fs_file_getline(char **, size_t *, FILE *);
|
||||||
|
|
||||||
/* directory handling */
|
/* directory handling */
|
||||||
|
int fs_dir_make (const char *);
|
||||||
DIR *fs_dir_open (const char *);
|
DIR *fs_dir_open (const char *);
|
||||||
int fs_dir_close (DIR *);
|
int fs_dir_close (DIR *);
|
||||||
struct dirent *fs_dir_read (DIR *);
|
struct dirent *fs_dir_read (DIR *);
|
||||||
int fs_dir_make (const char *);
|
|
||||||
int fs_dir_change (const char *);
|
|
||||||
|
|
||||||
|
|
||||||
/*===================================================================*/
|
/*===================================================================*/
|
||||||
|
@ -1025,17 +985,20 @@ qcint prog_tempstring(qc_program *prog, const char *_str);
|
||||||
/*===================================================================*/
|
/*===================================================================*/
|
||||||
/*===================== parser.c commandline ========================*/
|
/*===================== parser.c commandline ========================*/
|
||||||
/*===================================================================*/
|
/*===================================================================*/
|
||||||
|
struct parser_s;
|
||||||
|
|
||||||
bool parser_init ();
|
struct parser_s *parser_create ();
|
||||||
bool parser_compile_file (const char *);
|
bool parser_compile_file (struct parser_s *parser, const char *);
|
||||||
bool parser_compile_string(const char *, const char *, size_t);
|
bool parser_compile_string(struct parser_s *parser, const char *, const char *, size_t);
|
||||||
bool parser_finish (const char *);
|
bool parser_finish (struct parser_s *parser, const char *);
|
||||||
void parser_cleanup ();
|
void parser_cleanup (struct parser_s *parser);
|
||||||
|
|
||||||
/*===================================================================*/
|
/*===================================================================*/
|
||||||
/*====================== ftepp.c commandline ========================*/
|
/*====================== ftepp.c commandline ========================*/
|
||||||
/*===================================================================*/
|
/*===================================================================*/
|
||||||
struct lex_file_s;
|
struct lex_file_s;
|
||||||
|
struct ftepp_s;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
char *(*func)(struct lex_file_s *);
|
char *(*func)(struct lex_file_s *);
|
||||||
|
@ -1047,14 +1010,14 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
#define FTEPP_PREDEF_COUNT 8
|
#define FTEPP_PREDEF_COUNT 8
|
||||||
|
|
||||||
bool ftepp_init ();
|
struct ftepp_s *ftepp_create ();
|
||||||
bool ftepp_preprocess_file (const char *filename);
|
bool ftepp_preprocess_file (struct ftepp_s *ftepp, const char *filename);
|
||||||
bool ftepp_preprocess_string(const char *name, const char *str);
|
bool ftepp_preprocess_string(struct ftepp_s *ftepp, const char *name, const char *str);
|
||||||
void ftepp_finish ();
|
void ftepp_finish (struct ftepp_s *ftepp);
|
||||||
const char *ftepp_get ();
|
const char *ftepp_get (struct ftepp_s *ftepp);
|
||||||
void ftepp_flush ();
|
void ftepp_flush (struct ftepp_s *ftepp);
|
||||||
void ftepp_add_define (const char *source, const char *name);
|
void ftepp_add_define (struct ftepp_s *ftepp, const char *source, const char *name);
|
||||||
void ftepp_add_macro (const char *name, const char *value);
|
void ftepp_add_macro (struct ftepp_s *ftepp, const char *name, const char *value);
|
||||||
|
|
||||||
extern const ftepp_predef_t ftepp_predefs[FTEPP_PREDEF_COUNT];
|
extern const ftepp_predef_t ftepp_predefs[FTEPP_PREDEF_COUNT];
|
||||||
|
|
||||||
|
|
418
intrin.h
Normal file
418
intrin.h
Normal file
|
@ -0,0 +1,418 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012, 2013
|
||||||
|
* Dale Weiler
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Provides all the "intrinsics" / "builtins" for GMQCC. These can do
|
||||||
|
* a few things, they can provide fall back implementations for math
|
||||||
|
* functions if the definitions don't exist for some given engine. Or
|
||||||
|
* then can determine definitions for existing builtins, and simply
|
||||||
|
* wrap back to them instead. This is like a "portable" intrface that
|
||||||
|
* is entered when -fintrin is used (causing all existing builtins to
|
||||||
|
* be ignored by the compiler and instead interface through here.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
ast_expression *(*intrin)(parser_t *);
|
||||||
|
const char *name;
|
||||||
|
const char *alias;
|
||||||
|
} intrin_t;
|
||||||
|
|
||||||
|
ht intrin_intrinsics() {
|
||||||
|
static ht intrinsics = NULL;
|
||||||
|
if (!intrinsics)
|
||||||
|
intrinsics = util_htnew(PARSER_HT_SIZE);
|
||||||
|
|
||||||
|
return intrinsics;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INTRIN_VAL(VALUE, NAME, FUNC, STYPE, VTYPE) \
|
||||||
|
do { \
|
||||||
|
(VALUE) = ast_value_new ( \
|
||||||
|
parser_ctx(parser), \
|
||||||
|
"__builtin_" NAME, \
|
||||||
|
TYPE_FUNCTION \
|
||||||
|
); \
|
||||||
|
(VALUE)->expression.next = (ast_expression*)ast_value_new ( \
|
||||||
|
parser_ctx(parser), \
|
||||||
|
STYPE, \
|
||||||
|
VTYPE \
|
||||||
|
); \
|
||||||
|
(FUNC) = ast_function_new ( \
|
||||||
|
parser_ctx(parser), \
|
||||||
|
"__builtin_" NAME, \
|
||||||
|
(VALUE) \
|
||||||
|
); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define INTRIN_REG(FUNC, VALUE) \
|
||||||
|
do { \
|
||||||
|
vec_push(parser->functions, (FUNC)); \
|
||||||
|
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) {
|
||||||
|
/*
|
||||||
|
* float pow(float x, float y) {
|
||||||
|
* float local = 1.0f;
|
||||||
|
* while (y > 0) {
|
||||||
|
* while (!(y & 1)) {
|
||||||
|
* y >>= 2;
|
||||||
|
* x *= x;
|
||||||
|
* }
|
||||||
|
* y--;
|
||||||
|
* local *= x;
|
||||||
|
* }
|
||||||
|
* return local;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static ast_value *value = NULL;
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
ast_value *arg1 = ast_value_new(parser_ctx(parser), "x", TYPE_FLOAT);
|
||||||
|
ast_value *arg2 = ast_value_new(parser_ctx(parser), "y", TYPE_FLOAT);
|
||||||
|
ast_value *local = ast_value_new(parser_ctx(parser), "local", TYPE_FLOAT);
|
||||||
|
ast_block *body = ast_block_new(parser_ctx(parser));
|
||||||
|
ast_block *l1b = ast_block_new(parser_ctx(parser)); /* loop 1 body */
|
||||||
|
ast_block *l2b = ast_block_new(parser_ctx(parser)); /* looo 2 body */
|
||||||
|
ast_loop *loop1 = NULL;
|
||||||
|
ast_loop *loop2 = NULL;
|
||||||
|
ast_function *func = NULL;
|
||||||
|
|
||||||
|
INTRIN_VAL(value, "pow", func, "<float>", TYPE_FLOAT);
|
||||||
|
|
||||||
|
/* arguments */
|
||||||
|
vec_push(value->expression.params, arg1);
|
||||||
|
vec_push(value->expression.params, arg2);
|
||||||
|
|
||||||
|
/* local */
|
||||||
|
vec_push(body->locals, local);
|
||||||
|
|
||||||
|
/* assignment to local of value 1.0f */
|
||||||
|
vec_push(body->exprs,
|
||||||
|
(ast_expression*)ast_store_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_STORE_F,
|
||||||
|
(ast_expression*)local,
|
||||||
|
(ast_expression*)parser_const_float_1(parser)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/* y >>= 2 */
|
||||||
|
vec_push(l2b->exprs,
|
||||||
|
(ast_expression*)ast_binstore_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_STORE_F,
|
||||||
|
INSTR_MUL_F,
|
||||||
|
(ast_expression*)arg2,
|
||||||
|
(ast_expression*)parser_const_float(parser, 0.25f)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/* x *= x */
|
||||||
|
vec_push(l2b->exprs,
|
||||||
|
(ast_expression*)ast_binstore_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_STORE_F,
|
||||||
|
INSTR_MUL_F,
|
||||||
|
(ast_expression*)arg1,
|
||||||
|
(ast_expression*)arg1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/* while (!(y&1)) */
|
||||||
|
loop2 = ast_loop_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
NULL,
|
||||||
|
(ast_expression*)ast_binary_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_AND,
|
||||||
|
(ast_expression*)arg2,
|
||||||
|
(ast_expression*)parser_const_float_1(parser)
|
||||||
|
),
|
||||||
|
true, /* ! not */
|
||||||
|
NULL,
|
||||||
|
false,
|
||||||
|
NULL,
|
||||||
|
(ast_expression*)l2b
|
||||||
|
);
|
||||||
|
|
||||||
|
/* push nested loop into loop expressions */
|
||||||
|
vec_push(l1b->exprs, (ast_expression*)loop2);
|
||||||
|
|
||||||
|
/* y-- */
|
||||||
|
vec_push(l1b->exprs,
|
||||||
|
(ast_expression*)ast_binstore_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_STORE_F,
|
||||||
|
INSTR_SUB_F,
|
||||||
|
(ast_expression*)arg2,
|
||||||
|
(ast_expression*)parser_const_float_1(parser)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
/* local *= x */
|
||||||
|
vec_push(l1b->exprs,
|
||||||
|
(ast_expression*)ast_binstore_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_STORE_F,
|
||||||
|
INSTR_MUL_F,
|
||||||
|
(ast_expression*)local,
|
||||||
|
(ast_expression*)arg1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/* while (y > 0) */
|
||||||
|
loop1 = ast_loop_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
NULL,
|
||||||
|
(ast_expression*)ast_binary_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_GT,
|
||||||
|
(ast_expression*)arg2,
|
||||||
|
(ast_expression*)parser_const_float_0(parser)
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
NULL,
|
||||||
|
false,
|
||||||
|
NULL,
|
||||||
|
(ast_expression*)l1b
|
||||||
|
);
|
||||||
|
|
||||||
|
/* push the loop1 into the body for the function */
|
||||||
|
vec_push(body->exprs, (ast_expression*)loop1);
|
||||||
|
|
||||||
|
/* return local; */
|
||||||
|
vec_push(body->exprs,
|
||||||
|
(ast_expression*)ast_return_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
(ast_expression*)local
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/* push block and register intrin for codegen */
|
||||||
|
vec_push(func->blocks, body);
|
||||||
|
|
||||||
|
INTRIN_REG(func, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ast_expression*)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_expression *intrin_mod(parser_t *parser) {
|
||||||
|
/*
|
||||||
|
* float mod(float x, float y) {
|
||||||
|
* return x - y * floor(x / y);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static ast_value *value = NULL;
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
ast_call *call = ast_call_new (parser_ctx(parser), intrin_func(parser, "floor"));
|
||||||
|
ast_value *arg1 = ast_value_new(parser_ctx(parser), "x", TYPE_FLOAT);
|
||||||
|
ast_value *arg2 = ast_value_new(parser_ctx(parser), "y", TYPE_FLOAT);
|
||||||
|
ast_block *body = ast_block_new(parser_ctx(parser));
|
||||||
|
ast_function *func = NULL;
|
||||||
|
|
||||||
|
INTRIN_VAL(value, "mod", func, "<float>", TYPE_FLOAT);
|
||||||
|
|
||||||
|
/* floor(x/y) */
|
||||||
|
vec_push(call->params,
|
||||||
|
(ast_expression*)ast_binary_new (
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_DIV_F,
|
||||||
|
(ast_expression*)arg1,
|
||||||
|
(ast_expression*)arg2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec_push(body->exprs,
|
||||||
|
(ast_expression*)ast_return_new(
|
||||||
|
parser_ctx(parser),
|
||||||
|
(ast_expression*)ast_binary_new(
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_SUB_F,
|
||||||
|
(ast_expression*)arg1,
|
||||||
|
(ast_expression*)ast_binary_new(
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_MUL_F,
|
||||||
|
(ast_expression*)arg2,
|
||||||
|
(ast_expression*)call
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec_push(value->expression.params, arg1); /* float x (for param) */
|
||||||
|
vec_push(value->expression.params, arg2); /* float y (for param) */
|
||||||
|
|
||||||
|
vec_push(func->blocks, body); /* {{{ body }}} */
|
||||||
|
|
||||||
|
INTRIN_REG(func, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ast_expression*)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_expression *intrin_exp(parser_t *parser) {
|
||||||
|
/*
|
||||||
|
* float exp(float x) {
|
||||||
|
* return pow(QC_M_E, x);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static ast_value *value = NULL;
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
ast_call *call = ast_call_new (parser_ctx(parser), intrin_func(parser, "pow"));
|
||||||
|
ast_value *arg1 = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT);
|
||||||
|
ast_block *body = ast_block_new (parser_ctx(parser));
|
||||||
|
ast_function *func = NULL;
|
||||||
|
|
||||||
|
INTRIN_VAL(value, "exp", func, "<float>", TYPE_FLOAT);
|
||||||
|
|
||||||
|
/* push arguments for params to call */
|
||||||
|
vec_push(call->params, (ast_expression*)parser_const_float(parser, QC_M_E));
|
||||||
|
vec_push(call->params, (ast_expression*)arg1);
|
||||||
|
|
||||||
|
/* return pow(QC_M_E, x) */
|
||||||
|
vec_push(body->exprs,
|
||||||
|
(ast_expression*)ast_return_new(
|
||||||
|
parser_ctx(parser),
|
||||||
|
(ast_expression*)call
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec_push(value->expression.params, arg1); /* float x (for param) */
|
||||||
|
|
||||||
|
vec_push(func->blocks, body); /* {{{ body }}} */
|
||||||
|
|
||||||
|
INTRIN_REG(func, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ast_expression*)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_expression *intrin_isnan(parser_t *parser) {
|
||||||
|
/*
|
||||||
|
* float isnan(float x) {
|
||||||
|
* float local;
|
||||||
|
* local = x;
|
||||||
|
*
|
||||||
|
* return (x != local);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static ast_value *value = NULL;
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
ast_value *arg1 = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT);
|
||||||
|
ast_value *local = ast_value_new (parser_ctx(parser), "local", TYPE_FLOAT);
|
||||||
|
ast_block *body = ast_block_new (parser_ctx(parser));
|
||||||
|
ast_function *func = NULL;
|
||||||
|
|
||||||
|
INTRIN_VAL(value, "isnan", func, "<float>", TYPE_FLOAT);
|
||||||
|
|
||||||
|
vec_push(body->locals, local);
|
||||||
|
vec_push(body->exprs,
|
||||||
|
(ast_expression*)ast_store_new(
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_STORE_F,
|
||||||
|
(ast_expression*)local,
|
||||||
|
(ast_expression*)arg1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec_push(body->exprs,
|
||||||
|
(ast_expression*)ast_return_new(
|
||||||
|
parser_ctx(parser),
|
||||||
|
(ast_expression*)ast_binary_new(
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_NE_F,
|
||||||
|
(ast_expression*)arg1,
|
||||||
|
(ast_expression*)local
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec_push(value->expression.params, arg1);
|
||||||
|
|
||||||
|
vec_push(func->blocks, body);
|
||||||
|
|
||||||
|
INTRIN_REG(func, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ast_expression*)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static intrin_t intrinsics[] = {
|
||||||
|
{&intrin_exp, "__builtin_exp", "exp"},
|
||||||
|
{&intrin_mod, "__builtin_mod", "mod"},
|
||||||
|
{&intrin_pow, "__builtin_pow", "pow"},
|
||||||
|
{&intrin_isnan, "__builtin_isnan", "isnan"}
|
||||||
|
};
|
||||||
|
|
||||||
|
void intrin_intrinsics_destroy(parser_t *parser) {
|
||||||
|
/*size_t i;*/
|
||||||
|
(void)parser;
|
||||||
|
util_htdel(intrin_intrinsics());
|
||||||
|
#if 0
|
||||||
|
for (i = 0; i < sizeof(intrinsics)/sizeof(intrin_t); i++)
|
||||||
|
ast_value_delete( (ast_value*) intrinsics[i].intrin(parser));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ast_expression *intrin_func(parser_t *parser, const char *name) {
|
||||||
|
static bool init = false;
|
||||||
|
size_t i = 0;
|
||||||
|
void *find;
|
||||||
|
|
||||||
|
/* register the intrinsics in the hashtable for O(1) lookup */
|
||||||
|
if (!init) {
|
||||||
|
for (i = 0; i < sizeof(intrinsics)/sizeof(*intrinsics); i++)
|
||||||
|
util_htset(intrin_intrinsics(), intrinsics[i].alias, &intrinsics[i]);
|
||||||
|
|
||||||
|
init = true; /* only once */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* jesus fucking christ, Blub design something less fucking
|
||||||
|
* impossible to use, like a ast_is_builtin(ast_expression *), also
|
||||||
|
* use a hashtable :P
|
||||||
|
*/
|
||||||
|
if ((find = (void*)parser_find_global(parser, name)) && ((ast_value*)find)->expression.vtype == TYPE_FUNCTION)
|
||||||
|
for (i = 0; i < vec_size(parser->functions); ++i)
|
||||||
|
if (((ast_value*)find)->name && !strcmp(parser->functions[i]->name, ((ast_value*)find)->name) && parser->functions[i]->builtin < 0)
|
||||||
|
return find;
|
||||||
|
|
||||||
|
if ((find = util_htget(intrin_intrinsics(), name))) {
|
||||||
|
/* intrinsic is in table. This will "generate the function" so
|
||||||
|
* to speak (if it's not already generated).
|
||||||
|
*/
|
||||||
|
return ((intrin_t*)find)->intrin(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseerror(parser, "need function: `%s` compiler depends on it", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
19
ir.c
19
ir.c
|
@ -1206,22 +1206,11 @@ bool ir_value_set_field(ir_value *self, ir_value *fld)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *ir_strdup(const char *str)
|
|
||||||
{
|
|
||||||
if (str && !*str) {
|
|
||||||
/* actually dup empty strings */
|
|
||||||
char *out = (char*)mem_a(1);
|
|
||||||
*out = 0;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
return util_strdup(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ir_value_set_string(ir_value *self, const char *str)
|
bool ir_value_set_string(ir_value *self, const char *str)
|
||||||
{
|
{
|
||||||
if (self->vtype != TYPE_STRING)
|
if (self->vtype != TYPE_STRING)
|
||||||
return false;
|
return false;
|
||||||
self->constval.vstring = ir_strdup(str);
|
self->constval.vstring = util_strdupe(str);
|
||||||
self->hasvalue = true;
|
self->hasvalue = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1651,7 +1640,7 @@ void ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
|
||||||
* is doing something wrong.
|
* is doing something wrong.
|
||||||
*/
|
*/
|
||||||
irerror(self->context, "Invalid entry block for PHI");
|
irerror(self->context, "Invalid entry block for PHI");
|
||||||
abort();
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pe.value = v;
|
pe.value = v;
|
||||||
|
@ -3292,6 +3281,8 @@ static void gen_vector_defs(prog_section_def def, const char *name)
|
||||||
def.offset++;
|
def.offset++;
|
||||||
component[len-1]++;
|
component[len-1]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mem_d(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_vector_fields(prog_section_field fld, const char *name)
|
static void gen_vector_fields(prog_section_field fld, const char *name)
|
||||||
|
@ -3320,6 +3311,8 @@ static void gen_vector_fields(prog_section_field fld, const char *name)
|
||||||
fld.offset++;
|
fld.offset++;
|
||||||
component[len-1]++;
|
component[len-1]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mem_d(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal)
|
static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal)
|
||||||
|
|
25
lexer.c
25
lexer.c
|
@ -272,7 +272,7 @@ void lex_close(lex_file *lex)
|
||||||
static int lex_fgetc(lex_file *lex)
|
static int lex_fgetc(lex_file *lex)
|
||||||
{
|
{
|
||||||
if (lex->file)
|
if (lex->file)
|
||||||
return fgetc(lex->file);
|
return fs_file_getc(lex->file);
|
||||||
if (lex->open_string) {
|
if (lex->open_string) {
|
||||||
if (lex->open_string_pos >= lex->open_string_length)
|
if (lex->open_string_pos >= lex->open_string_length)
|
||||||
return EOF;
|
return EOF;
|
||||||
|
@ -483,6 +483,9 @@ static bool lex_try_pragma(lex_file *lex)
|
||||||
lex->line = line;
|
lex->line = line;
|
||||||
while (ch != '\n' && ch != EOF)
|
while (ch != '\n' && ch != EOF)
|
||||||
ch = lex_getch(lex);
|
ch = lex_getch(lex);
|
||||||
|
vec_free(command);
|
||||||
|
vec_free(param);
|
||||||
|
vec_free(pragma);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
unroll:
|
unroll:
|
||||||
|
@ -495,13 +498,13 @@ unroll:
|
||||||
vec_free(command);
|
vec_free(command);
|
||||||
lex_ungetch(lex, ' ');
|
lex_ungetch(lex, ' ');
|
||||||
}
|
}
|
||||||
if (command) {
|
if (param) {
|
||||||
vec_pop(command);
|
vec_pop(param);
|
||||||
while (vec_size(command)) {
|
while (vec_size(param)) {
|
||||||
lex_ungetch(lex, (unsigned char)vec_last(command));
|
lex_ungetch(lex, (unsigned char)vec_last(param));
|
||||||
vec_pop(command);
|
vec_pop(param);
|
||||||
}
|
}
|
||||||
vec_free(command);
|
vec_free(param);
|
||||||
lex_ungetch(lex, ' ');
|
lex_ungetch(lex, ' ');
|
||||||
}
|
}
|
||||||
if (pragma) {
|
if (pragma) {
|
||||||
|
@ -1352,7 +1355,7 @@ int lex_do(lex_file *lex)
|
||||||
lex_tokench(lex, ch);
|
lex_tokench(lex, ch);
|
||||||
|
|
||||||
nextch = lex_getch(lex);
|
nextch = lex_getch(lex);
|
||||||
if (nextch == '=') {
|
if (nextch == '=' || nextch == '*') {
|
||||||
lex_tokench(lex, nextch);
|
lex_tokench(lex, nextch);
|
||||||
} else
|
} else
|
||||||
lex_ungetch(lex, nextch);
|
lex_ungetch(lex, nextch);
|
||||||
|
@ -1361,6 +1364,12 @@ int lex_do(lex_file *lex)
|
||||||
return (lex->tok.ttype = TOKEN_OPERATOR);
|
return (lex->tok.ttype = TOKEN_OPERATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ch == '%') {
|
||||||
|
lex_tokench(lex, ch);
|
||||||
|
lex_endtoken(lex);
|
||||||
|
return (lex->tok.ttype = TOKEN_OPERATOR);
|
||||||
|
}
|
||||||
|
|
||||||
if (isident_start(ch))
|
if (isident_start(ch))
|
||||||
{
|
{
|
||||||
const char *v;
|
const char *v;
|
||||||
|
|
17
lexer.h
17
lexer.h
|
@ -166,18 +166,21 @@ typedef struct {
|
||||||
static const oper_info c_operators[] = {
|
static const oper_info c_operators[] = {
|
||||||
{ "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */
|
{ "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */
|
||||||
|
|
||||||
{ "++", 1, opid3('S','+','+'), ASSOC_LEFT, 15, OP_SUFFIX},
|
{ "++", 1, opid3('S','+','+'), ASSOC_LEFT, 17, OP_SUFFIX},
|
||||||
{ "--", 1, opid3('S','-','-'), ASSOC_LEFT, 15, OP_SUFFIX},
|
{ "--", 1, opid3('S','-','-'), ASSOC_LEFT, 17, OP_SUFFIX},
|
||||||
{ ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 },
|
{ ".", 2, opid1('.'), ASSOC_LEFT, 17, 0 },
|
||||||
{ "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */
|
{ "(", 0, opid1('('), ASSOC_LEFT, 17, 0 }, /* function call */
|
||||||
{ "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */
|
{ "[", 2, opid1('['), ASSOC_LEFT, 17, 0 }, /* array subscript */
|
||||||
|
|
||||||
|
{ "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 16, OP_PREFIX },
|
||||||
|
{ "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 16, OP_PREFIX },
|
||||||
|
|
||||||
|
{ "**", 2, opid2('*', '*'), ASSOC_RIGHT, 15, 0 },
|
||||||
|
|
||||||
{ "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
{ "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||||
{ "~", 1, opid2('~', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
{ "~", 1, opid2('~', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||||
{ "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
{ "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||||
{ "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
{ "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||||
{ "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
|
||||||
{ "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
|
||||||
/* { "&", 1, opid2('&','P'), ASSOC_RIGHT, 14, OP_PREFIX }, */
|
/* { "&", 1, opid2('&','P'), ASSOC_RIGHT, 14, OP_PREFIX }, */
|
||||||
|
|
||||||
{ "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 },
|
{ "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 },
|
||||||
|
|
60
main.c
60
main.c
|
@ -146,9 +146,10 @@ static bool options_parse(int argc, char **argv) {
|
||||||
bool argend = false;
|
bool argend = false;
|
||||||
size_t itr;
|
size_t itr;
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
char *redirout = NULL;
|
char *redirout = NULL;
|
||||||
char *redirerr = NULL;
|
char *redirerr = NULL;
|
||||||
char *config = NULL;
|
char *config = NULL;
|
||||||
|
char *memdumpcols = NULL;
|
||||||
|
|
||||||
while (!argend && argc > 1) {
|
while (!argend && argc > 1) {
|
||||||
char *argarg;
|
char *argarg;
|
||||||
|
@ -223,6 +224,10 @@ static bool options_parse(int argc, char **argv) {
|
||||||
config = argarg;
|
config = argarg;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (options_long_gcc("memdumpcols", &argc, &argv, &memdumpcols)) {
|
||||||
|
OPTS_OPTION_U16(OPTION_MEMDUMPCOLS) = (uint16_t)strtol(memdumpcols, NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* show defaults (like pathscale) */
|
/* show defaults (like pathscale) */
|
||||||
if (!strcmp(argv[0]+1, "show-defaults")) {
|
if (!strcmp(argv[0]+1, "show-defaults")) {
|
||||||
|
@ -403,7 +408,7 @@ static bool options_parse(int argc, char **argv) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isdigit(argarg[0])) {
|
if (isdigit(argarg[0])) {
|
||||||
uint32_t val = atoi(argarg);
|
uint32_t val = (uint32_t)strtol(argarg, NULL, 10);
|
||||||
OPTS_OPTION_U32(OPTION_O) = val;
|
OPTS_OPTION_U32(OPTION_O) = val;
|
||||||
opts_setoptimlevel(val);
|
opts_setoptimlevel(val);
|
||||||
} else {
|
} else {
|
||||||
|
@ -541,12 +546,14 @@ static bool progs_nextline(char **out, size_t *alen,FILE *src) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
size_t itr;
|
size_t itr;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
bool opts_output_free = false;
|
bool opts_output_free = false;
|
||||||
bool operators_free = false;
|
bool operators_free = false;
|
||||||
bool progs_src = false;
|
bool progs_src = false;
|
||||||
FILE *outfile = NULL;
|
FILE *outfile = NULL;
|
||||||
|
struct parser_s *parser = NULL;
|
||||||
|
struct ftepp_s *ftepp = NULL;
|
||||||
|
|
||||||
app_name = argv[0];
|
app_name = argv[0];
|
||||||
con_init ();
|
con_init ();
|
||||||
|
@ -621,7 +628,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
||||||
if (!parser_init()) {
|
if (!(parser = parser_create())) {
|
||||||
con_err("failed to initialize parser\n");
|
con_err("failed to initialize parser\n");
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -629,7 +636,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
|
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
|
||||||
if (!ftepp_init()) {
|
if (!(ftepp = ftepp_create())) {
|
||||||
con_err("failed to initialize parser\n");
|
con_err("failed to initialize parser\n");
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -644,7 +651,7 @@ int main(int argc, char **argv) {
|
||||||
/* add macros */
|
/* add macros */
|
||||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
|
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
|
||||||
for (itr = 0; itr < vec_size(ppems); itr++) {
|
for (itr = 0; itr < vec_size(ppems); itr++) {
|
||||||
ftepp_add_macro(ppems[itr].name, ppems[itr].value);
|
ftepp_add_macro(ftepp, ppems[itr].name, ppems[itr].value);
|
||||||
mem_d(ppems[itr].name);
|
mem_d(ppems[itr].name);
|
||||||
|
|
||||||
/* can be null */
|
/* can be null */
|
||||||
|
@ -703,6 +710,7 @@ srcdone:
|
||||||
con_out("Mode: %s\n", (progs_src ? "progs.src" : "manual"));
|
con_out("Mode: %s\n", (progs_src ? "progs.src" : "manual"));
|
||||||
con_out("There are %lu items to compile:\n", (unsigned long)vec_size(items));
|
con_out("There are %lu items to compile:\n", (unsigned long)vec_size(items));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (itr = 0; itr < vec_size(items); ++itr) {
|
for (itr = 0; itr < vec_size(items); ++itr) {
|
||||||
if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
|
if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
|
||||||
!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
|
!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
|
||||||
|
@ -717,33 +725,33 @@ srcdone:
|
||||||
|
|
||||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
||||||
const char *out;
|
const char *out;
|
||||||
if (!ftepp_preprocess_file(items[itr].filename)) {
|
if (!ftepp_preprocess_file(ftepp, items[itr].filename)) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
out = ftepp_get();
|
out = ftepp_get(ftepp);
|
||||||
if (out)
|
if (out)
|
||||||
fs_file_printf(outfile, "%s", out);
|
fs_file_printf(outfile, "%s", out);
|
||||||
ftepp_flush();
|
ftepp_flush(ftepp);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (OPTS_FLAG(FTEPP)) {
|
if (OPTS_FLAG(FTEPP)) {
|
||||||
const char *data;
|
const char *data;
|
||||||
if (!ftepp_preprocess_file(items[itr].filename)) {
|
if (!ftepp_preprocess_file(ftepp, items[itr].filename)) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
data = ftepp_get();
|
data = ftepp_get(ftepp);
|
||||||
if (vec_size(data)) {
|
if (vec_size(data)) {
|
||||||
if (!parser_compile_string(items[itr].filename, data, vec_size(data))) {
|
if (!parser_compile_string(parser, items[itr].filename, data, vec_size(data))) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ftepp_flush();
|
ftepp_flush(ftepp);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!parser_compile_file(items[itr].filename)) {
|
if (!parser_compile_file(parser, items[itr].filename)) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -756,9 +764,10 @@ srcdone:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ftepp_finish();
|
ftepp_finish(ftepp);
|
||||||
|
ftepp = NULL;
|
||||||
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
||||||
if (!parser_finish(OPTS_OPTION_STR(OPTION_OUTPUT))) {
|
if (!parser_finish(parser, OPTS_OPTION_STR(OPTION_OUTPUT))) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -778,13 +787,14 @@ srcdone:
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
util_debug("COM", "cleaning ...\n");
|
util_debug("COM", "cleaning ...\n");
|
||||||
ftepp_finish();
|
if (ftepp)
|
||||||
|
ftepp_finish(ftepp);
|
||||||
con_close();
|
con_close();
|
||||||
vec_free(items);
|
vec_free(items);
|
||||||
vec_free(ppems);
|
vec_free(ppems);
|
||||||
|
|
||||||
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
|
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
|
||||||
parser_cleanup();
|
parser_cleanup(parser);
|
||||||
if (opts_output_free)
|
if (opts_output_free)
|
||||||
mem_d(OPTS_OPTION_STR(OPTION_OUTPUT));
|
mem_d(OPTS_OPTION_STR(OPTION_OUTPUT));
|
||||||
if (operators_free)
|
if (operators_free)
|
||||||
|
|
4
opts.c
4
opts.c
|
@ -64,6 +64,7 @@ static void opts_setdefault() {
|
||||||
opts_set(opts.flags, BAIL_ON_WERROR, true);
|
opts_set(opts.flags, BAIL_ON_WERROR, true);
|
||||||
opts_set(opts.flags, LEGACY_VECTOR_MATHS, true);
|
opts_set(opts.flags, LEGACY_VECTOR_MATHS, true);
|
||||||
opts_set(opts.flags, DARKPLACES_STRING_TABLE_BUG, true);
|
opts_set(opts.flags, DARKPLACES_STRING_TABLE_BUG, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void opts_backup_non_Wall() {
|
void opts_backup_non_Wall() {
|
||||||
|
@ -96,6 +97,7 @@ void opts_init(const char *output, int standard, size_t arraysize) {
|
||||||
OPTS_OPTION_STR(OPTION_OUTPUT) = (char*)output;
|
OPTS_OPTION_STR(OPTION_OUTPUT) = (char*)output;
|
||||||
OPTS_OPTION_U32(OPTION_STANDARD) = standard;
|
OPTS_OPTION_U32(OPTION_STANDARD) = standard;
|
||||||
OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE) = arraysize;
|
OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE) = arraysize;
|
||||||
|
OPTS_OPTION_U16(OPTION_MEMDUMPCOLS) = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool opts_setflag_all(const char *name, bool on, uint32_t *flags, const opts_flag_def *list, size_t listsize) {
|
static bool opts_setflag_all(const char *name, bool on, uint32_t *flags, const opts_flag_def *list, size_t listsize) {
|
||||||
|
@ -257,7 +259,7 @@ static size_t opts_ini_parse (
|
||||||
static bool opts_ini_bool(const char *value) {
|
static bool opts_ini_bool(const char *value) {
|
||||||
if (!strcmp(value, "true")) return true;
|
if (!strcmp(value, "true")) return true;
|
||||||
if (!strcmp(value, "false")) return false;
|
if (!strcmp(value, "false")) return false;
|
||||||
return !!atoi(value);
|
return !!strtol(value, NULL, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *opts_ini_load(const char *section, const char *name, const char *value) {
|
static char *opts_ini_load(const char *section, const char *name, const char *value) {
|
||||||
|
|
1
opts.def
1
opts.def
|
@ -109,6 +109,7 @@
|
||||||
GMQCC_DEFINE_FLAG(G)
|
GMQCC_DEFINE_FLAG(G)
|
||||||
GMQCC_DEFINE_FLAG(STANDARD)
|
GMQCC_DEFINE_FLAG(STANDARD)
|
||||||
GMQCC_DEFINE_FLAG(DEBUG)
|
GMQCC_DEFINE_FLAG(DEBUG)
|
||||||
|
GMQCC_DEFINE_FLAG(MEMDUMPCOLS)
|
||||||
GMQCC_DEFINE_FLAG(MEMCHK)
|
GMQCC_DEFINE_FLAG(MEMCHK)
|
||||||
GMQCC_DEFINE_FLAG(DUMPFIN)
|
GMQCC_DEFINE_FLAG(DUMPFIN)
|
||||||
GMQCC_DEFINE_FLAG(DUMP)
|
GMQCC_DEFINE_FLAG(DUMP)
|
||||||
|
|
33
pak.c
33
pak.c
|
@ -259,9 +259,10 @@ bool pak_exists(pak_file_t *pak, const char *file, pak_directory_t **dir) {
|
||||||
/*
|
/*
|
||||||
* Extraction abilities. These work as you expect them to.
|
* Extraction abilities. These work as you expect them to.
|
||||||
*/
|
*/
|
||||||
bool pak_extract_one(pak_file_t *pak, const char *file) {
|
bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) {
|
||||||
pak_directory_t *dir = NULL;
|
pak_directory_t *dir = NULL;
|
||||||
unsigned char *dat = NULL;
|
unsigned char *dat = NULL;
|
||||||
|
char *local = NULL;
|
||||||
FILE *out;
|
FILE *out;
|
||||||
|
|
||||||
if (!pak_exists(pak, file, &dir)) {
|
if (!pak_exists(pak, file, &dir)) {
|
||||||
|
@ -278,15 +279,20 @@ bool pak_extract_one(pak_file_t *pak, const char *file) {
|
||||||
*/
|
*/
|
||||||
pak_tree_build(file);
|
pak_tree_build(file);
|
||||||
|
|
||||||
|
/* TODO portable path seperators */
|
||||||
|
util_asprintf(&local, "%s/%s", outdir, file);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now create the file, if this operation fails. Then abort
|
* Now create the file, if this operation fails. Then abort
|
||||||
* It shouldn't fail though.
|
* It shouldn't fail though.
|
||||||
*/
|
*/
|
||||||
if (!(out = fs_file_open(file, "wb"))) {
|
if (!(out = fs_file_open(local, "wb"))) {
|
||||||
mem_d(dat);
|
mem_d(dat);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* free memory for directory string */
|
||||||
|
mem_d(local);
|
||||||
|
|
||||||
/* read */
|
/* read */
|
||||||
fs_file_seek (pak->handle, dir->pos, SEEK_SET);
|
fs_file_seek (pak->handle, dir->pos, SEEK_SET);
|
||||||
|
@ -310,11 +316,8 @@ bool pak_extract_all(pak_file_t *pak, const char *dir) {
|
||||||
if (!fs_dir_make(dir))
|
if (!fs_dir_make(dir))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (fs_dir_change(dir))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (itr = 0; itr < vec_size(pak->directories); itr++) {
|
for (itr = 0; itr < vec_size(pak->directories); itr++) {
|
||||||
if (!pak_extract_one(pak, pak->directories[itr].name))
|
if (!pak_extract_one(pak, pak->directories[itr].name, dir))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,7 +364,7 @@ bool pak_insert_one(pak_file_t *pak, const char *file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(dir.name, file);
|
strncpy(dir.name, file, strlen(file));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate some memory for loading in the data that will be
|
* Allocate some memory for loading in the data that will be
|
||||||
|
@ -477,7 +480,6 @@ int main(int argc, char **argv) {
|
||||||
bool extract = true;
|
bool extract = true;
|
||||||
char *redirout = (char*)stdout;
|
char *redirout = (char*)stdout;
|
||||||
char *redirerr = (char*)stderr;
|
char *redirerr = (char*)stderr;
|
||||||
char *directory = NULL;
|
|
||||||
char *file = NULL;
|
char *file = NULL;
|
||||||
char **files = NULL;
|
char **files = NULL;
|
||||||
pak_file_t *pak = NULL;
|
pak_file_t *pak = NULL;
|
||||||
|
@ -498,8 +500,6 @@ int main(int argc, char **argv) {
|
||||||
continue;
|
continue;
|
||||||
if (parsecmd("redirerr", &argc, &argv, &redirerr, 1, false))
|
if (parsecmd("redirerr", &argc, &argv, &redirerr, 1, false))
|
||||||
continue;
|
continue;
|
||||||
if (parsecmd("directory", &argc, &argv, &directory, 1, false))
|
|
||||||
continue;
|
|
||||||
if (parsecmd("file", &argc, &argv, &file, 1, false))
|
if (parsecmd("file", &argc, &argv, &file, 1, false))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ int main(int argc, char **argv) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pak_extract_all(pak, (directory) ? directory : "./")) {
|
if (!pak_extract_all(pak, "./")) {
|
||||||
con_err("failed to extract PAK %s (files may be missing)\n", file);
|
con_err("failed to extract PAK %s (files may be missing)\n", file);
|
||||||
pak_close(pak);
|
pak_close(pak);
|
||||||
vec_free(files);
|
vec_free(files);
|
||||||
|
@ -562,13 +562,6 @@ int main(int argc, char **argv) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directory && !fs_dir_change(directory)) {
|
|
||||||
con_err("failed to change directory %s\n", directory);
|
|
||||||
pak_close(pak);
|
|
||||||
vec_free(files);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (iter = 0; iter < vec_size(files); iter++) {
|
for (iter = 0; iter < vec_size(files); iter++) {
|
||||||
if (!(pak_insert_one(pak, files[iter]))) {
|
if (!(pak_insert_one(pak, files[iter]))) {
|
||||||
con_err("failed inserting %s for PAK %s\n", files[iter], file);
|
con_err("failed inserting %s for PAK %s\n", files[iter], file);
|
||||||
|
|
155
parser.c
155
parser.c
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "gmqcc.h"
|
#include "gmqcc.h"
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
@ -34,7 +35,7 @@
|
||||||
#define PARSER_HT_SIZE 128
|
#define PARSER_HT_SIZE 128
|
||||||
#define TYPEDEF_HT_SIZE 16
|
#define TYPEDEF_HT_SIZE 16
|
||||||
|
|
||||||
typedef struct {
|
typedef struct parser_s {
|
||||||
lex_file *lex;
|
lex_file *lex;
|
||||||
int tok;
|
int tok;
|
||||||
|
|
||||||
|
@ -46,6 +47,8 @@ typedef struct {
|
||||||
ast_value **imm_vector;
|
ast_value **imm_vector;
|
||||||
size_t translated;
|
size_t translated;
|
||||||
|
|
||||||
|
ht ht_imm_string;
|
||||||
|
|
||||||
/* must be deleted first, they reference immediates and values */
|
/* must be deleted first, they reference immediates and values */
|
||||||
ast_value **accessors;
|
ast_value **accessors;
|
||||||
|
|
||||||
|
@ -252,12 +255,22 @@ static char *parser_strdup(const char *str)
|
||||||
|
|
||||||
static ast_value* parser_const_string(parser_t *parser, const char *str, bool dotranslate)
|
static ast_value* parser_const_string(parser_t *parser, const char *str, bool dotranslate)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t hash = util_hthash(parser->ht_imm_string, str);
|
||||||
ast_value *out;
|
ast_value *out;
|
||||||
|
if ( (out = util_htgeth(parser->ht_imm_string, str, hash)) ) {
|
||||||
|
if (dotranslate && out->name[0] == '#') {
|
||||||
|
char name[32];
|
||||||
|
snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
|
||||||
|
ast_value_set_name(out, name);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
/*
|
||||||
for (i = 0; i < vec_size(parser->imm_string); ++i) {
|
for (i = 0; i < vec_size(parser->imm_string); ++i) {
|
||||||
if (!strcmp(parser->imm_string[i]->constval.vstring, str))
|
if (!strcmp(parser->imm_string[i]->constval.vstring, str))
|
||||||
return parser->imm_string[i];
|
return parser->imm_string[i];
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if (dotranslate) {
|
if (dotranslate) {
|
||||||
char name[32];
|
char name[32];
|
||||||
snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
|
snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
|
||||||
|
@ -268,6 +281,7 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do
|
||||||
out->hasvalue = true;
|
out->hasvalue = true;
|
||||||
out->constval.vstring = parser_strdup(str);
|
out->constval.vstring = parser_strdup(str);
|
||||||
vec_push(parser->imm_string, out);
|
vec_push(parser->imm_string, out);
|
||||||
|
util_htseth(parser->ht_imm_string, str, hash, out);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,6 +393,9 @@ static ast_value* parser_find_typedef(parser_t *parser, const char *name, size_t
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* include intrinsics */
|
||||||
|
#include "intrin.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
size_t etype; /* 0 = expression, others are operators */
|
size_t etype; /* 0 = expression, others are operators */
|
||||||
|
@ -961,10 +978,35 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case opid1('%'):
|
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]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (CanConstFold(exprs[0], exprs[1])) {
|
||||||
|
out = (ast_expression*)parser_const_float(parser,
|
||||||
|
(float)(((qcint)ConstF(0)) % ((qcint)ConstF(1))));
|
||||||
|
} else {
|
||||||
|
/* generate a call to __builtin_mod */
|
||||||
|
ast_expression *mod = intrin_func(parser, "mod");
|
||||||
|
ast_call *call = NULL;
|
||||||
|
if (!mod) return false; /* can return null for missing floor */
|
||||||
|
|
||||||
|
call = ast_call_new(parser_ctx(parser), mod);
|
||||||
|
vec_push(call->params, exprs[0]);
|
||||||
|
vec_push(call->params, exprs[1]);
|
||||||
|
|
||||||
|
out = (ast_expression*)call;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case opid2('%','='):
|
case opid2('%','='):
|
||||||
compile_error(ctx, "qc does not have a modulo operator");
|
compile_error(ctx, "%= is unimplemented");
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case opid1('|'):
|
case opid1('|'):
|
||||||
case opid1('&'):
|
case opid1('&'):
|
||||||
if (NotSameType(TYPE_FLOAT)) {
|
if (NotSameType(TYPE_FLOAT)) {
|
||||||
|
@ -1071,6 +1113,26 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
|
||||||
out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]);
|
out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case opid2('*', '*'):
|
||||||
|
if (NotSameType(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 exponentiation: %s and %s",
|
||||||
|
ty1, ty2);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CanConstFold(exprs[0], exprs[1])) {
|
||||||
|
out = (ast_expression*)parser_const_float(parser, powf(ConstF(0), ConstF(1)));
|
||||||
|
} else {
|
||||||
|
ast_call *gencall = ast_call_new(parser_ctx(parser), intrin_func(parser, "pow"));
|
||||||
|
vec_push(gencall->params, exprs[0]);
|
||||||
|
vec_push(gencall->params, exprs[1]);
|
||||||
|
out = (ast_expression*)gencall;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case opid3('<','=','>'): /* -1, 0, or 1 */
|
case opid3('<','=','>'): /* -1, 0, or 1 */
|
||||||
if (NotSameType(TYPE_FLOAT)) {
|
if (NotSameType(TYPE_FLOAT)) {
|
||||||
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
|
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
|
||||||
|
@ -1416,7 +1478,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
|
||||||
if(CanConstFold1(exprs[0]))
|
if(CanConstFold1(exprs[0]))
|
||||||
out = (ast_expression*)parser_const_float(parser, ~(qcint)ConstF(0));
|
out = (ast_expression*)parser_const_float(parser, ~(qcint)ConstF(0));
|
||||||
else
|
else
|
||||||
out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser_const_float_neg1(parser), exprs[0]);
|
out = (ast_expression*)
|
||||||
|
ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser_const_float_neg1(parser), exprs[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#undef NotSameType
|
#undef NotSameType
|
||||||
|
@ -1830,6 +1893,15 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
|
||||||
if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) {
|
if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) {
|
||||||
var = (ast_expression*)intrinsic_debug_typestring;
|
var = (ast_expression*)intrinsic_debug_typestring;
|
||||||
}
|
}
|
||||||
|
/* now we try for the real intrinsic hashtable. If the string
|
||||||
|
* begins with __builtin, we simply skip past it, otherwise we
|
||||||
|
* use the identifier as is.
|
||||||
|
*/
|
||||||
|
else if (!strncmp(parser_tokval(parser), "__builtin_", 10)) {
|
||||||
|
var = intrin_func(parser, parser_tokval(parser) + 10 /* skip __builtin */);
|
||||||
|
} else {
|
||||||
|
var = intrin_func(parser, parser_tokval(parser));
|
||||||
|
}
|
||||||
|
|
||||||
if (!var) {
|
if (!var) {
|
||||||
char *correct = NULL;
|
char *correct = NULL;
|
||||||
|
@ -3654,6 +3726,8 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression *
|
||||||
|
|
||||||
static bool parse_enum(parser_t *parser)
|
static bool parse_enum(parser_t *parser)
|
||||||
{
|
{
|
||||||
|
bool flag = false;
|
||||||
|
bool reverse = false;
|
||||||
qcfloat num = 0;
|
qcfloat num = 0;
|
||||||
ast_value **values = NULL;
|
ast_value **values = NULL;
|
||||||
ast_value *var = NULL;
|
ast_value *var = NULL;
|
||||||
|
@ -3661,11 +3735,37 @@ static bool parse_enum(parser_t *parser)
|
||||||
|
|
||||||
ast_expression *old;
|
ast_expression *old;
|
||||||
|
|
||||||
if (!parser_next(parser) || parser->tok != '{') {
|
if (!parser_next(parser) || (parser->tok != '{' && parser->tok != ':')) {
|
||||||
parseerror(parser, "expected `{` after `enum` keyword");
|
parseerror(parser, "expected `{` or `:` after `enum` keyword");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* enumeration attributes (can add more later) */
|
||||||
|
if (parser->tok == ':') {
|
||||||
|
if (!parser_next(parser) || parser->tok != TOKEN_IDENT){
|
||||||
|
parseerror(parser, "expected `flag` or `reverse` for enumeration attribute");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* attributes? */
|
||||||
|
if (!strcmp(parser_tokval(parser), "flag")) {
|
||||||
|
num = 1;
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
else if (!strcmp(parser_tokval(parser), "reverse")) {
|
||||||
|
reverse = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parseerror(parser, "invalid attribute `%s` for enumeration", parser_tokval(parser));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parser_next(parser) || parser->tok != '{') {
|
||||||
|
parseerror(parser, "expected `{` after enum attribute ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
|
if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
|
||||||
if (parser->tok == '}') {
|
if (parser->tok == '}') {
|
||||||
|
@ -3689,8 +3789,9 @@ static bool parse_enum(parser_t *parser)
|
||||||
vec_push(values, var);
|
vec_push(values, var);
|
||||||
var->cvq = CV_CONST;
|
var->cvq = CV_CONST;
|
||||||
var->hasvalue = true;
|
var->hasvalue = true;
|
||||||
var->constval.vfloat = num++;
|
|
||||||
|
|
||||||
|
/* for flagged enumerations increment in POTs of TWO */
|
||||||
|
var->constval.vfloat = (flag) ? (num *= 2) : (num ++);
|
||||||
parser_addglobal(parser, var->name, (ast_expression*)var);
|
parser_addglobal(parser, var->name, (ast_expression*)var);
|
||||||
|
|
||||||
if (!parser_next(parser)) {
|
if (!parser_next(parser)) {
|
||||||
|
@ -3729,6 +3830,13 @@ static bool parse_enum(parser_t *parser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* patch them all (for reversed attribute) */
|
||||||
|
if (reverse) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < vec_size(values); i++)
|
||||||
|
values[i]->constval.vfloat = vec_size(values) - i - 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (parser->tok != '}') {
|
if (parser->tok != '}') {
|
||||||
parseerror(parser, "internal error: breaking without `}`");
|
parseerror(parser, "internal error: breaking without `}`");
|
||||||
goto onerror;
|
goto onerror;
|
||||||
|
@ -4696,6 +4804,8 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
|
||||||
on_error:
|
on_error:
|
||||||
if (argcounter)
|
if (argcounter)
|
||||||
mem_d(argcounter);
|
mem_d(argcounter);
|
||||||
|
if (varparam)
|
||||||
|
ast_delete(varparam);
|
||||||
ast_delete(var);
|
ast_delete(var);
|
||||||
for (i = 0; i < vec_size(params); ++i)
|
for (i = 0; i < vec_size(params); ++i)
|
||||||
ast_delete(params[i]);
|
ast_delete(params[i]);
|
||||||
|
@ -5814,16 +5924,15 @@ static void generate_checksum(parser_t *parser)
|
||||||
code_crc = crc;
|
code_crc = crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static parser_t *parser;
|
parser_t *parser_create()
|
||||||
|
|
||||||
bool parser_init()
|
|
||||||
{
|
{
|
||||||
|
parser_t *parser;
|
||||||
lex_ctx empty_ctx;
|
lex_ctx empty_ctx;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
parser = (parser_t*)mem_a(sizeof(parser_t));
|
parser = (parser_t*)mem_a(sizeof(parser_t));
|
||||||
if (!parser)
|
if (!parser)
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
memset(parser, 0, sizeof(*parser));
|
memset(parser, 0, sizeof(*parser));
|
||||||
|
|
||||||
|
@ -5836,7 +5945,7 @@ bool parser_init()
|
||||||
if (!parser->assign_op) {
|
if (!parser->assign_op) {
|
||||||
printf("internal error: initializing parser: failed to find assign operator\n");
|
printf("internal error: initializing parser: failed to find assign operator\n");
|
||||||
mem_d(parser);
|
mem_d(parser);
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_push(parser->variables, parser->htfields = util_htnew(PARSER_HT_SIZE));
|
vec_push(parser->variables, parser->htfields = util_htnew(PARSER_HT_SIZE));
|
||||||
|
@ -5846,6 +5955,8 @@ bool parser_init()
|
||||||
|
|
||||||
parser->aliases = util_htnew(PARSER_HT_SIZE);
|
parser->aliases = util_htnew(PARSER_HT_SIZE);
|
||||||
|
|
||||||
|
parser->ht_imm_string = util_htnew(512);
|
||||||
|
|
||||||
/* corrector */
|
/* corrector */
|
||||||
vec_push(parser->correct_variables, correct_trie_new());
|
vec_push(parser->correct_variables, correct_trie_new());
|
||||||
vec_push(parser->correct_variables_score, NULL);
|
vec_push(parser->correct_variables_score, NULL);
|
||||||
|
@ -5872,10 +5983,11 @@ bool parser_init()
|
||||||
} else {
|
} else {
|
||||||
parser->reserved_version = NULL;
|
parser->reserved_version = NULL;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
return parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parser_compile()
|
bool parser_compile(parser_t *parser)
|
||||||
{
|
{
|
||||||
/* initial lexer/parser state */
|
/* initial lexer/parser state */
|
||||||
parser->lex->flags.noops = true;
|
parser->lex->flags.noops = true;
|
||||||
|
@ -5907,27 +6019,27 @@ bool parser_compile()
|
||||||
return !compile_errors;
|
return !compile_errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parser_compile_file(const char *filename)
|
bool parser_compile_file(parser_t *parser, const char *filename)
|
||||||
{
|
{
|
||||||
parser->lex = lex_open(filename);
|
parser->lex = lex_open(filename);
|
||||||
if (!parser->lex) {
|
if (!parser->lex) {
|
||||||
con_err("failed to open file \"%s\"\n", filename);
|
con_err("failed to open file \"%s\"\n", filename);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return parser_compile();
|
return parser_compile(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parser_compile_string(const char *name, const char *str, size_t len)
|
bool parser_compile_string(parser_t *parser, const char *name, const char *str, size_t len)
|
||||||
{
|
{
|
||||||
parser->lex = lex_open_string(str, len, name);
|
parser->lex = lex_open_string(str, len, name);
|
||||||
if (!parser->lex) {
|
if (!parser->lex) {
|
||||||
con_err("failed to create lexer for string \"%s\"\n", name);
|
con_err("failed to create lexer for string \"%s\"\n", name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return parser_compile();
|
return parser_compile(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parser_cleanup()
|
void parser_cleanup(parser_t *parser)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < vec_size(parser->accessors); ++i) {
|
for (i = 0; i < vec_size(parser->accessors); ++i) {
|
||||||
|
@ -5957,6 +6069,7 @@ void parser_cleanup()
|
||||||
vec_free(parser->functions);
|
vec_free(parser->functions);
|
||||||
vec_free(parser->imm_vector);
|
vec_free(parser->imm_vector);
|
||||||
vec_free(parser->imm_string);
|
vec_free(parser->imm_string);
|
||||||
|
util_htdel(parser->ht_imm_string);
|
||||||
vec_free(parser->imm_float);
|
vec_free(parser->imm_float);
|
||||||
vec_free(parser->globals);
|
vec_free(parser->globals);
|
||||||
vec_free(parser->fields);
|
vec_free(parser->fields);
|
||||||
|
@ -5998,10 +6111,12 @@ void parser_cleanup()
|
||||||
|
|
||||||
util_htdel(parser->aliases);
|
util_htdel(parser->aliases);
|
||||||
|
|
||||||
|
intrin_intrinsics_destroy(parser);
|
||||||
|
|
||||||
mem_d(parser);
|
mem_d(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parser_finish(const char *output)
|
bool parser_finish(parser_t *parser, const char *output)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
ir_builder *ir;
|
ir_builder *ir;
|
||||||
|
|
24
syntax/README
Normal file
24
syntax/README
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
Here exists some syntax highlighting configuration files for various
|
||||||
|
text editors. Inside each directory exists some documentaiton on how
|
||||||
|
you can install the configuration file correctly.
|
||||||
|
|
||||||
|
Currently the supported text editors:
|
||||||
|
geany
|
||||||
|
kate
|
||||||
|
kwrite - uses kate syntax highlighting
|
||||||
|
kdevelop - uses kate syntax highlighting
|
||||||
|
QtCreator - supports kate syntax highlighting
|
||||||
|
gtksourceview - main source viewer in GNOME
|
||||||
|
gedit - uses gtksourceview
|
||||||
|
sandy - uses gtksourceview
|
||||||
|
nano
|
||||||
|
jedit
|
||||||
|
|
||||||
|
|
||||||
|
Other text editors we plan to provide syntax highlighting configuration
|
||||||
|
files for (but never got around to figuring out)
|
||||||
|
vim
|
||||||
|
emacs
|
||||||
|
|
||||||
|
If your text editor is not supported and you'd like to create syntax
|
||||||
|
highlighting support for it, don't hesitate to share it with us.
|
8
syntax/geany/README
Normal file
8
syntax/geany/README
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
To use the geany syntax highlighting install filetypes.qc to the syntax
|
||||||
|
directory for geany.
|
||||||
|
|
||||||
|
# Can be installed globally to
|
||||||
|
/usr/share/geany/
|
||||||
|
|
||||||
|
# Can be installed locally to
|
||||||
|
~/.config/geany/filedefs/
|
55
syntax/geany/filetypes.qc
Normal file
55
syntax/geany/filetypes.qc
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
[styling]
|
||||||
|
default=default
|
||||||
|
comment=comment
|
||||||
|
commentline=comment_line
|
||||||
|
commentdoc=comment_doc
|
||||||
|
preprocessorcomment=comment
|
||||||
|
number=number_1
|
||||||
|
word=keyword_1
|
||||||
|
word2=keyword_2
|
||||||
|
string=string_1
|
||||||
|
stringraw=string_2
|
||||||
|
character=character
|
||||||
|
uuid=other
|
||||||
|
preprocessor=preprocessor
|
||||||
|
operator=operator
|
||||||
|
identifier=identifier_1
|
||||||
|
stringeol=string_eol
|
||||||
|
verbatim=string_2
|
||||||
|
regex=regex
|
||||||
|
commentlinedoc=comment_line_doc
|
||||||
|
commentdockeyword=comment_doc_keyword
|
||||||
|
commentdockeyworderror=comment_doc_keyword_error
|
||||||
|
globalclass=class
|
||||||
|
tripleverbatim=string_2
|
||||||
|
hashquotedstring=string_2
|
||||||
|
|
||||||
|
[keywords]
|
||||||
|
primary=break case const continue string default do else enum float for goto if return switch typedef void while false nil true
|
||||||
|
secondary=
|
||||||
|
docComment=
|
||||||
|
|
||||||
|
[lexer_properties]
|
||||||
|
styling.within.preprocessor=1
|
||||||
|
lexer.cpp.track.preprocessor=0
|
||||||
|
preprocessor.symbol.$(file.patterns.cpp)=#
|
||||||
|
preprocessor.start.$(file.patterns.cpp)=if ifdef ifndef
|
||||||
|
preprocessor.middle.$(file.patterns.cpp)=else elif
|
||||||
|
preprocessor.end.$(file.patterns.cpp)=endif
|
||||||
|
|
||||||
|
[settings]
|
||||||
|
extension=qc
|
||||||
|
comment_single=//
|
||||||
|
comment_open=/*
|
||||||
|
comment_close=*/
|
||||||
|
comment_use_indent=true
|
||||||
|
context_action_cmd=
|
||||||
|
|
||||||
|
[indentation]
|
||||||
|
width=4
|
||||||
|
type=0
|
||||||
|
|
||||||
|
[build_settings]
|
||||||
|
compiler=gmqcc -Wall "%f" -o "%e"
|
||||||
|
linker=
|
||||||
|
run_cmd=qcvm "./%e"
|
5
syntax/gtksourceview/README
Normal file
5
syntax/gtksourceview/README
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
To use the gtksourceview syntax highlighting install qc.lang to the syntax
|
||||||
|
directory for gtksourceview
|
||||||
|
|
||||||
|
# Can be installed globally to
|
||||||
|
/usr/share/gtksourceview-[version]/language-specs/
|
173
syntax/gtksourceview/qc.lang
Normal file
173
syntax/gtksourceview/qc.lang
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<language id="qc" _name="QuakeC" version="1.0" _section="Sources">
|
||||||
|
<metadata>
|
||||||
|
<property name="globs">*.qc</property>
|
||||||
|
<property name="line-comment-start">//</property>
|
||||||
|
<property name="block-comment-start">/*</property>
|
||||||
|
<property name="block-comment-end">*/</property>
|
||||||
|
</metadata>
|
||||||
|
|
||||||
|
<styles>
|
||||||
|
<style id="comment" _name="Comment" map-to="def:comment"/>
|
||||||
|
<style id="string" _name="String" map-to="def:string"/>
|
||||||
|
<style id="preprocessor" _name="Preprocessor" map-to="def:preprocessor"/>
|
||||||
|
<style id="common-defines" _name="Common Defines" map-to="def:special-constant"/>
|
||||||
|
<style id="included-file" _name="Included File" map-to="def:string"/>
|
||||||
|
<style id="keyword" _name="Keyword" map-to="def:keyword"/>
|
||||||
|
<style id="type" _name="Data Type" map-to="def:type"/>
|
||||||
|
<style id="escaped-character" _name="Escaped Character" map-to="def:special-char"/>
|
||||||
|
<style id="floating-point" _name="Floating point number" map-to="def:floating-point"/>
|
||||||
|
<style id="decimal" _name="Decimal number" map-to="def:decimal"/>
|
||||||
|
<style id="hexadecimal" _name="Hexadecimal number" map-to="def:base-n-integer"/>
|
||||||
|
<style id="boolean" _name="Boolean value" map-to="def:boolean"/>
|
||||||
|
</styles>
|
||||||
|
|
||||||
|
<definitions>
|
||||||
|
|
||||||
|
<!--regexs-->
|
||||||
|
<define-regex id="preproc-start">^\s*#\s*</define-regex>
|
||||||
|
<define-regex id="escaped-character" extended="true">
|
||||||
|
\\( # leading backslash
|
||||||
|
[\\\"\'nrbtfav\?] | # escaped character
|
||||||
|
[0-7]{1,3} | # one, two, or three octal digits
|
||||||
|
x[0-9A-Fa-f]+ # 'x' followed by hex digits
|
||||||
|
)
|
||||||
|
</define-regex>
|
||||||
|
|
||||||
|
<!-- Preprocessor -->
|
||||||
|
<context id="if0-comment" style-ref="comment">
|
||||||
|
<start>\%{preproc-start}if\b\s*0\b</start>
|
||||||
|
<end>\%{preproc-start}(endif|else|elif)\b</end>
|
||||||
|
<include>
|
||||||
|
<context id="if-in-if0">
|
||||||
|
<start>\%{preproc-start}if(n?def)?\b</start>
|
||||||
|
<end>\%{preproc-start}endif\b</end>
|
||||||
|
<include>
|
||||||
|
<context ref="if-in-if0"/>
|
||||||
|
<context ref="def:in-comment"/>
|
||||||
|
</include>
|
||||||
|
</context>
|
||||||
|
<context ref="def:in-comment"/>
|
||||||
|
</include>
|
||||||
|
</context>
|
||||||
|
<context id="include" style-ref="preprocessor">
|
||||||
|
<match extended="true">
|
||||||
|
\%{preproc-start}
|
||||||
|
(include|import)\s*
|
||||||
|
(".*?"|<.*>)
|
||||||
|
</match>
|
||||||
|
<include>
|
||||||
|
<context id="included-file" sub-pattern="2" style-ref="included-file"/>
|
||||||
|
</include>
|
||||||
|
</context>
|
||||||
|
<context id="preprocessor" style-ref="preprocessor" end-at-line-end="true">
|
||||||
|
<start extended="true">
|
||||||
|
\%{preproc-start}
|
||||||
|
(define|undef|error|pragma|ident|if(n?def)?|else|elif|endif|line|warning)
|
||||||
|
\b
|
||||||
|
</start>
|
||||||
|
<include>
|
||||||
|
<context ref="def:line-continue" ignore-style="true"/>
|
||||||
|
<context ref="string" ignore-style="true"/>
|
||||||
|
<context ref="def:qc-like-comment"/>
|
||||||
|
<context ref="def:qc-like-comment-multiline"/>
|
||||||
|
</include>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context id="float" style-ref="floating-point">
|
||||||
|
<match extended="true">
|
||||||
|
(?<![\w\.])
|
||||||
|
((\.[0-9]+ | [0-9]+\.[0-9]*) ([Ee][+-]?[0-9]*)? |
|
||||||
|
([0-9]+[Ee][+-]?[0-9]*))
|
||||||
|
[fFlL]?
|
||||||
|
(?![\w\.])
|
||||||
|
</match>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context id="hexadecimal" style-ref="hexadecimal">
|
||||||
|
<match extended="true">
|
||||||
|
(?<![\w\.])
|
||||||
|
0[xX][a-fA-F0-9]+[uUlL]*
|
||||||
|
(?![\w\.])
|
||||||
|
</match>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context id="invalid-hexadecimal" style-ref="error">
|
||||||
|
<match extended="true">
|
||||||
|
(?<![\w\.])
|
||||||
|
0[xX][a-fA-F0-9]*[g-zG-Z][a-zA-Z0-9]*[uUlL]*
|
||||||
|
(?![\w\.])
|
||||||
|
</match>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context id="decimal" style-ref="decimal">
|
||||||
|
<match extended="true">
|
||||||
|
(?<![\w\.])
|
||||||
|
(0|[1-9][0-9]*)[uUlL]*
|
||||||
|
(?![\w\.])
|
||||||
|
</match>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context id="keywords" style-ref="keyword">
|
||||||
|
<keyword>break</keyword>
|
||||||
|
<keyword>case</keyword>
|
||||||
|
<keyword>continue</keyword>
|
||||||
|
<keyword>default</keyword>
|
||||||
|
<keyword>do</keyword>
|
||||||
|
<keyword>else</keyword>
|
||||||
|
<keyword>enum</keyword>
|
||||||
|
<keyword>for</keyword>
|
||||||
|
<keyword>goto</keyword>
|
||||||
|
<keyword>if</keyword>
|
||||||
|
<keyword>return</keyword>
|
||||||
|
<keyword>switch</keyword>
|
||||||
|
<keyword>typedef</keyword>
|
||||||
|
<keyword>while</keyword>
|
||||||
|
<keyword>nil</keyword>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context id="types" style-ref="type">
|
||||||
|
<keyword>bool</keyword>
|
||||||
|
<keyword>string</keyword>
|
||||||
|
<keyword>vector</keyword>
|
||||||
|
<keyword>float</keyword>
|
||||||
|
<keyword>void</keyword>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context id="boolean" style-ref="boolean">
|
||||||
|
<keyword>true</keyword>
|
||||||
|
<keyword>false</keyword>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context id="common-defines" style-ref="common-defines">
|
||||||
|
<keyword>__LINE__</keyword>
|
||||||
|
<keyword>__FILE__</keyword>
|
||||||
|
<keyword>__TIME__</keyword>
|
||||||
|
<keyword>__RANDOM__</keyword>
|
||||||
|
<keyword>__RANDOM_LAST__</keyword>
|
||||||
|
<keyword>__COUNTER__</keyword>
|
||||||
|
<keyword>__COUNTER_LAST__</keyword>
|
||||||
|
<keyword>__DATE__</keyword>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context id="qc" class="no-spell-check">
|
||||||
|
<include>
|
||||||
|
<context ref="def:qc-like-comment"/>
|
||||||
|
<context ref="def:qc-like-comment-multiline"/>
|
||||||
|
<context ref="def:qc-like-close-comment-outside-comment"/>
|
||||||
|
<context ref="if0-comment"/>
|
||||||
|
<context ref="include"/>
|
||||||
|
<context ref="preprocessor"/>
|
||||||
|
<context ref="string"/>
|
||||||
|
<context ref="float"/>
|
||||||
|
<context ref="hexadecimal"/>
|
||||||
|
<context ref="invalid-hexadecimal"/>
|
||||||
|
<context ref="decimal"/>
|
||||||
|
<context ref="keywords"/>
|
||||||
|
<context ref="types"/>
|
||||||
|
<context ref="boolean"/>
|
||||||
|
<context ref="common-defines"/>
|
||||||
|
</include>
|
||||||
|
</context>
|
||||||
|
</definitions>
|
||||||
|
</language>
|
26
syntax/jedit/README
Normal file
26
syntax/jedit/README
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
To use the jedit syntax highlighting install qc.xml to the syntax
|
||||||
|
directory for jedit
|
||||||
|
|
||||||
|
# For Windows Users that directory is
|
||||||
|
C:\Users\username\.jedit\modes
|
||||||
|
|
||||||
|
# For Linux users that directory is
|
||||||
|
/home/username/.jedit/modes
|
||||||
|
|
||||||
|
# For Mac users that directory is
|
||||||
|
/Users/username/Library/jEdit/modes
|
||||||
|
|
||||||
|
After the file is installed, a mode line needs to be added to
|
||||||
|
a file caled catalog in that same directory.
|
||||||
|
|
||||||
|
Add the following line:
|
||||||
|
<MODE NAME="QuakeC Code" FILE="qc.xml" FILE_NAME_GLOB="*.qc" />
|
||||||
|
|
||||||
|
inside the <MODES> block before the end tag </MODES>. If the file
|
||||||
|
does not exist, you can simply make one and use the following:
|
||||||
|
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE MODES SYSTEM "catalog.dtd">
|
||||||
|
<MODES>
|
||||||
|
<MODE NAME="QuakeC Code" FILE="qc.xml" FILE_NAME_GLOB="*.qc" />
|
||||||
|
</MODES>
|
271
syntax/jedit/qc.xml
Normal file
271
syntax/jedit/qc.xml
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<!DOCTYPE MODE SYSTEM "xmode.dtd">
|
||||||
|
|
||||||
|
<MODE>
|
||||||
|
<PROPS>
|
||||||
|
<PROPERTY NAME="commentStart" VALUE="/*" />
|
||||||
|
<PROPERTY NAME="commentEnd" VALUE="*/" />
|
||||||
|
<PROPERTY NAME="lineComment" VALUE="//" />
|
||||||
|
<PROPERTY NAME="wordBreakChars" VALUE=",+-=<>/?^&*" />
|
||||||
|
|
||||||
|
<!-- Auto indent -->
|
||||||
|
<PROPERTY NAME="indentOpenBrackets" VALUE="{" />
|
||||||
|
<PROPERTY NAME="indentCloseBrackets" VALUE="}" />
|
||||||
|
<PROPERTY NAME="unalignedOpenBrackets" VALUE="(" />
|
||||||
|
<PROPERTY NAME="unalignedCloseBrackets" VALUE=")" />
|
||||||
|
<PROPERTY NAME="indentNextLine"
|
||||||
|
VALUE="(?!^\s*(#|//)).*(\b(if|while|for)\s*\(.*\)|\b(else|do)\b)[^{;]*$" />
|
||||||
|
<PROPERTY NAME="unindentThisLine"
|
||||||
|
VALUE="^\s*((case\b.*|[\p{Alpha}_][\p{Alnum}_]*)\s*:(?!:)).*$" />
|
||||||
|
<PROPERTY NAME="electricKeys" VALUE=":" />
|
||||||
|
</PROPS>
|
||||||
|
|
||||||
|
<RULES
|
||||||
|
IGNORE_CASE="FALSE"
|
||||||
|
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
|
||||||
|
<EOL_SPAN TYPE="KEYWORD2" AT_WHITESPACE_END="TRUE" DELEGATE="CPP">#</EOL_SPAN>
|
||||||
|
|
||||||
|
<IMPORT DELEGATE="LEX"/>
|
||||||
|
<IMPORT DELEGATE="CORE"/>
|
||||||
|
</RULES>
|
||||||
|
|
||||||
|
<RULES SET="LEX" IGNORE_CASE="FALSE">
|
||||||
|
<IMPORT DELEGATE="COMMENTS" />
|
||||||
|
<IMPORT DELEGATE="C_LEXER" />
|
||||||
|
</RULES>
|
||||||
|
|
||||||
|
<!-- Comments, Trigraph, Alternate-Tokens -->
|
||||||
|
<RULES SET="C_LEXER"
|
||||||
|
IGNORE_CASE="FALSE"
|
||||||
|
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
|
||||||
|
|
||||||
|
<SPAN TYPE="LITERAL1" NO_LINE_BREAK="TRUE" ESCAPE="\">
|
||||||
|
<BEGIN>L"</BEGIN>
|
||||||
|
<END>"</END>
|
||||||
|
</SPAN>
|
||||||
|
<SPAN TYPE="LITERAL1" NO_LINE_BREAK="TRUE" ESCAPE="\">
|
||||||
|
<BEGIN>"</BEGIN>
|
||||||
|
<END>"</END>
|
||||||
|
</SPAN>
|
||||||
|
<SPAN TYPE="LITERAL1" NO_LINE_BREAK="TRUE" ESCAPE="\">
|
||||||
|
<BEGIN>L'</BEGIN>
|
||||||
|
<END>'</END>
|
||||||
|
</SPAN>
|
||||||
|
<SPAN TYPE="LITERAL1" NO_LINE_BREAK="TRUE" ESCAPE="\">
|
||||||
|
<BEGIN>'</BEGIN>
|
||||||
|
<END>'</END>
|
||||||
|
</SPAN>
|
||||||
|
|
||||||
|
<!-- Trigraphs -->
|
||||||
|
<SEQ TYPE="LITERAL4">??(</SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">??/</SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">??)</SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">??'</SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">??<</SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">??!</SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">??></SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">??-</SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">??=</SEQ>
|
||||||
|
|
||||||
|
<!-- Alternate tokens -->
|
||||||
|
<SEQ TYPE="LITERAL4"><:</SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">:></SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4"><%</SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">%></SEQ>
|
||||||
|
<SEQ TYPE="LITERAL4">%:</SEQ>
|
||||||
|
|
||||||
|
<!-- Labels.
|
||||||
|
This is a part of core language syntax, but must be here
|
||||||
|
because it can't work after SEQ for ':'. -->
|
||||||
|
<MARK_PREVIOUS AT_WHITESPACE_END="TRUE"
|
||||||
|
MATCH_TYPE="OPERATOR"
|
||||||
|
TYPE="LABEL">:</MARK_PREVIOUS>
|
||||||
|
|
||||||
|
<!-- Function-like macro or function calls.
|
||||||
|
This can't work after SEQ for '('. -->
|
||||||
|
<MARK_PREVIOUS
|
||||||
|
TYPE="FUNCTION"
|
||||||
|
MATCH_TYPE="OPERATOR">(</MARK_PREVIOUS>
|
||||||
|
|
||||||
|
<SEQ TYPE="OPERATOR">=</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">!</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">+</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">-</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">/</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">*</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">></SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR"><</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">%</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">&</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">|</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">^</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">~</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">?</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">:</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">.</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">,</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">[</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">]</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">)</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">}</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">{</SEQ>
|
||||||
|
<SEQ TYPE="OPERATOR">;</SEQ>
|
||||||
|
|
||||||
|
<KEYWORDS>
|
||||||
|
<LITERAL2>__FILE__</LITERAL2>
|
||||||
|
<LITERAL2>__LINE__</LITERAL2>
|
||||||
|
<LITERAL2>__DATE__</LITERAL2>
|
||||||
|
<LITERAL2>__RANDOM__</LITERAL2>
|
||||||
|
<LITERAL2>__RANDOM_LAST</LITERAL2>
|
||||||
|
<LITERAL2>__COUNT__</LITERAL2>
|
||||||
|
<LITERAL2>__COUNT_LAST</LITERAL2>
|
||||||
|
</KEYWORDS>
|
||||||
|
</RULES>
|
||||||
|
|
||||||
|
<!-- Core language -->
|
||||||
|
<RULES SET="CORE"
|
||||||
|
IGNORE_CASE="FALSE"
|
||||||
|
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
|
||||||
|
<KEYWORDS>
|
||||||
|
<!-- Types -->
|
||||||
|
<KEYWORD3>float</KEYWORD3>
|
||||||
|
<KEYWORD3>vector</KEYWORD3>
|
||||||
|
<KEYWORD3>string</KEYWORD3>
|
||||||
|
<KEYWORD3>entity</KEYWORD3>
|
||||||
|
<KEYWORD3>enum</KEYWORD3>
|
||||||
|
<KEYWORD3>.float</KEYWORD3>
|
||||||
|
<KEYWORD3>.int</KEYWORD3>
|
||||||
|
<KEYWORD3>.vector</KEYWORD3>
|
||||||
|
<KEYWORD3>.string</KEYWORD3>
|
||||||
|
<KEYWORD3>.entity</KEYWORD3>
|
||||||
|
<KEYWORD3>.void</KEYWORD3>
|
||||||
|
<KEYWORD3>typedef</KEYWORD3>
|
||||||
|
|
||||||
|
<KEYWORD1>break</KEYWORD1>
|
||||||
|
<KEYWORD1>case</KEYWORD1>
|
||||||
|
<KEYWORD1>continue</KEYWORD1>
|
||||||
|
<KEYWORD1>default</KEYWORD1>
|
||||||
|
<KEYWORD1>do</KEYWORD1>
|
||||||
|
<KEYWORD1>else</KEYWORD1>
|
||||||
|
<KEYWORD1>for</KEYWORD1>
|
||||||
|
<KEYWORD1>goto</KEYWORD1>
|
||||||
|
<KEYWORD1>if</KEYWORD1>
|
||||||
|
<KEYWORD1>return</KEYWORD1>
|
||||||
|
<KEYWORD1>switch</KEYWORD1>
|
||||||
|
<KEYWORD1>void</KEYWORD1>
|
||||||
|
<KEYWORD1>while</KEYWORD1>
|
||||||
|
<KEYWORD1>nil</KEYWORD1>
|
||||||
|
|
||||||
|
<LITERAL2>FALSE</LITERAL2>
|
||||||
|
<LITERAL2>TRUE</LITERAL2>
|
||||||
|
<LITERAL2>...</LITERAL2>
|
||||||
|
</KEYWORDS>
|
||||||
|
</RULES>
|
||||||
|
|
||||||
|
<!-- Different comment styles. -->
|
||||||
|
<RULES SET="COMMENTS">
|
||||||
|
<!-- Doxygen comment, Javadoc style -->
|
||||||
|
<SEQ TYPE="COMMENT1">/**/</SEQ>
|
||||||
|
<SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">
|
||||||
|
<BEGIN>/**<</BEGIN>
|
||||||
|
<END>*/</END>
|
||||||
|
</SPAN>
|
||||||
|
<SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">
|
||||||
|
<BEGIN>/**</BEGIN>
|
||||||
|
<END>*/</END>
|
||||||
|
</SPAN>
|
||||||
|
<EOL_SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">///<</EOL_SPAN>
|
||||||
|
<EOL_SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">///</EOL_SPAN>
|
||||||
|
|
||||||
|
<!-- Doxygen comment, Qt style -->
|
||||||
|
<SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">
|
||||||
|
<BEGIN>/*!<</BEGIN>
|
||||||
|
<END>*/</END>
|
||||||
|
</SPAN>
|
||||||
|
<SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">
|
||||||
|
<BEGIN>/*!</BEGIN>
|
||||||
|
<END>*/</END>
|
||||||
|
</SPAN>
|
||||||
|
<EOL_SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">//!<</EOL_SPAN>
|
||||||
|
<EOL_SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">//!</EOL_SPAN>
|
||||||
|
|
||||||
|
<!-- C style comment -->
|
||||||
|
<SPAN TYPE="COMMENT1">
|
||||||
|
<BEGIN>/*</BEGIN>
|
||||||
|
<END>*/</END>
|
||||||
|
</SPAN>
|
||||||
|
<EOL_SPAN TYPE="COMMENT1">//</EOL_SPAN>
|
||||||
|
</RULES>
|
||||||
|
|
||||||
|
<!-- Preprocessor specific rules -->
|
||||||
|
<RULES SET="CPP"
|
||||||
|
IGNORE_CASE="FALSE"
|
||||||
|
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
|
||||||
|
|
||||||
|
<EOL_SPAN_REGEXP HASH_CHAR="include" TYPE="MARKUP" DELEGATE="INCLUDE">include\b</EOL_SPAN_REGEXP>
|
||||||
|
<EOL_SPAN_REGEXP HASH_CHAR="define" TYPE="MARKUP" DELEGATE="DEFINE">define\b</EOL_SPAN_REGEXP>
|
||||||
|
<EOL_SPAN_REGEXP HASH_CHAR="endif" TYPE="MARKUP" DELEGATE="LEX">endif\b</EOL_SPAN_REGEXP>
|
||||||
|
<EOL_SPAN_REGEXP HASH_CHAR="elif" TYPE="MARKUP" DELEGATE="CONDITION">elif\b</EOL_SPAN_REGEXP>
|
||||||
|
<EOL_SPAN_REGEXP HASH_CHAR="if" TYPE="MARKUP" DELEGATE="CONDITION">if\b</EOL_SPAN_REGEXP>
|
||||||
|
|
||||||
|
<IMPORT DELEGATE="LEX"/>
|
||||||
|
|
||||||
|
<!-- Directives -->
|
||||||
|
<KEYWORDS>
|
||||||
|
<MARKUP>undef</MARKUP>
|
||||||
|
<MARKUP>ifdef</MARKUP>
|
||||||
|
<MARKUP>ifndef</MARKUP>
|
||||||
|
<MARKUP>else</MARKUP>
|
||||||
|
<MARKUP>error</MARKUP>
|
||||||
|
<MARKUP>warning</MARKUP>
|
||||||
|
<MARKUP>pragma</MARKUP>
|
||||||
|
<MARKUP>$frame</MARKUP>
|
||||||
|
<MARKUP>$model</MARKUP>
|
||||||
|
</KEYWORDS>
|
||||||
|
</RULES>
|
||||||
|
|
||||||
|
<!-- After #include directive -->
|
||||||
|
<!-- "\"s are not escaped. -->
|
||||||
|
<RULES SET="INCLUDE"
|
||||||
|
IGNORE_CASE="FALSE"
|
||||||
|
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
|
||||||
|
<SPAN TYPE="LITERAL1" NO_LINE_BREAK="TRUE">
|
||||||
|
<BEGIN><</BEGIN>
|
||||||
|
<END>></END>
|
||||||
|
</SPAN>
|
||||||
|
<SPAN TYPE="LITERAL1" NO_LINE_BREAK="TRUE">
|
||||||
|
<BEGIN>"</BEGIN>
|
||||||
|
<END>"</END>
|
||||||
|
</SPAN>
|
||||||
|
<IMPORT DELEGATE="LEX"/>
|
||||||
|
</RULES>
|
||||||
|
|
||||||
|
<!-- After #define directive -->
|
||||||
|
<!-- Almost same as the normal code,
|
||||||
|
except two additional operators # and ##. -->
|
||||||
|
<RULES SET="DEFINE"
|
||||||
|
IGNORE_CASE="FALSE"
|
||||||
|
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
|
||||||
|
<SEQ TYPE="OPERATOR">#</SEQ>
|
||||||
|
<IMPORT DELEGATE="LEX"/>
|
||||||
|
<IMPORT DELEGATE="CORE"/>
|
||||||
|
</RULES>
|
||||||
|
|
||||||
|
<!-- After #if or #elif directive -->
|
||||||
|
<!-- All constant expressions and a special operator
|
||||||
|
'defined' is available. But the core language elements
|
||||||
|
(such as operator 'sizeof', type casting, etc...) are not. -->
|
||||||
|
<RULES SET="CONDITION"
|
||||||
|
IGNORE_CASE="FALSE"
|
||||||
|
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
|
||||||
|
<IMPORT DELEGATE="LEX"/>
|
||||||
|
<KEYWORDS>
|
||||||
|
<KEYWORD2>defined</KEYWORD2>
|
||||||
|
<KEYWORD2>TRUE</KEYWORD2>
|
||||||
|
<KEYWORD2>FALSE</KEYWORD2>
|
||||||
|
<KEYWORD2>true</KEYWORD2>
|
||||||
|
<KEYWORD2>false</KEYWORD2>
|
||||||
|
</KEYWORDS>
|
||||||
|
</RULES>
|
||||||
|
</MODE>
|
9
syntax/kate/README
Normal file
9
syntax/kate/README
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
To use the Kate syntax highlighting install qc.xml to the syntax
|
||||||
|
directory for kate.
|
||||||
|
|
||||||
|
# Can be installed globally to
|
||||||
|
$KDEDIR/share/apps/katepart/syntax
|
||||||
|
|
||||||
|
if $KDEDIR is unset you can lookup the folder directory with
|
||||||
|
kde4-config --prefix if that doesn't work chances are KDEDIR is
|
||||||
|
/usr
|
155
syntax/kate/qc.xml
Normal file
155
syntax/kate/qc.xml
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE language SYSTEM "language.dtd">
|
||||||
|
<language name="QuakeC" section="Sources"
|
||||||
|
version="1.00" kateversion="2.4"
|
||||||
|
indenter="cstyle"
|
||||||
|
extensions="*.qc;*.QC;*.qh"
|
||||||
|
mimetype=""
|
||||||
|
priority="5"
|
||||||
|
author="Dale Weiler">
|
||||||
|
<highlighting>
|
||||||
|
<list name="keywords">
|
||||||
|
<item> break </item>
|
||||||
|
<item> case </item>
|
||||||
|
<item> continue </item>
|
||||||
|
<item> default </item>
|
||||||
|
<item> do </item>
|
||||||
|
<item> else </item>
|
||||||
|
<item> enum </item>
|
||||||
|
<item> for </item>
|
||||||
|
<item> goto </item>
|
||||||
|
<item> if </item>
|
||||||
|
<item> return </item>
|
||||||
|
<item> switch </item>
|
||||||
|
<item> typedef </item>
|
||||||
|
<item> while </item>
|
||||||
|
<item> nil </item>
|
||||||
|
</list>
|
||||||
|
<list name="types">
|
||||||
|
<item> const </item>
|
||||||
|
<item> vector </item>
|
||||||
|
<item> float </item>
|
||||||
|
<item> void </item>
|
||||||
|
<item> string </item>
|
||||||
|
</list>
|
||||||
|
<contexts>
|
||||||
|
<context attribute="Normal Text" lineEndContext="#stay" name="Normal">
|
||||||
|
<DetectSpaces />
|
||||||
|
<RegExpr attribute="Preprocessor" context="Outscoped" String="#\s*if\s+0\s*$" beginRegion="PP" firstNonSpace="true" />
|
||||||
|
<DetectChar context="AfterHash" char="#" firstNonSpace="true" lookAhead="true" />
|
||||||
|
<StringDetect attribute="Region Marker" context="Region Marker" String="//BEGIN" beginRegion="Region1" firstNonSpace="true" />
|
||||||
|
<StringDetect attribute="Region Marker" context="Region Marker" String="//END" endRegion="Region1" firstNonSpace="true" />
|
||||||
|
<keyword attribute="Keyword" context="#stay" String="keywords"/>
|
||||||
|
<keyword attribute="Data Type" context="#stay" String="types"/>
|
||||||
|
<DetectIdentifier />
|
||||||
|
<DetectChar attribute="Symbol" context="#stay" char="{" beginRegion="Brace1" />
|
||||||
|
<DetectChar attribute="Symbol" context="#stay" char="}" endRegion="Brace1" />
|
||||||
|
<Float attribute="Float" context="#stay">
|
||||||
|
<AnyChar String="fF" attribute="Float" context="#stay"/>
|
||||||
|
</Float>
|
||||||
|
<HlCHex attribute="Hex" context="#stay"/>
|
||||||
|
<Int attribute="Decimal" context="#stay" >
|
||||||
|
<StringDetect attribute="Decimal" context="#stay" String="ULL" insensitive="TRUE"/>
|
||||||
|
<StringDetect attribute="Decimal" context="#stay" String="LUL" insensitive="TRUE"/>
|
||||||
|
<StringDetect attribute="Decimal" context="#stay" String="LLU" insensitive="TRUE"/>
|
||||||
|
<StringDetect attribute="Decimal" context="#stay" String="UL" insensitive="TRUE"/>
|
||||||
|
<StringDetect attribute="Decimal" context="#stay" String="LU" insensitive="TRUE"/>
|
||||||
|
<StringDetect attribute="Decimal" context="#stay" String="LL" insensitive="TRUE"/>
|
||||||
|
<StringDetect attribute="Decimal" context="#stay" String="U" insensitive="TRUE"/>
|
||||||
|
<StringDetect attribute="Decimal" context="#stay" String="L" insensitive="TRUE"/>
|
||||||
|
</Int>
|
||||||
|
<HlCChar attribute="Char" context="#stay"/>
|
||||||
|
<DetectChar attribute="String" context="String" char="""/>
|
||||||
|
<Detect2Chars attribute="Comment" context="Commentar 1" char="/" char1="/"/>
|
||||||
|
<Detect2Chars attribute="Comment" context="Commentar 2" char="/" char1="*" beginRegion="Comment"/>
|
||||||
|
<AnyChar attribute="Symbol" context="#stay" String=":!%&()+,-/.*<=>?[]|~^;"/>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="String" lineEndContext="#pop" name="String">
|
||||||
|
<LineContinue attribute="String" context="#stay"/>
|
||||||
|
<HlCStringChar attribute="String Char" context="#stay"/>
|
||||||
|
<DetectChar attribute="String" context="#pop" char="""/>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Region Marker" lineEndContext="#pop" name="Region Marker">
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Comment" lineEndContext="#pop" name="Commentar 1">
|
||||||
|
<LineContinue attribute="Comment" context="#stay"/>
|
||||||
|
<IncludeRules context="##Alerts" />
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Comment" lineEndContext="#stay" name="Commentar 2">
|
||||||
|
<Detect2Chars attribute="Comment" context="#pop" char="*" char1="/" endRegion="Comment"/>
|
||||||
|
<IncludeRules context="##Alerts" />
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Error" lineEndContext="#pop" name="AfterHash">
|
||||||
|
<!-- define, elif, else, endif, error, if, ifdef, ifndef, include, include_next, line, pragma, undef, warning -->
|
||||||
|
<RegExpr attribute="Preprocessor" context="Preprocessor" String="#\s*if(?:def|ndef)?(?=\s+\S)" insensitive="true" beginRegion="PP" firstNonSpace="true" />
|
||||||
|
<RegExpr attribute="Preprocessor" context="Preprocessor" String="#\s*endif" insensitive="true" endRegion="PP" firstNonSpace="true" />
|
||||||
|
<RegExpr attribute="Preprocessor" context="Define" String="#\s*define.*((?=\\))" insensitive="true" firstNonSpace="true" />
|
||||||
|
<RegExpr attribute="Preprocessor" context="Preprocessor" String="#\s*(?:el(?:se|if)|include(?:_next)?|define|undef|line|error|warning|pragma)" insensitive="true" firstNonSpace="true" />
|
||||||
|
<RegExpr attribute="Preprocessor" context="Preprocessor" String="#\s+[0-9]+" insensitive="true" firstNonSpace="true" />
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Preprocessor" lineEndContext="#pop" name="Preprocessor">
|
||||||
|
<LineContinue attribute="Preprocessor" context="#stay"/>
|
||||||
|
<RangeDetect attribute="Prep. Lib" context="#stay" char=""" char1="""/>
|
||||||
|
<RangeDetect attribute="Prep. Lib" context="#stay" char="<" char1=">"/>
|
||||||
|
<IncludeRules context="##Doxygen" />
|
||||||
|
<Detect2Chars attribute="Comment" context="Commentar/Preprocessor" char="/" char1="*" beginRegion="Comment2" />
|
||||||
|
<Detect2Chars attribute="Comment" context="Commentar 1" char="/" char1="/" />
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Preprocessor" lineEndContext="#pop" name="Define">
|
||||||
|
<LineContinue attribute="Preprocessor" context="#stay"/>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Comment" lineEndContext="#stay" name="Commentar/Preprocessor">
|
||||||
|
<Detect2Chars attribute="Comment" context="#pop" char="*" char1="/" endRegion="Comment2" />
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Comment" lineEndContext="#stay" name="Outscoped" >
|
||||||
|
<DetectSpaces />
|
||||||
|
<DetectIdentifier />
|
||||||
|
<DetectChar attribute="String" context="String" char="""/>
|
||||||
|
<Detect2Chars attribute="Comment" context="Commentar 1" char="/" char1="/"/>
|
||||||
|
<Detect2Chars attribute="Comment" context="Commentar 2" char="/" char1="*" beginRegion="Comment"/>
|
||||||
|
<RegExpr attribute="Comment" context="Outscoped intern" String="#\s*if" beginRegion="PP" firstNonSpace="true" />
|
||||||
|
<RegExpr attribute="Preprocessor" context="#pop" String="#\s*el(?:se|if)" firstNonSpace="true" />
|
||||||
|
<RegExpr attribute="Preprocessor" context="#pop" String="#\s*endif" endRegion="PP" firstNonSpace="true" />
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Comment" lineEndContext="#stay" name="Outscoped intern">
|
||||||
|
<DetectSpaces />
|
||||||
|
<DetectIdentifier />
|
||||||
|
<DetectChar attribute="String" context="String" char="""/>
|
||||||
|
<Detect2Chars attribute="Comment" context="Commentar 1" char="/" char1="/"/>
|
||||||
|
<Detect2Chars attribute="Comment" context="Commentar 2" char="/" char1="*" beginRegion="Comment"/>
|
||||||
|
<RegExpr attribute="Comment" context="Outscoped intern" String="#\s*if" beginRegion="PP" firstNonSpace="true" />
|
||||||
|
<RegExpr attribute="Comment" context="#pop" String="#\s*endif" endRegion="PP" firstNonSpace="true" />
|
||||||
|
</context>
|
||||||
|
</contexts>
|
||||||
|
<itemDatas>
|
||||||
|
<itemData name="Normal Text" defStyleNum="dsNormal" spellChecking="false"/>
|
||||||
|
<itemData name="Keyword" defStyleNum="dsKeyword" spellChecking="false"/>
|
||||||
|
<itemData name="Data Type" defStyleNum="dsDataType" spellChecking="false"/>
|
||||||
|
<itemData name="Decimal" defStyleNum="dsDecVal" spellChecking="false"/>
|
||||||
|
<itemData name="Hex" defStyleNum="dsBaseN" spellChecking="false"/>
|
||||||
|
<itemData name="Float" defStyleNum="dsFloat" spellChecking="false"/>
|
||||||
|
<itemData name="String" defStyleNum="dsString"/>
|
||||||
|
<itemData name="String Char" defStyleNum="dsChar"/>
|
||||||
|
<itemData name="Comment" defStyleNum="dsComment"/>
|
||||||
|
<itemData name="Symbol" defStyleNum="dsNormal" spellChecking="false"/>
|
||||||
|
<itemData name="Preprocessor" defStyleNum="dsOthers" spellChecking="false"/>
|
||||||
|
</itemDatas>
|
||||||
|
</highlighting>
|
||||||
|
<general>
|
||||||
|
<comments>
|
||||||
|
<comment name="singleLine" start="//" />
|
||||||
|
<comment name="multiLine" start="/*" end="*/" />
|
||||||
|
</comments>
|
||||||
|
<keywords casesensitive="1" additionalDeliminator="'"" />
|
||||||
|
</general>
|
||||||
|
</language>
|
12
syntax/nano/README
Normal file
12
syntax/nano/README
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
To use the nano syntax highlighting install qc.nanorc somewhere and
|
||||||
|
add:
|
||||||
|
|
||||||
|
include /directory/qc.nanorc
|
||||||
|
|
||||||
|
to your nanorc file located at ~/.nanorc. If the file doesn't exist
|
||||||
|
create it.
|
||||||
|
|
||||||
|
Optionally you can install it globally by installing qc.nanorc to
|
||||||
|
/usr/share/nano
|
||||||
|
|
||||||
|
However you still need to provide the include to your ~/.nanorc
|
22
syntax/nano/qc.nanorc
Normal file
22
syntax/nano/qc.nanorc
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Language: QuakeC
|
||||||
|
# Maintainer: Dale Weiler
|
||||||
|
|
||||||
|
syntax "qc" "\.(qc|QC)$" "\.(qh|QH)$"
|
||||||
|
color brightred "\<[A-Z_][0-9A-Z_]+\>"
|
||||||
|
color green "\<(float|string|enum|void|const|typedef|nil)\>"
|
||||||
|
color brightyellow "\<(for|if|while|do|else|case|default|switch)\>"
|
||||||
|
color magenta "\<(goto|continue|break|return)\>"
|
||||||
|
color brightcyan "^[[:space:]]*#[[:space:]]*(define|include|(un|ifn?)def|endif|el(if|se)|if|warning|error|pragma)"
|
||||||
|
color brightmagenta "'([^'\]|(\\["'abfnrtv\\]))'" "'\\(([0-3]?[0-7]{1,2}))'" "'\\x[0-9A-Fa-f]{1,2}'"
|
||||||
|
|
||||||
|
color brightyellow "<[^= ]*>" ""(\\.|[^"])*""
|
||||||
|
|
||||||
|
## This string is VERY resource intensive!
|
||||||
|
color brightyellow start=""(\\.|[^"])*\\[[:space:]]*$" end="^(\\.|[^"])*""
|
||||||
|
|
||||||
|
## Comment highlighting
|
||||||
|
color brightblue "//.*"
|
||||||
|
color brightblue start="/\*" end="\*/"
|
||||||
|
|
||||||
|
## Trailing whitespace
|
||||||
|
color ,green "[[:space:]]+$"
|
260
test.c
260
test.c
|
@ -176,8 +176,8 @@ int task_pclose(FILE **handles) {
|
||||||
}
|
}
|
||||||
#endif /*! _WIN32 */
|
#endif /*! _WIN32 */
|
||||||
|
|
||||||
#define TASK_COMPILE 0
|
#define TASK_COMPILE 0
|
||||||
#define TASK_EXECUTE 1
|
#define TASK_EXECUTE 1
|
||||||
/*
|
/*
|
||||||
* Task template system:
|
* Task template system:
|
||||||
* templates are rules for a specific test, used to create a "task" that
|
* templates are rules for a specific test, used to create a "task" that
|
||||||
|
@ -269,6 +269,7 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
bool task_template_generate(task_template_t *tmpl, char tag, const char *file, size_t line, char *value, size_t *pad) {
|
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 desclen = 0;
|
||||||
|
size_t filelen = 0;
|
||||||
char **destval = NULL;
|
char **destval = NULL;
|
||||||
|
|
||||||
if (!tmpl)
|
if (!tmpl)
|
||||||
|
@ -315,7 +316,7 @@ bool task_template_generate(task_template_t *tmpl, char tag, const char *file, s
|
||||||
if (strchr(value, '\n'))
|
if (strchr(value, '\n'))
|
||||||
*strrchr(value, '\n')='\0';
|
*strrchr(value, '\n')='\0';
|
||||||
else /* cppcheck: possible nullpointer dereference */
|
else /* cppcheck: possible nullpointer dereference */
|
||||||
abort();
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now allocate and set the actual value for the specific tag. Which
|
* Now allocate and set the actual value for the specific tag. Which
|
||||||
|
@ -333,6 +334,9 @@ bool task_template_generate(task_template_t *tmpl, char tag, const char *file, s
|
||||||
pad[0] = desclen;
|
pad[0] = desclen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((filelen = strlen(file)) > pad[2])
|
||||||
|
pad[2] = filelen;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +432,7 @@ bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size
|
||||||
if (strrchr(value, '\n'))
|
if (strrchr(value, '\n'))
|
||||||
*strrchr(value, '\n')='\0';
|
*strrchr(value, '\n')='\0';
|
||||||
else /* cppcheck: possible null pointer dereference */
|
else /* cppcheck: possible null pointer dereference */
|
||||||
abort();
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
vec_push(tmpl->comparematch, util_strdup(value));
|
vec_push(tmpl->comparematch, util_strdup(value));
|
||||||
|
|
||||||
|
@ -563,7 +567,13 @@ task_template_t *task_template_compile(const char *file, const char *dir, size_t
|
||||||
con_err("template compile warning: %s erroneous tag `E:` when only failing\n", file);
|
con_err("template compile warning: %s erroneous tag `E:` when only failing\n", file);
|
||||||
if (tmpl->comparematch)
|
if (tmpl->comparematch)
|
||||||
con_err("template compile warning: %s erroneous tag `M:` when only failing\n", file);
|
con_err("template compile warning: %s erroneous tag `M:` when only failing\n", file);
|
||||||
goto success;
|
} else if (!strcmp(tmpl->proceduretype, "-pp")) {
|
||||||
|
if (tmpl->executeflags)
|
||||||
|
con_err("template compile warning: %s erroneous tag `E:` when only preprocessing\n", file);
|
||||||
|
if (!tmpl->comparematch) {
|
||||||
|
con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
con_err("template compile error: %s invalid procedure type: %s\n", file, tmpl->proceduretype);
|
con_err("template compile error: %s invalid procedure type: %s\n", file, tmpl->proceduretype);
|
||||||
goto failure;
|
goto failure;
|
||||||
|
@ -644,10 +654,10 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
size_t found = 0;
|
size_t found = 0;
|
||||||
|
|
||||||
dir = opendir(curdir);
|
dir = fs_dir_open(curdir);
|
||||||
|
|
||||||
while ((files = readdir(dir))) {
|
while ((files = fs_dir_read(dir))) {
|
||||||
snprintf(buffer, sizeof(buffer), "%s/%s", curdir, files->d_name);
|
snprintf(buffer, sizeof(buffer), "%s/%s", curdir, files->d_name);
|
||||||
|
|
||||||
if (stat(buffer, &directory) == -1) {
|
if (stat(buffer, &directory) == -1) {
|
||||||
con_err("internal error: stat failed, aborting\n");
|
con_err("internal error: stat failed, aborting\n");
|
||||||
|
@ -679,7 +689,8 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
||||||
* Generate a temportary file name for the output binary
|
* Generate a temportary file name for the output binary
|
||||||
* so we don't trample over an existing one.
|
* so we don't trample over an existing one.
|
||||||
*/
|
*/
|
||||||
tmpl->tempfilename = tempnam(curdir, "TMPDAT");
|
tmpl->tempfilename = NULL;
|
||||||
|
util_asprintf(&tmpl->tempfilename, "%s/TMPDAT.%s", curdir, files->d_name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Additional QCFLAGS enviroment variable may be used
|
* Additional QCFLAGS enviroment variable may be used
|
||||||
|
@ -693,45 +704,66 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
||||||
* which will be refered to with a handle in the task for
|
* which will be refered to with a handle in the task for
|
||||||
* reading the data from the pipe.
|
* reading the data from the pipe.
|
||||||
*/
|
*/
|
||||||
if (qcflags) {
|
if (strcmp(tmpl->proceduretype, "-pp")) {
|
||||||
if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
|
if (qcflags) {
|
||||||
snprintf(buf, sizeof(buf), "%s %s/%s %s %s -o %s",
|
if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
|
||||||
task_bins[TASK_COMPILE],
|
snprintf(buf, sizeof(buf), "%s %s/%s %s %s -o %s",
|
||||||
curdir,
|
task_bins[TASK_COMPILE],
|
||||||
tmpl->sourcefile,
|
curdir,
|
||||||
qcflags,
|
tmpl->sourcefile,
|
||||||
tmpl->compileflags,
|
qcflags,
|
||||||
tmpl->tempfilename
|
tmpl->compileflags,
|
||||||
);
|
tmpl->tempfilename
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s %s -o %s",
|
||||||
|
task_bins[TASK_COMPILE],
|
||||||
|
curdir,
|
||||||
|
defs,
|
||||||
|
curdir,
|
||||||
|
tmpl->sourcefile,
|
||||||
|
qcflags,
|
||||||
|
tmpl->compileflags,
|
||||||
|
tmpl->tempfilename
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s %s -o %s",
|
if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
|
||||||
task_bins[TASK_COMPILE],
|
snprintf(buf, sizeof(buf), "%s %s/%s %s -o %s",
|
||||||
curdir,
|
task_bins[TASK_COMPILE],
|
||||||
defs,
|
curdir,
|
||||||
curdir,
|
tmpl->sourcefile,
|
||||||
tmpl->sourcefile,
|
tmpl->compileflags,
|
||||||
qcflags,
|
tmpl->tempfilename
|
||||||
tmpl->compileflags,
|
);
|
||||||
tmpl->tempfilename
|
} else {
|
||||||
);
|
snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s -o %s",
|
||||||
|
task_bins[TASK_COMPILE],
|
||||||
|
curdir,
|
||||||
|
defs,
|
||||||
|
curdir,
|
||||||
|
tmpl->sourcefile,
|
||||||
|
tmpl->compileflags,
|
||||||
|
tmpl->tempfilename
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* Preprocessing (qcflags mean shit all here we don't allow them) */
|
||||||
if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
|
if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
|
||||||
snprintf(buf, sizeof(buf), "%s %s/%s %s -o %s",
|
snprintf(buf, sizeof(buf), "%s -E %s/%s -o %s",
|
||||||
task_bins[TASK_COMPILE],
|
task_bins[TASK_COMPILE],
|
||||||
curdir,
|
curdir,
|
||||||
tmpl->sourcefile,
|
tmpl->sourcefile,
|
||||||
tmpl->compileflags,
|
|
||||||
tmpl->tempfilename
|
tmpl->tempfilename
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s -o %s",
|
snprintf(buf, sizeof(buf), "%s -E %s/%s %s/%s -o %s",
|
||||||
task_bins[TASK_COMPILE],
|
task_bins[TASK_COMPILE],
|
||||||
curdir,
|
curdir,
|
||||||
defs,
|
defs,
|
||||||
curdir,
|
curdir,
|
||||||
tmpl->sourcefile,
|
tmpl->sourcefile,
|
||||||
tmpl->compileflags,
|
|
||||||
tmpl->tempfilename
|
tmpl->tempfilename
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -777,7 +809,7 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
||||||
found
|
found
|
||||||
);
|
);
|
||||||
|
|
||||||
closedir(dir);
|
fs_dir_close(dir);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,9 +822,9 @@ void task_precleanup(const char *curdir) {
|
||||||
struct dirent *files;
|
struct dirent *files;
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
|
|
||||||
dir = opendir(curdir);
|
dir = fs_dir_open(curdir);
|
||||||
|
|
||||||
while ((files = readdir(dir))) {
|
while ((files = fs_dir_read(dir))) {
|
||||||
if (strstr(files->d_name, "TMP") ||
|
if (strstr(files->d_name, "TMP") ||
|
||||||
strstr(files->d_name, ".stdout") ||
|
strstr(files->d_name, ".stdout") ||
|
||||||
strstr(files->d_name, ".stderr"))
|
strstr(files->d_name, ".stderr"))
|
||||||
|
@ -805,7 +837,7 @@ void task_precleanup(const char *curdir) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
fs_dir_close(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_destroy(void) {
|
void task_destroy(void) {
|
||||||
|
@ -854,40 +886,50 @@ void task_destroy(void) {
|
||||||
/*
|
/*
|
||||||
* This executes the QCVM task for a specificly compiled progs.dat
|
* This executes the QCVM task for a specificly compiled progs.dat
|
||||||
* using the template passed into it for call-flags and user defined
|
* using the template passed into it for call-flags and user defined
|
||||||
* messages.
|
* messages IF the procedure type is -execute, otherwise it matches
|
||||||
|
* the preprocessor output.
|
||||||
*/
|
*/
|
||||||
bool task_execute(task_template_t *tmpl, char ***line) {
|
bool task_trymatch(task_template_t *tmpl, char ***line) {
|
||||||
bool success = true;
|
bool success = true;
|
||||||
FILE *execute;
|
FILE *execute;
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
memset (buffer,0,sizeof(buffer));
|
memset (buffer,0,sizeof(buffer));
|
||||||
|
|
||||||
/*
|
if (strcmp(tmpl->proceduretype, "-pp")) {
|
||||||
* Drop the execution flags for the QCVM if none where
|
/*
|
||||||
* actually specified.
|
* Drop the execution flags for the QCVM if none where
|
||||||
*/
|
* actually specified.
|
||||||
if (!strcmp(tmpl->executeflags, "$null")) {
|
*/
|
||||||
snprintf(buffer, sizeof(buffer), "%s %s",
|
if (!strcmp(tmpl->executeflags, "$null")) {
|
||||||
task_bins[TASK_EXECUTE],
|
snprintf(buffer, sizeof(buffer), "%s %s",
|
||||||
tmpl->tempfilename
|
task_bins[TASK_EXECUTE],
|
||||||
|
tmpl->tempfilename
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
snprintf(buffer, sizeof(buffer), "%s %s %s",
|
||||||
|
task_bins[TASK_EXECUTE],
|
||||||
|
tmpl->executeflags,
|
||||||
|
tmpl->tempfilename
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
util_debug("TEST", "executing qcvm: `%s` [%s]\n",
|
||||||
|
tmpl->description,
|
||||||
|
buffer
|
||||||
);
|
);
|
||||||
|
|
||||||
|
execute = popen(buffer, "r");
|
||||||
|
if (!execute)
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
snprintf(buffer, sizeof(buffer), "%s %s %s",
|
/*
|
||||||
task_bins[TASK_EXECUTE],
|
* we're preprocessing, which means we need to read int
|
||||||
tmpl->executeflags,
|
* the produced file and do some really weird shit.
|
||||||
tmpl->tempfilename
|
*/
|
||||||
);
|
if (!(execute = fs_file_open(tmpl->tempfilename, "r")))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
util_debug("TEST", "executing qcvm: `%s` [%s]\n",
|
|
||||||
tmpl->description,
|
|
||||||
buffer
|
|
||||||
);
|
|
||||||
|
|
||||||
execute = popen(buffer, "r");
|
|
||||||
if (!execute)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now lets read the lines and compare them to the matches we expect
|
* Now lets read the lines and compare them to the matches we expect
|
||||||
* and handle accordingly.
|
* and handle accordingly.
|
||||||
|
@ -913,6 +955,13 @@ bool task_execute(task_template_t *tmpl, char ***line) {
|
||||||
if (strrchr(data, '\n'))
|
if (strrchr(data, '\n'))
|
||||||
*strrchr(data, '\n') = '\0';
|
*strrchr(data, '\n') = '\0';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If data is just null now, that means the line was an empty
|
||||||
|
* one and for that, we just ignore it.
|
||||||
|
*/
|
||||||
|
if (!*data)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (vec_size(tmpl->comparematch) > compare) {
|
if (vec_size(tmpl->comparematch) > compare) {
|
||||||
if (strcmp(data, tmpl->comparematch[compare++]))
|
if (strcmp(data, tmpl->comparematch[compare++]))
|
||||||
success = false;
|
success = false;
|
||||||
|
@ -933,10 +982,25 @@ bool task_execute(task_template_t *tmpl, char ***line) {
|
||||||
mem_d(data);
|
mem_d(data);
|
||||||
data = NULL;
|
data = NULL;
|
||||||
}
|
}
|
||||||
pclose(execute);
|
|
||||||
|
if (strcmp(tmpl->proceduretype, "-pp"))
|
||||||
|
pclose(execute);
|
||||||
|
else
|
||||||
|
fs_file_close(execute);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *task_type(task_template_t *tmpl) {
|
||||||
|
if (!strcmp(tmpl->proceduretype, "-pp"))
|
||||||
|
return "type: preprocessor";
|
||||||
|
if (!strcmp(tmpl->proceduretype, "-execute"))
|
||||||
|
return "type: execution";
|
||||||
|
if (!strcmp(tmpl->proceduretype, "-compile"))
|
||||||
|
return "type: compile";
|
||||||
|
return "type: fail";
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This schedualizes all tasks and actually runs them individually
|
* This schedualizes all tasks and actually runs them individually
|
||||||
* this is generally easy for just -compile variants. For compile and
|
* this is generally easy for just -compile variants. For compile and
|
||||||
|
@ -945,6 +1009,7 @@ bool task_execute(task_template_t *tmpl, char ***line) {
|
||||||
*/
|
*/
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
void task_schedualize(size_t *pad) {
|
void task_schedualize(size_t *pad) {
|
||||||
|
char space[2][64];
|
||||||
bool execute = false;
|
bool execute = false;
|
||||||
char *data = NULL;
|
char *data = NULL;
|
||||||
char **match = NULL;
|
char **match = NULL;
|
||||||
|
@ -952,15 +1017,21 @@ void task_schedualize(size_t *pad) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
size_t j = 0;
|
size_t j = 0;
|
||||||
|
|
||||||
|
snprintf(space[0], sizeof(space[0]), "%d", (int)vec_size(task_tasks));
|
||||||
|
|
||||||
for (; i < vec_size(task_tasks); i++) {
|
for (; i < vec_size(task_tasks); i++) {
|
||||||
con_out("test #%u %*s", i + 1, (int)log10(vec_size(task_tasks)) - (int)(log10(i + 1)), "");
|
memset(space[1], 0, sizeof(space[1]));
|
||||||
|
snprintf(space[1], sizeof(space[1]), "%d", (int)(i + 1));
|
||||||
|
|
||||||
|
con_out("test #%u %*s", i + 1, strlen(space[0]) - strlen(space[1]), "");
|
||||||
|
|
||||||
util_debug("TEST", "executing task: %d: %s\n", i, task_tasks[i].tmpl->description);
|
util_debug("TEST", "executing task: %d: %s\n", i, task_tasks[i].tmpl->description);
|
||||||
/*
|
/*
|
||||||
* Generate a task from thin air if it requires execution in
|
* Generate a task from thin air if it requires execution in
|
||||||
* the QCVM.
|
* the QCVM.
|
||||||
*/
|
*/
|
||||||
execute = !!(!strcmp(task_tasks[i].tmpl->proceduretype, "-execute"));
|
execute = !! (!strcmp(task_tasks[i].tmpl->proceduretype, "-execute")) ||
|
||||||
|
(!strcmp(task_tasks[i].tmpl->proceduretype, "-pp"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We assume it compiled before we actually compiled :). On error
|
* We assume it compiled before we actually compiled :). On error
|
||||||
|
@ -979,8 +1050,6 @@ void task_schedualize(size_t *pad) {
|
||||||
task_tasks[i].compiled = false;
|
task_tasks[i].compiled = false;
|
||||||
execute = false;
|
execute = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_file_flush(task_tasks[i].stdoutlog);
|
|
||||||
}
|
}
|
||||||
while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) {
|
while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) {
|
||||||
/*
|
/*
|
||||||
|
@ -997,25 +1066,26 @@ void task_schedualize(size_t *pad) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_file_puts (task_tasks[i].stderrlog, data);
|
fs_file_puts (task_tasks[i].stderrlog, data);
|
||||||
fs_file_flush(task_tasks[i].stdoutlog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!task_tasks[i].compiled && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
|
if (!task_tasks[i].compiled && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
|
||||||
con_err("failure: `%s` (failed to compile) see %s.stdout and %s.stderr [%s]\n",
|
con_out("failure: `%s` %*s %*s\n",
|
||||||
task_tasks[i].tmpl->description,
|
task_tasks[i].tmpl->description,
|
||||||
task_tasks[i].tmpl->tempfilename,
|
(pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
|
||||||
task_tasks[i].tmpl->tempfilename,
|
task_tasks[i].tmpl->rulesfile,
|
||||||
task_tasks[i].tmpl->rulesfile
|
(pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen("(failed to compile)") - pad[2]),
|
||||||
|
"(failed to compile)"
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!execute) {
|
if (!execute) {
|
||||||
con_out("succeeded: `%s` %*s\n",
|
con_out("succeeded: `%s` %*s %*s\n",
|
||||||
task_tasks[i].tmpl->description,
|
task_tasks[i].tmpl->description,
|
||||||
(pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) +
|
(pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
|
||||||
(strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
|
task_tasks[i].tmpl->rulesfile,
|
||||||
task_tasks[i].tmpl->rulesfile
|
(pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen(task_type(task_tasks[i].tmpl)) - pad[2]),
|
||||||
|
task_type(task_tasks[i].tmpl)
|
||||||
|
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1023,14 +1093,24 @@ void task_schedualize(size_t *pad) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we made it here that concludes the task is to be executed
|
* If we made it here that concludes the task is to be executed
|
||||||
* in the virtual machine.
|
* in the virtual machine (or the preprocessor output needs to
|
||||||
|
* be matched).
|
||||||
*/
|
*/
|
||||||
if (!task_execute(task_tasks[i].tmpl, &match)) {
|
if (!task_trymatch(task_tasks[i].tmpl, &match)) {
|
||||||
size_t d = 0;
|
size_t d = 0;
|
||||||
|
|
||||||
con_err("failure: `%s` (invalid results from execution) [%s]\n",
|
con_out("failure: `%s` %*s %*s\n",
|
||||||
task_tasks[i].tmpl->description,
|
task_tasks[i].tmpl->description,
|
||||||
task_tasks[i].tmpl->rulesfile
|
(pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
|
||||||
|
task_tasks[i].tmpl->rulesfile,
|
||||||
|
(pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen(
|
||||||
|
(strcmp(task_tasks[i].tmpl->proceduretype, "-pp"))
|
||||||
|
? "(invalid results from execution)"
|
||||||
|
: "(invalid results from preprocessing)"
|
||||||
|
) - pad[2]),
|
||||||
|
(strcmp(task_tasks[i].tmpl->proceduretype, "-pp"))
|
||||||
|
? "(invalid results from execution)"
|
||||||
|
: "(invalid results from preprocessing)"
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1038,7 +1118,7 @@ void task_schedualize(size_t *pad) {
|
||||||
* handler for the all the given matches in the template file and
|
* handler for the all the given matches in the template file and
|
||||||
* what was actually returned from executing.
|
* what was actually returned from executing.
|
||||||
*/
|
*/
|
||||||
con_err(" Expected From %u Matches: (got %u Matches)\n",
|
con_out(" Expected From %u Matches: (got %u Matches)\n",
|
||||||
vec_size(task_tasks[i].tmpl->comparematch),
|
vec_size(task_tasks[i].tmpl->comparematch),
|
||||||
vec_size(match)
|
vec_size(match)
|
||||||
);
|
);
|
||||||
|
@ -1046,10 +1126,10 @@ void task_schedualize(size_t *pad) {
|
||||||
char *select = task_tasks[i].tmpl->comparematch[d];
|
char *select = task_tasks[i].tmpl->comparematch[d];
|
||||||
size_t length = 40 - strlen(select);
|
size_t length = 40 - strlen(select);
|
||||||
|
|
||||||
con_err(" Expected: \"%s\"", select);
|
con_out(" Expected: \"%s\"", select);
|
||||||
while (length --)
|
while (length --)
|
||||||
con_err(" ");
|
con_out(" ");
|
||||||
con_err("| Got: \"%s\"\n", (d >= vec_size(match)) ? "<<nothing else to compare>>" : match[d]);
|
con_out("| Got: \"%s\"\n", (d >= vec_size(match)) ? "<<nothing else to compare>>" : match[d]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1059,7 +1139,7 @@ void task_schedualize(size_t *pad) {
|
||||||
*/
|
*/
|
||||||
if (vec_size(match) > vec_size(task_tasks[i].tmpl->comparematch)) {
|
if (vec_size(match) > vec_size(task_tasks[i].tmpl->comparematch)) {
|
||||||
for (d = 0; d < vec_size(match) - vec_size(task_tasks[i].tmpl->comparematch); d++) {
|
for (d = 0; d < vec_size(match) - vec_size(task_tasks[i].tmpl->comparematch); d++) {
|
||||||
con_err(" Expected: Nothing | Got: \"%s\"\n",
|
con_out(" Expected: Nothing | Got: \"%s\"\n",
|
||||||
match[d + vec_size(task_tasks[i].tmpl->comparematch)]
|
match[d + vec_size(task_tasks[i].tmpl->comparematch)]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1075,11 +1155,12 @@ void task_schedualize(size_t *pad) {
|
||||||
mem_d(match[j]);
|
mem_d(match[j]);
|
||||||
vec_free(match);
|
vec_free(match);
|
||||||
|
|
||||||
con_out("succeeded: `%s` %*s\n",
|
con_out("succeeded: `%s` %*s %*s\n",
|
||||||
task_tasks[i].tmpl->description,
|
task_tasks[i].tmpl->description,
|
||||||
(pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) +
|
(pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
|
||||||
(strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
|
task_tasks[i].tmpl->rulesfile,
|
||||||
task_tasks[i].tmpl->rulesfile
|
(pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen(task_type(task_tasks[i].tmpl))- pad[2]),
|
||||||
|
task_type(task_tasks[i].tmpl)
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1104,7 +1185,8 @@ GMQCC_WARN bool test_perform(const char *curdir, const char *defs) {
|
||||||
static const char *default_defs = "defs.qh";
|
static const char *default_defs = "defs.qh";
|
||||||
|
|
||||||
size_t pad[] = {
|
size_t pad[] = {
|
||||||
0, 0
|
/* test ### [succeed/fail]: `description` [tests/template.tmpl] [type] */
|
||||||
|
0, 0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -16,3 +16,4 @@ string (...) strcat = #10;
|
||||||
float (string, string) strcmp = #11;
|
float (string, string) strcmp = #11;
|
||||||
vector (vector) normalize = #12;
|
vector (vector) normalize = #12;
|
||||||
float (float) sqrt = #13;
|
float (float) sqrt = #13;
|
||||||
|
float (float) floor = #14;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
void(string, ...) print = #1;enum {
|
enum {
|
||||||
// this behaviour is confusing, but I like that
|
// this behaviour is confusing, but I like that
|
||||||
// we support it.
|
// we support it.
|
||||||
__ = (__ - 1),
|
__ = (__ - 1),
|
||||||
|
@ -27,6 +27,20 @@ enum {
|
||||||
N
|
N
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum : flag {
|
||||||
|
F1, /* = 1 << 1 */
|
||||||
|
F2, /* = 1 << 2 */
|
||||||
|
F3 /* = 1 << 3 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* reversed enumeration */
|
||||||
|
enum : reverse {
|
||||||
|
R1, // 3
|
||||||
|
R2, // 2
|
||||||
|
R3, // 1
|
||||||
|
R4 // 0
|
||||||
|
};
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
print(ftos(A), "\n");
|
print(ftos(A), "\n");
|
||||||
print(ftos(B), "\n");
|
print(ftos(B), "\n");
|
||||||
|
@ -42,4 +56,13 @@ void main() {
|
||||||
print(ftos(L), "\n");
|
print(ftos(L), "\n");
|
||||||
print(ftos(M), "\n");
|
print(ftos(M), "\n");
|
||||||
print(ftos(N), "\n");
|
print(ftos(N), "\n");
|
||||||
|
|
||||||
|
print(ftos(F1), "\n");
|
||||||
|
print(ftos(F2), "\n");
|
||||||
|
print(ftos(F3), "\n");
|
||||||
|
|
||||||
|
print(ftos(R1), "\n");
|
||||||
|
print(ftos(R2), "\n");
|
||||||
|
print(ftos(R3), "\n");
|
||||||
|
print(ftos(R4), "\n");
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,3 +16,10 @@ M: 10
|
||||||
M: 11
|
M: 11
|
||||||
M: 12
|
M: 12
|
||||||
M: 13
|
M: 13
|
||||||
|
M: 2
|
||||||
|
M: 4
|
||||||
|
M: 8
|
||||||
|
M: 3
|
||||||
|
M: 2
|
||||||
|
M: 1
|
||||||
|
M: 0
|
||||||
|
|
14
tests/exponentiation.qc
Normal file
14
tests/exponentiation.qc
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
float pow(float x, float y) {
|
||||||
|
return __builtin_pow(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float hundy = pow(10, 2); // 10^2 == 100
|
||||||
|
print(ftos(hundy), "\n"); // prints: 100
|
||||||
|
|
||||||
|
hundy -= 90; // 100-90 = 10
|
||||||
|
print(ftos(hundy ** 2), "\n"); // prints: 100
|
||||||
|
|
||||||
|
hundy = 10.0f;
|
||||||
|
print(ftos(__builtin_exp(hundy)), "\n"); // prints: 22026.5
|
||||||
|
}
|
9
tests/exponentiation.tmpl
Normal file
9
tests/exponentiation.tmpl
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# used to test the builtins
|
||||||
|
I: exponentiation.qc
|
||||||
|
D: test exponentiation operator and __builtin_pow
|
||||||
|
T: -execute
|
||||||
|
C: -std=gmqcc
|
||||||
|
E: $null
|
||||||
|
M: 100
|
||||||
|
M: 100
|
||||||
|
M: 22026.5
|
13
tests/ppcat.qc
Normal file
13
tests/ppcat.qc
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#define CAT(X, Y) X##Y
|
||||||
|
CAT(hello, world)
|
||||||
|
|
||||||
|
#define REDIR(X, Y) CAT(X, Y)
|
||||||
|
REDIR(CAT(hello, world), CAT(world, hello))
|
||||||
|
|
||||||
|
#define SCONS(X, ...) REDIR(X, __VA_ARGS__)
|
||||||
|
SCONS(hello, world)
|
||||||
|
|
||||||
|
#define FOO(X) X##X
|
||||||
|
#define BAR(X) FOO(X)##FOO(X)
|
||||||
|
|
||||||
|
REDIR(BAR(hello), BAR(world))
|
10
tests/ppcat.tmpl
Normal file
10
tests/ppcat.tmpl
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
I: ppcat.qc
|
||||||
|
D: test preprocessor concatenation
|
||||||
|
T: -pp
|
||||||
|
C: -std=gmqcc
|
||||||
|
F: -no-defs
|
||||||
|
M: helloworld
|
||||||
|
M: helloworldworldhello
|
||||||
|
M: helloworld
|
||||||
|
M: hellohellohellohelloworldworldworldworld
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
I: uninit.qc
|
I: uninit.qc
|
||||||
D: catch another case of unused vector accesses - should fail
|
D: catch another case of unused vector accesses
|
||||||
T: -fail
|
T: -fail
|
||||||
C: -std=fteqcc -Wall -Werror -DUNINIT
|
C: -std=fteqcc -Wall -Werror -DUNINIT
|
||||||
|
|
4
utf8.c
4
utf8.c
|
@ -198,7 +198,7 @@ uchar_t u8_getchar(const char *_s, const char **_end)
|
||||||
|
|
||||||
if (!u8_analyze(_s, &st, &ln, &ch, 0x10))
|
if (!u8_analyze(_s, &st, &ln, &ch, 0x10))
|
||||||
ch = 0;
|
ch = 0;
|
||||||
if (_end)
|
else if (_end)
|
||||||
*_end = _s + st + ln;
|
*_end = _s + st + ln;
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ uchar_t u8_getnchar(const char *_s, const char **_end, size_t _maxlen)
|
||||||
|
|
||||||
if (!u8_analyze(_s, &st, &ln, &ch, _maxlen))
|
if (!u8_analyze(_s, &st, &ln, &ch, _maxlen))
|
||||||
ch = 0;
|
ch = 0;
|
||||||
if (_end)
|
else if (_end)
|
||||||
*_end = _s + st + ln;
|
*_end = _s + st + ln;
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
267
util.c
267
util.c
|
@ -30,6 +30,8 @@ uint64_t mem_ab = 0;
|
||||||
uint64_t mem_db = 0;
|
uint64_t mem_db = 0;
|
||||||
uint64_t mem_at = 0;
|
uint64_t mem_at = 0;
|
||||||
uint64_t mem_dt = 0;
|
uint64_t mem_dt = 0;
|
||||||
|
uint64_t mem_pk = 0;
|
||||||
|
uint64_t mem_hw = 0;
|
||||||
|
|
||||||
struct memblock_t {
|
struct memblock_t {
|
||||||
const char *file;
|
const char *file;
|
||||||
|
@ -39,6 +41,12 @@ struct memblock_t {
|
||||||
struct memblock_t *prev;
|
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;
|
static struct memblock_t *mem_start = NULL;
|
||||||
|
|
||||||
void *util_memory_a(size_t byte, unsigned int line, const char *file) {
|
void *util_memory_a(size_t byte, unsigned int line, const char *file) {
|
||||||
|
@ -56,6 +64,9 @@ void *util_memory_a(size_t byte, unsigned int line, const char *file) {
|
||||||
|
|
||||||
mem_at++;
|
mem_at++;
|
||||||
mem_ab += info->byte;
|
mem_ab += info->byte;
|
||||||
|
mem_hw += info->byte;
|
||||||
|
|
||||||
|
PEAK_MEM;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -67,6 +78,7 @@ void util_memory_d(void *ptrn) {
|
||||||
info = ((struct memblock_t*)ptrn - 1);
|
info = ((struct memblock_t*)ptrn - 1);
|
||||||
|
|
||||||
mem_db += info->byte;
|
mem_db += info->byte;
|
||||||
|
mem_hw -= info->byte;
|
||||||
mem_dt++;
|
mem_dt++;
|
||||||
|
|
||||||
if (info->prev)
|
if (info->prev)
|
||||||
|
@ -122,51 +134,111 @@ void *util_memory_r(void *ptrn, size_t byte, unsigned int line, const char *file
|
||||||
mem_start = newinfo;
|
mem_start = newinfo;
|
||||||
|
|
||||||
mem_ab -= oldinfo->byte;
|
mem_ab -= oldinfo->byte;
|
||||||
|
mem_hw -= oldinfo->byte;
|
||||||
mem_ab += newinfo->byte;
|
mem_ab += newinfo->byte;
|
||||||
|
mem_hw += newinfo->byte;
|
||||||
|
|
||||||
|
PEAK_MEM;
|
||||||
|
|
||||||
free(oldinfo);
|
free(oldinfo);
|
||||||
|
|
||||||
return newinfo+1;
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void util_meminfo() {
|
void util_meminfo() {
|
||||||
struct memblock_t *info;
|
struct memblock_t *info;
|
||||||
|
|
||||||
if (!OPTS_OPTION_BOOL(OPTION_MEMCHK))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (info = mem_start; info; info = info->next) {
|
if (OPTS_OPTION_BOOL(OPTION_DEBUG)) {
|
||||||
util_debug("MEM", "lost: % 8u (bytes) at %s:%u\n",
|
for (info = mem_start; info; info = info->next) {
|
||||||
info->byte,
|
con_out("lost: %u (bytes) at %s:%u\n",
|
||||||
info->file,
|
info->byte,
|
||||||
info->line);
|
info->file,
|
||||||
|
info->line);
|
||||||
|
|
||||||
|
util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
util_debug("MEM", "Memory information:\n\
|
if (OPTS_OPTION_BOOL(OPTION_DEBUG) ||
|
||||||
Total allocations: %llu\n\
|
OPTS_OPTION_BOOL(OPTION_MEMCHK)) {
|
||||||
Total deallocations: %llu\n\
|
con_out("Memory information:\n\
|
||||||
Total allocated: %llu (bytes)\n\
|
Total allocations: %llu\n\
|
||||||
Total deallocated: %llu (bytes)\n\
|
Total deallocations: %llu\n\
|
||||||
Leaks found: lost %llu (bytes) in %d allocations\n",
|
Total allocated: %f (MB)\n\
|
||||||
mem_at, mem_dt,
|
Total deallocated: %f (MB)\n\
|
||||||
mem_ab, mem_db,
|
Total peak memory: %f (MB)\n\
|
||||||
(mem_ab - mem_db),
|
Total leaked memory: %f (MB) in %llu allocations\n",
|
||||||
(mem_at - mem_dt)
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some string utility functions, because strdup uses malloc, and we want
|
* Some string utility functions, because strdup uses malloc, and we want
|
||||||
* to track all memory (without replacing malloc).
|
* to track all memory (without replacing malloc).
|
||||||
*/
|
*/
|
||||||
char *util_strdup(const char *s) {
|
char *_util_Estrdup(const char *s, const char *file, size_t line) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
char *ptr = NULL;
|
char *ptr = NULL;
|
||||||
|
|
||||||
|
/* in case of -DNOTRACK */
|
||||||
|
(void)file;
|
||||||
|
(void)line;
|
||||||
|
|
||||||
if (!s)
|
if (!s)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if ((len = strlen(s)) && (ptr = (char*)mem_a(len+1))) {
|
if ((len = strlen(s)) && (ptr = (char*)mem_af(len+1, line, file))) {
|
||||||
|
memcpy(ptr, s, len);
|
||||||
|
ptr[len] = '\0';
|
||||||
|
}
|
||||||
|
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);
|
memcpy(ptr, s, len);
|
||||||
ptr[len] = '\0';
|
ptr[len] = '\0';
|
||||||
}
|
}
|
||||||
|
@ -253,7 +325,7 @@ void util_endianswap(void *_data, size_t length, unsigned int typesize) {
|
||||||
util_swap64((uint32_t*)_data, length>>3);
|
util_swap64((uint32_t*)_data, length>>3);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default: abort(); /* please blow the fuck up! */
|
default: exit(EXIT_FAILURE); /* please blow the fuck up! */
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -425,7 +497,7 @@ hash_node_t *_util_htnewpair(const char *key, void *value) {
|
||||||
if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t))))
|
if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t))))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!(node->key = util_strdup(key))) {
|
if (!(node->key = util_strdupe(key))) {
|
||||||
mem_d(node);
|
mem_d(node);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -548,7 +620,7 @@ void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin) {
|
||||||
* Free all allocated data in a hashtable, this is quite the amount
|
* Free all allocated data in a hashtable, this is quite the amount
|
||||||
* of work.
|
* of work.
|
||||||
*/
|
*/
|
||||||
void util_htdel(hash_table_t *ht) {
|
void util_htrem(hash_table_t *ht, void (*callback)(void *data)) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (; i < ht->size; i++) {
|
for (; i < ht->size; i++) {
|
||||||
hash_node_t *n = ht->table[i];
|
hash_node_t *n = ht->table[i];
|
||||||
|
@ -558,6 +630,8 @@ void util_htdel(hash_table_t *ht) {
|
||||||
while (n) {
|
while (n) {
|
||||||
if (n->key)
|
if (n->key)
|
||||||
mem_d(n->key);
|
mem_d(n->key);
|
||||||
|
if (callback)
|
||||||
|
callback(n->value);
|
||||||
p = n;
|
p = n;
|
||||||
n = n->next;
|
n = n->next;
|
||||||
mem_d(p);
|
mem_d(p);
|
||||||
|
@ -569,146 +643,33 @@ void util_htdel(hash_table_t *ht) {
|
||||||
mem_d(ht);
|
mem_d(ht);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) {
|
||||||
* A basic implementation of a hash-set. Unlike a hashtable, a hash
|
hash_node_t **pair = &ht->table[bin];
|
||||||
* set doesn't maintain key-value pairs. It simply maintains a key
|
hash_node_t *tmp;
|
||||||
* that can be set, removed, and checked for.
|
|
||||||
*
|
|
||||||
* See EXPOSED interface comment below
|
|
||||||
*/
|
|
||||||
#define GMQCC_HASHSET_PRIME0 0x0049
|
|
||||||
#define GMQCC_HASHSET_PRIME1 0x1391
|
|
||||||
|
|
||||||
static int util_hsput(hash_set_t *set, void *item) {
|
while (*pair && (*pair)->key && strcmp(key, (*pair)->key) > 0)
|
||||||
size_t hash = (size_t)item; /* shouldn't drop the bits */
|
pair = &(*pair)->next;
|
||||||
size_t iter;
|
|
||||||
|
|
||||||
/* a == 0 || a == 1 */
|
tmp = *pair;
|
||||||
if (hash >> 1)
|
if (!tmp || !tmp->key || strcmp(key, tmp->key) != 0)
|
||||||
return -1;
|
return;
|
||||||
|
|
||||||
iter = set->mask & (GMQCC_HASHSET_PRIME0 * hash);
|
if (cb)
|
||||||
|
(*cb)(tmp->value);
|
||||||
|
|
||||||
/* while (set->items[iter] != 0 && set->items[iter] != 1) */
|
*pair = tmp->next;
|
||||||
while (!(set->items[iter] >> 1)) {
|
mem_d(tmp->key);
|
||||||
if (set->items[iter] == hash)
|
mem_d(tmp);
|
||||||
return 0;
|
|
||||||
|
|
||||||
iter = set->mask & (iter + GMQCC_HASHSET_PRIME1);
|
|
||||||
}
|
|
||||||
|
|
||||||
set->total ++;
|
|
||||||
set->items[iter] = hash;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void util_hsupdate(hash_set_t *set) {
|
void util_htrm(hash_table_t *ht, const char *key, void (*cb)(void*)) {
|
||||||
size_t *old;
|
util_htrmh(ht, key, util_hthash(ht, key), cb);
|
||||||
size_t end;
|
|
||||||
size_t itr;
|
|
||||||
|
|
||||||
/* time to rehash? */
|
|
||||||
if ((float)set->total >= (size_t)((double)set->capacity * 0.85)) {
|
|
||||||
old = set->items;
|
|
||||||
end = set->capacity;
|
|
||||||
|
|
||||||
set->bits ++;
|
|
||||||
set->capacity = (size_t)(1 << set->bits);
|
|
||||||
set->mask = set->capacity - 1;
|
|
||||||
set->items = (size_t*)mem_a(set->capacity * sizeof(size_t));
|
|
||||||
set->total = 0;
|
|
||||||
|
|
||||||
/*assert(set->items);*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* this shouldn't be slow? if so unroll it a little perhaps
|
|
||||||
* (shouldn't be though)
|
|
||||||
*/
|
|
||||||
for (itr = 0; itr < end; itr++)
|
|
||||||
util_hsput(set, (void*)old[itr]);
|
|
||||||
|
|
||||||
mem_d(old);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void util_htdel(hash_table_t *ht) {
|
||||||
* EXPOSED interface: all of these functions are exposed to the outside
|
util_htrem(ht, NULL);
|
||||||
* for use. The stuff above is static because it's the "internal" mechanics
|
|
||||||
* for syncronizing the set for updating, and putting data into the set.
|
|
||||||
*/
|
|
||||||
int util_hsadd(hash_set_t *set, void *item) {
|
|
||||||
int run = util_hsput(set, item); /* inlined */
|
|
||||||
util_hsupdate(set);
|
|
||||||
|
|
||||||
return run;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove item in set */
|
|
||||||
int util_hsrem(hash_set_t *set, void *item) {
|
|
||||||
size_t hash = (size_t)item;
|
|
||||||
size_t iter = set->mask & (GMQCC_HASHSET_PRIME0 * hash);
|
|
||||||
|
|
||||||
while (set->items[iter]) {
|
|
||||||
if (set->items[iter] == hash) {
|
|
||||||
set->items[iter] = 1;
|
|
||||||
set->total --;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
iter = set->mask & (iter + GMQCC_HASHSET_PRIME1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check if item is set */
|
|
||||||
int util_hshas(hash_set_t *set, void *item) {
|
|
||||||
size_t hash = (size_t)item;
|
|
||||||
size_t iter = set->mask & (GMQCC_HASHSET_PRIME0 * hash);
|
|
||||||
|
|
||||||
while (set->items[iter]) {
|
|
||||||
if (set->items[iter] == hash)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
iter = set->mask & (iter + GMQCC_HASHSET_PRIME1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
hash_set_t *util_hsnew(void) {
|
|
||||||
hash_set_t *set;
|
|
||||||
|
|
||||||
if (!(set = (hash_set_t*)mem_a(sizeof(hash_set_t))))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
set->bits = 3;
|
|
||||||
set->total = 0;
|
|
||||||
set->capacity = (size_t)(1 << set->bits);
|
|
||||||
set->mask = set->capacity - 1;
|
|
||||||
set->items = (size_t*)mem_a(set->capacity * sizeof(size_t));
|
|
||||||
|
|
||||||
if (!set->items) {
|
|
||||||
util_hsdel(set);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
|
|
||||||
void util_hsdel(hash_set_t *set) {
|
|
||||||
if (!set) return;
|
|
||||||
|
|
||||||
if (set->items)
|
|
||||||
mem_d(set->items);
|
|
||||||
|
|
||||||
mem_d(set);
|
|
||||||
}
|
|
||||||
#undef GMQCC_HASHSET_PRIME0
|
|
||||||
#undef GMQCC_HASHSET_PRIME1
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Portable implementation of vasprintf/asprintf. Assumes vsnprintf
|
* Portable implementation of vasprintf/asprintf. Assumes vsnprintf
|
||||||
* exists, otherwise compiler error.
|
* exists, otherwise compiler error.
|
||||||
|
|
Loading…
Reference in a new issue