mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2024-11-24 04:41:25 +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
|
||||
qcvm
|
||||
gmqcc
|
||||
pak
|
||||
|
||||
distro/arch/*
|
||||
distro/archlinux/*
|
||||
distro/archbsd/*
|
||||
!distro/archlinux/git/PKGBUILD
|
||||
!distro/archlinux/release/PKGBUILD
|
||||
!distro/archbsd/release/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:
|
||||
- __VA_ARGS__ support
|
||||
_ __VA_ARGS__ indexing
|
||||
- Predefined macros like __DATE__, __TIME__, ...
|
||||
(check the manpage for a full list)
|
||||
- Signed numbers as single token in the
|
||||
- Fixes some issues with #if operations on macros.
|
||||
- Speed improvements
|
||||
* Language:
|
||||
- Untyped `nil` keyword.
|
||||
- Removed the `noreturn` keyword.
|
||||
|
@ -21,6 +23,8 @@ Release v0.2.4
|
|||
- Type restricted variadict parameters:
|
||||
ie: void print(string...);
|
||||
- Accessing varargs from QC via: ...(index, type)
|
||||
- New operators: ** (exponentiation), % (modulo), etc
|
||||
- Enumeration attributes: flag, reverse
|
||||
* Compilation:
|
||||
- Various optimizations and progs-size reductions.
|
||||
- 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
|
||||
compatbility option (enabled by default) has been added for
|
||||
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.
|
||||
- More builtins: sqrt(), normalize()
|
||||
* Commandline:
|
||||
- Nicer memory dumps
|
||||
- Support for making individual warnings an error
|
||||
- via -Werror-<warning>
|
||||
- added --add-info
|
||||
* Testsuite:
|
||||
- Support for QCFLAGS to run tests with several additional
|
||||
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
|
||||
* Liferanges
|
||||
|
|
76
Makefile
76
Makefile
|
@ -1,4 +1,5 @@
|
|||
DESTDIR :=
|
||||
OPTIONAL:=
|
||||
PREFIX := /usr/local
|
||||
BINDIR := $(PREFIX)/bin
|
||||
DATADIR := $(PREFIX)/share
|
||||
|
@ -9,7 +10,7 @@ CYGWIN = $(findstring CYGWIN, $(UNAME))
|
|||
MINGW = $(findstring MINGW32, $(UNAME))
|
||||
|
||||
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),)
|
||||
CFLAGS += -DGMQCC_GITINFO="\"$(shell git describe --always)\""
|
||||
endif
|
||||
|
@ -17,28 +18,28 @@ endif
|
|||
# but also turn off the STUPID ONES
|
||||
ifeq ($(CC), clang)
|
||||
CFLAGS += \
|
||||
-Weverything \
|
||||
-Wno-padded \
|
||||
-Wno-format-nonliteral \
|
||||
-Wno-disabled-macro-expansion \
|
||||
-Wno-conversion \
|
||||
-Wno-missing-prototypes \
|
||||
-Wno-float-equal \
|
||||
-Wno-cast-align \
|
||||
-Wno-missing-variable-declarations \
|
||||
-Wno-unknown-warning-option
|
||||
-Weverything \
|
||||
-Wno-padded \
|
||||
-Wno-format-nonliteral \
|
||||
-Wno-disabled-macro-expansion \
|
||||
-Wno-conversion \
|
||||
-Wno-missing-prototypes \
|
||||
-Wno-float-equal \
|
||||
-Wno-cast-align \
|
||||
-Wno-missing-variable-declarations \
|
||||
-Wno-unknown-warning-option
|
||||
else
|
||||
#Tiny C Compiler doesn't know what -pedantic-errors is
|
||||
# and instead of ignoring .. just errors.
|
||||
ifneq ($(CC), tcc)
|
||||
CFLAGS +=-pedantic-errors
|
||||
CFLAGS +=-pedantic-errors -ffunction-sections -fdata-sections -Wl,-gc-sections
|
||||
else
|
||||
CFLAGS += -Wno-pointer-sign -fno-common
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(track), no)
|
||||
CFLAGS += -DNOTRACK
|
||||
CFLAGS += -DNOTRACK
|
||||
endif
|
||||
|
||||
OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o
|
||||
|
@ -84,6 +85,36 @@ else
|
|||
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
|
||||
SPLINTFLAGS = \
|
||||
-redef \
|
||||
|
@ -119,7 +150,6 @@ SPLINTFLAGS = \
|
|||
-kepttrans \
|
||||
-unqualifiedtrans \
|
||||
+matchanyintegral \
|
||||
-bufferoverflowhigh \
|
||||
+voidabstract \
|
||||
-nullassign \
|
||||
-unrecog \
|
||||
|
@ -147,7 +177,7 @@ $(QCVM): $(OBJ_X)
|
|||
$(CC) -o $@ $^ $(CFLAGS) -lm
|
||||
|
||||
$(GMQCC): $(OBJ_C) $(OBJ_D)
|
||||
$(CC) -o $@ $^ $(CFLAGS)
|
||||
$(CC) -o $@ $^ $(CFLAGS) -lm
|
||||
|
||||
$(TESTSUITE): $(OBJ_T)
|
||||
$(CC) -o $@ $^ $(CFLAGS) -lm
|
||||
|
@ -163,11 +193,17 @@ test: all
|
|||
@ ./$(TESTSUITE)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat
|
||||
rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat gource.mp4
|
||||
|
||||
splint:
|
||||
@ splint $(SPLINTFLAGS) *.c *.h
|
||||
|
||||
gource:
|
||||
@ gource $(GOURCEFLAGS)
|
||||
|
||||
gource-record:
|
||||
@ gource $(GOURCEFLAGS) -o - | ffmpeg $(FFMPEGFLAGS) gource.mp4
|
||||
|
||||
depend:
|
||||
@makedepend -Y -w 65536 2> /dev/null \
|
||||
$(subst .o,.c,$(OBJ_D))
|
||||
|
@ -219,9 +255,15 @@ fs.o: gmqcc.h opts.def
|
|||
|
||||
main.o: gmqcc.h opts.def lexer.h
|
||||
lexer.o: gmqcc.h opts.def lexer.h
|
||||
parser.o: gmqcc.h opts.def lexer.h ast.h ir.h
|
||||
parser.o: gmqcc.h opts.def lexer.h ast.h ir.h intrin.h
|
||||
fs.o: gmqcc.h opts.def
|
||||
|
||||
util.o: gmqcc.h opts.def
|
||||
conout.o: gmqcc.h opts.def
|
||||
fs.o: gmqcc.h opts.def
|
||||
|
||||
util.o: gmqcc.h opts.def
|
||||
fs.o: gmqcc.h opts.def
|
||||
conout.o: gmqcc.h opts.def
|
||||
opts.o: gmqcc.h opts.def
|
||||
pak.o: gmqcc.h opts.def
|
||||
|
|
12
README
12
README
|
@ -1,10 +1,14 @@
|
|||
GMQCC: An improved Quake C compiler
|
||||
|
||||
For licensing: see the LICENSE file.
|
||||
For installation notes: see the INSTALL file.
|
||||
For a list of authors: see the AUTHORS file.
|
||||
For a list of changes: see the CHANGES file.
|
||||
For licensing: see the LICENSE file.
|
||||
For installation notes: see the INSTALL file.
|
||||
For a list of authors: see the AUTHORS file.
|
||||
For a list of changes: see the CHANGES file.
|
||||
|
||||
For documentation:
|
||||
See the manpages, or visit the documentation online at
|
||||
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;
|
||||
con_err("ast node missing destroy()\n");
|
||||
abort();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Initialize main ast node aprts */
|
||||
|
@ -87,6 +87,8 @@ static void ast_expression_delete(ast_expression *self)
|
|||
ast_delete(self->expression.params[i]);
|
||||
}
|
||||
vec_free(self->expression.params);
|
||||
if (self->expression.varparam)
|
||||
ast_delete(self->expression.varparam);
|
||||
}
|
||||
|
||||
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 (pos + 6 >= bufsize)
|
||||
goto full;
|
||||
strcpy(buf + pos, "(null)");
|
||||
strncpy(buf + pos, "(null)", 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) {
|
||||
case TYPE_VARIANT:
|
||||
strcpy(buf + pos, "(variant)");
|
||||
strncpy(buf + pos, "(variant)", 9);
|
||||
return pos + 9;
|
||||
|
||||
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);
|
||||
if (pos + typelen >= bufsize)
|
||||
goto full;
|
||||
strcpy(buf + pos, typestr);
|
||||
strncpy(buf + pos, typestr, typelen);
|
||||
return pos + typelen;
|
||||
}
|
||||
|
||||
|
@ -584,6 +586,7 @@ void ast_member_delete(ast_member *self)
|
|||
* purpose that is not garbage-collected.
|
||||
*/
|
||||
ast_expression_delete((ast_expression*)self);
|
||||
mem_d(self->name);
|
||||
mem_d(self);
|
||||
}
|
||||
|
||||
|
@ -1216,7 +1219,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
|
|||
|
||||
namelen = strlen(self->name);
|
||||
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[0] = v;
|
||||
|
@ -1274,7 +1277,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
|
|||
|
||||
namelen = strlen(self->name);
|
||||
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[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);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
name = (char*)mem_a(namelen + 16);
|
||||
strcpy(name, self->name);
|
||||
strncpy(name, self->name, namelen);
|
||||
|
||||
self->ir_values[0] = v;
|
||||
for (ai = 1; ai < self->expression.count; ++ai) {
|
||||
snprintf(name + namelen, 16, "[%u]", (unsigned int)ai);
|
||||
self->ir_values[ai] = ir_function_create_local(func, name, vtype, param);
|
||||
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;
|
||||
}
|
||||
self->ir_values[ai]->context = ast_ctx(self);
|
||||
self->ir_values[ai]->unique_life = true;
|
||||
self->ir_values[ai]->locked = true;
|
||||
}
|
||||
mem_d(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1538,7 +1542,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
|
|||
|
||||
irf = self->ir_func;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
6
conout.c
6
conout.c
|
@ -168,7 +168,7 @@ static int win_fputs(FILE *h, const char *str) {
|
|||
state = -1;
|
||||
}
|
||||
} else {
|
||||
fs_file_putc(h, *str);
|
||||
fs_file_write(str, 1, 1, stdout);
|
||||
length ++;
|
||||
}
|
||||
str++;
|
||||
|
@ -282,10 +282,6 @@ int con_change(const char *out, const char *err) {
|
|||
con_enablecolor();
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
|
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() {
|
||||
cd "$srcdir"/"$_gitname"
|
||||
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."
|
||||
|
||||
install -dm755 ${pkgdir}/usr/local/share/licenses/gmqcc
|
||||
install -m644 LICENSE ${pkgdir}/usr/local/share/licenses/gmqcc/LICENSE
|
||||
install -dm755 ${pkgdir}/usr/share/licenses/gmqcc
|
||||
install -m644 LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
|
||||
}
|
||||
|
|
|
@ -30,9 +30,9 @@ check() {
|
|||
package() {
|
||||
cd "$srcdir"/"$_gitname"
|
||||
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."
|
||||
|
||||
install -dm755 ${pkgdir}/usr/local/share/licenses/gmqcc
|
||||
install -m644 LICENSE ${pkgdir}/usr/local/share/licenses/gmqcc/LICENSE
|
||||
install -dm755 ${pkgdir}/usr/share/licenses/gmqcc
|
||||
install -m644 LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
|
||||
|
||||
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
|
||||
pkgdesc="An Improved Quake C Compiler"
|
||||
arch=('i686' 'x86_64')
|
||||
|
@ -11,40 +15,25 @@ provides=('gmqcc=0.2.4')
|
|||
makedepends=('git')
|
||||
url="https://github.com/graphitemaster/gmqcc.git"
|
||||
license=('MIT')
|
||||
source=('gmqcc::git://github.com/graphitemaster/gmqcc.git')
|
||||
sha1sums=('SKIP')
|
||||
|
||||
_gitroot="git://github.com/graphitemaster/gmqcc.git"
|
||||
_gitname="gmqcc"
|
||||
|
||||
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..."
|
||||
cd "$srcdir"/"$_gitname"
|
||||
cd "$srcdir"/"gmqcc"
|
||||
|
||||
msg "Compiling..."
|
||||
make
|
||||
}
|
||||
|
||||
check() {
|
||||
cd "$srcdir"/"$_gitname"
|
||||
cd "$srcdir"/"gmqcc"
|
||||
make check
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir"/"$_gitname"
|
||||
cd "$srcdir"/"gmqcc"
|
||||
msg "Compiling and installing to pkgdir this time..."
|
||||
make install DESTDIR=$pkgdir PREFIX=/usr
|
||||
msg "Compiling done."
|
||||
|
|
|
@ -9,7 +9,7 @@ depends=('glibc')
|
|||
url="https://github.com/graphitemaster/gmqcc.git"
|
||||
license=('MIT')
|
||||
source=(gmqcc-$pkgver.zip::https://github.com/graphitemaster/gmqcc/zipball/$pkgver)
|
||||
sha1sums=('8cd91dc13f70cd9d3767602bf3eb47a1906d9353')
|
||||
sha1sums=('e0fe99af9a55d36cd9e0909a96d1b14f2db8b757')
|
||||
|
||||
_gitname=graphitemaster-gmqcc-de24486/
|
||||
|
||||
|
|
|
@ -9,9 +9,17 @@ CARCH := $(shell uname -m)
|
|||
PKGDIR := gmqcc-$(MAJOR).$(MINOR).$(PATCH)-$(PKGREL)-$(CARCH)
|
||||
PKG := $(PKGDIR).pkg.tar.xz
|
||||
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 "pkgver = $(MAJOR).$(MINOR).$(PATCH)-$(PKGREL)" >> $(PKGINFO)
|
||||
@echo "pkgdesc = An Improved Quake C Compiler" >> $(PKGINFO)
|
||||
|
@ -34,7 +42,7 @@ base: clean
|
|||
@rm -rf $(PKGDIR)
|
||||
|
||||
clean:
|
||||
@rm -f $(PKG)
|
||||
|
||||
$(MAKE) -C $(BASEDIR) clean
|
||||
@rm -f *.pkg.tar.xz
|
||||
|
||||
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)`
|
||||
PATCH := `sed -n -e '/GMQCC_VERSION_PATCH/{s/.* .* //;p;q;}' $(HEADER)`
|
||||
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:
|
||||
$(MAKE) -C $(BASEDIR) clean
|
||||
$(MAKE) -C $(BASEDIR) DESTDIR=distro/deb/$(DEBDIR) PREFIX=$(PREFIX) install
|
||||
@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 control.tar.gz -C $(DEBDIR)/DEBIAN/ .
|
||||
@echo 2.0 > debian-binary
|
||||
@ar r $(DEB) debian-binary control.tar.gz data.tar.gz
|
||||
@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
|
||||
|
|
|
@ -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)");
|
||||
printf("\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static qcint prog_enterfunction(qc_program *prog, prog_section_function *func)
|
||||
|
@ -825,6 +824,16 @@ static int qc_strcmp(qc_program *prog)
|
|||
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[] = {
|
||||
NULL,
|
||||
&qc_print, /* 1 */
|
||||
|
@ -839,7 +848,8 @@ static prog_builtin qc_builtins[] = {
|
|||
&qc_strcat, /* 10 */
|
||||
&qc_strcmp, /* 11 */
|
||||
&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]);
|
||||
|
||||
|
|
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"Aborting ...\n");
|
||||
abort();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void file_init() {
|
||||
|
@ -165,16 +165,6 @@ int fs_file_seek(FILE *fp, long int off, int 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) {
|
||||
/* Invokes file_exception on windows if fp is null */
|
||||
return ftell(fp);
|
||||
|
@ -238,7 +228,7 @@ int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
|
|||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
strcpy(dir->dd_name, name);
|
||||
strncpy(dir->dd_name, name, strlen(name));
|
||||
return dir;
|
||||
}
|
||||
|
||||
|
@ -258,8 +248,8 @@ int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
|
|||
if (*dir->dd_name) {
|
||||
size_t n = strlen(dir->dd_name);
|
||||
if ((dirname = (char*)mem_a(n + 5) /* 4 + 1 */)) {
|
||||
strcpy(dirname, dir->dd_name);
|
||||
strcpy(dirname + n, "\\*.*"); /* 4 + 1 */
|
||||
strncpy(dirname, dir->dd_name, n);
|
||||
strncpy(dirname + n, "\\*.*", 4); /* 4 + 1 */
|
||||
}
|
||||
} else {
|
||||
if (!(dirname = util_strdup("\\*.*")))
|
||||
|
@ -303,7 +293,6 @@ int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
|
|||
#else
|
||||
# if !defined(__MINGW32__)
|
||||
# include <sys/stat.h> /* mkdir */
|
||||
# include <unistd.h> /* chdir */
|
||||
|
||||
int fs_dir_make(const char *path) {
|
||||
return mkdir(path, 0700);
|
||||
|
@ -326,8 +315,4 @@ struct dirent *fs_dir_read(DIR *dir) {
|
|||
return readdir(dir);
|
||||
}
|
||||
|
||||
int fs_dir_change(const char *path) {
|
||||
return chdir(path);
|
||||
}
|
||||
|
||||
#endif /*! defined(_WIN32) && !defined(__MINGW32__) */
|
||||
|
|
123
ftepp.c
123
ftepp.c
|
@ -25,6 +25,7 @@
|
|||
#include "gmqcc.h"
|
||||
#include "lexer.h"
|
||||
|
||||
#define HT_MACROS 1024
|
||||
typedef struct {
|
||||
bool on;
|
||||
bool was_on;
|
||||
|
@ -55,14 +56,15 @@ typedef struct {
|
|||
pptoken **output;
|
||||
} ppmacro;
|
||||
|
||||
typedef struct {
|
||||
typedef struct ftepp_s {
|
||||
lex_file *lex;
|
||||
int token;
|
||||
unsigned int errors;
|
||||
|
||||
bool output_on;
|
||||
ppcondition *conditions;
|
||||
ppmacro **macros;
|
||||
/*ppmacro **macros;*/
|
||||
ht macros; /* hashtable<string, ppmacro*> */
|
||||
|
||||
char *output_string;
|
||||
|
||||
|
@ -124,7 +126,7 @@ char *ftepp_predef_line(lex_file *context) {
|
|||
char *ftepp_predef_file(lex_file *context) {
|
||||
size_t length = strlen(context->name) + 3; /* two quotes and a terminator */
|
||||
char *value = (char*)mem_a(length);
|
||||
sprintf(value, "\"%s\"", context->name);
|
||||
snprintf(value, length, "\"%s\"", context->name);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -225,7 +227,7 @@ static pptoken *pptoken_make(ftepp_t *ftepp)
|
|||
return token;
|
||||
}
|
||||
|
||||
static void pptoken_delete(pptoken *self)
|
||||
static GMQCC_INLINE void pptoken_delete(pptoken *self)
|
||||
{
|
||||
mem_d(self->value);
|
||||
mem_d(self);
|
||||
|
@ -261,27 +263,27 @@ static ftepp_t* ftepp_new()
|
|||
ftepp = (ftepp_t*)mem_a(sizeof(*ftepp));
|
||||
memset(ftepp, 0, sizeof(*ftepp));
|
||||
|
||||
ftepp->macros = util_htnew(HT_MACROS);
|
||||
ftepp->output_on = true;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void ftepp_delete(ftepp_t *self)
|
||||
{
|
||||
size_t i;
|
||||
ftepp_flush_do(self);
|
||||
if (self->itemname)
|
||||
mem_d(self->itemname);
|
||||
if (self->includename)
|
||||
vec_free(self->includename);
|
||||
for (i = 0; i < vec_size(self->macros); ++i)
|
||||
ppmacro_delete(self->macros[i]);
|
||||
vec_free(self->macros);
|
||||
|
||||
util_htrem(self->macros, (void (*)(void*))&ppmacro_delete);
|
||||
|
||||
vec_free(self->conditions);
|
||||
if (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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
for (i = 0; i < vec_size(ftepp->macros); ++i) {
|
||||
if (!strcmp(name, ftepp->macros[i]->name))
|
||||
return ftepp->macros[i];
|
||||
}
|
||||
return NULL;
|
||||
return util_htget(ftepp->macros, name);
|
||||
}
|
||||
|
||||
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;
|
||||
for (i = 0; i < vec_size(ftepp->macros); ++i) {
|
||||
if (!strcmp(name, ftepp->macros[i]->name)) {
|
||||
vec_remove(ftepp->macros, i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
util_htrm(ftepp->macros, name, NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
} while (ftepp->token == ',');
|
||||
|
||||
if (ftepp->token != ')') {
|
||||
ftepp_error(ftepp, "expected closing paren after macro parameter list");
|
||||
return false;
|
||||
|
@ -422,7 +414,7 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
|
|||
return false;
|
||||
}
|
||||
|
||||
index = atoi(ftepp_tokval(ftepp));
|
||||
index = (int)strtol(ftepp_tokval(ftepp), NULL, 10);
|
||||
|
||||
if (ftepp_next(ftepp) != ']') {
|
||||
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)
|
||||
{
|
||||
ppmacro *macro;
|
||||
ppmacro *macro = NULL;
|
||||
size_t l = ftepp_ctx(ftepp).line;
|
||||
|
||||
(void)ftepp_next(ftepp);
|
||||
|
@ -499,18 +491,28 @@ static bool ftepp_define(ftepp_t *ftepp)
|
|||
|
||||
if (ftepp->token == '(') {
|
||||
macro->has_params = true;
|
||||
if (!ftepp_define_params(ftepp, macro))
|
||||
if (!ftepp_define_params(ftepp, macro)) {
|
||||
ppmacro_delete(macro);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ftepp_skipspace(ftepp))
|
||||
if (!ftepp_skipspace(ftepp)) {
|
||||
ppmacro_delete(macro);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ftepp_define_body(ftepp, macro))
|
||||
if (!ftepp_define_body(ftepp, macro)) {
|
||||
ppmacro_delete(macro);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (ftepp->output_on)
|
||||
vec_push(ftepp->macros, macro);
|
||||
#endif
|
||||
if (ftepp->output_on)
|
||||
util_htset(ftepp->macros, macro->name, (void*)macro);
|
||||
else {
|
||||
ppmacro_delete(macro);
|
||||
}
|
||||
|
@ -830,7 +832,7 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
|
|||
|
||||
if (resetline && !ftepp->in_macro) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* preprocessor. Except here we will want to warn about dangling #ifs.
|
||||
*/
|
||||
static ftepp_t *ftepp;
|
||||
|
||||
static bool ftepp_preprocess_done()
|
||||
static bool ftepp_preprocess_done(ftepp_t *ftepp)
|
||||
{
|
||||
bool retval = true;
|
||||
if (vec_size(ftepp->conditions)) {
|
||||
|
@ -1724,7 +1724,7 @@ static bool ftepp_preprocess_done()
|
|||
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->itemname = util_strdup(filename);
|
||||
|
@ -1734,10 +1734,10 @@ bool ftepp_preprocess_file(const char *filename)
|
|||
}
|
||||
if (!ftepp_preprocess(ftepp))
|
||||
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->itemname = util_strdup(name);
|
||||
|
@ -1747,16 +1747,16 @@ bool ftepp_preprocess_string(const char *name, const char *str)
|
|||
}
|
||||
if (!ftepp_preprocess(ftepp))
|
||||
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;
|
||||
|
||||
/* use saner path for empty macros */
|
||||
if (!value) {
|
||||
ftepp_add_define("__builtin__", name);
|
||||
ftepp_add_define(ftepp, "__builtin__", name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1766,26 +1766,27 @@ void ftepp_add_macro(const char *name, const char *value) {
|
|||
vec_upload(create, value, strlen(value));
|
||||
vec_push (create, 0);
|
||||
|
||||
ftepp_preprocess_string("__builtin__", create);
|
||||
ftepp_preprocess_string(ftepp, "__builtin__", create);
|
||||
vec_free (create);
|
||||
}
|
||||
|
||||
bool ftepp_init()
|
||||
ftepp_t *ftepp_create()
|
||||
{
|
||||
ftepp_t *ftepp;
|
||||
char minor[32];
|
||||
char major[32];
|
||||
|
||||
ftepp = ftepp_new();
|
||||
if (!ftepp)
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
memset(minor, 0, sizeof(minor));
|
||||
memset(major, 0, sizeof(major));
|
||||
|
||||
/* 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) {
|
||||
ftepp_add_define(NULL, "__STD_FTEQCC__");
|
||||
ftepp_add_define(ftepp, NULL, "__STD_FTEQCC__");
|
||||
/* 1.00 */
|
||||
major[0] = '"';
|
||||
major[1] = '1';
|
||||
|
@ -1795,15 +1796,15 @@ bool ftepp_init()
|
|||
minor[1] = '0';
|
||||
minor[2] = '"';
|
||||
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
|
||||
ftepp_add_define(NULL, "__STD_GMQCC__");
|
||||
sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR);
|
||||
sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR);
|
||||
ftepp_add_define(ftepp, NULL, "__STD_GMQCC__");
|
||||
snprintf(major, 32, "\"%d\"", GMQCC_VERSION_MAJOR);
|
||||
snprintf(minor, 32, "\"%d\"", GMQCC_VERSION_MINOR);
|
||||
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCCX) {
|
||||
ftepp_add_define(NULL, "__STD_QCCX__");
|
||||
sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR);
|
||||
sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR);
|
||||
ftepp_add_define(ftepp, NULL, "__STD_QCCX__");
|
||||
snprintf(major, 32, "\"%d\"", GMQCC_VERSION_MAJOR);
|
||||
snprintf(minor, 32, "\"%d\"", GMQCC_VERSION_MINOR);
|
||||
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
|
||||
ftepp_add_define(NULL, "__STD_QCC__");
|
||||
ftepp_add_define(ftepp, NULL, "__STD_QCC__");
|
||||
/* 1.0 */
|
||||
major[0] = '"';
|
||||
major[1] = '1';
|
||||
|
@ -1814,35 +1815,35 @@ bool ftepp_init()
|
|||
minor[2] = '"';
|
||||
}
|
||||
|
||||
ftepp_add_macro("__STD_VERSION_MINOR__", minor);
|
||||
ftepp_add_macro("__STD_VERSION_MAJOR__", major);
|
||||
ftepp_add_macro(ftepp, "__STD_VERSION_MINOR__", minor);
|
||||
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;
|
||||
lex_ctx ctx = { "__builtin__", 0 };
|
||||
ctx.file = source;
|
||||
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;
|
||||
}
|
||||
|
||||
void ftepp_flush()
|
||||
void ftepp_flush(ftepp_t *ftepp)
|
||||
{
|
||||
ftepp_flush_do(ftepp);
|
||||
}
|
||||
|
||||
void ftepp_finish()
|
||||
void ftepp_finish(ftepp_t *ftepp)
|
||||
{
|
||||
if (!ftepp)
|
||||
return;
|
||||
ftepp_delete(ftepp);
|
||||
ftepp = NULL;
|
||||
}
|
||||
|
|
105
gmqcc.h
105
gmqcc.h
|
@ -300,7 +300,8 @@ void util_meminfo ();
|
|||
bool util_filexists (const char *);
|
||||
bool util_strupper (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_endianswap (void *, size_t, unsigned int);
|
||||
|
||||
|
@ -317,22 +318,27 @@ int util_asprintf (char **ret, const char *fmt, ...);
|
|||
|
||||
|
||||
#ifdef NOTRACK
|
||||
# define mem_a(x) malloc (x)
|
||||
# define mem_d(x) free ((void*)x)
|
||||
# define mem_r(x, n) realloc((void*)x, n)
|
||||
# define mem_a(x) malloc (x)
|
||||
# define mem_d(x) free ((void*)x)
|
||||
# define mem_r(x, n) realloc((void*)x, n)
|
||||
# define mem_af(x,f,l) malloc (x)
|
||||
#else
|
||||
# define mem_a(x) util_memory_a((x), __LINE__, __FILE__)
|
||||
# define mem_d(x) util_memory_d((void*)(x))
|
||||
# define mem_r(x, n) util_memory_r((void*)(x), (n), __LINE__, __FILE__)
|
||||
# define mem_a(x) util_memory_a((x), __LINE__, __FILE__)
|
||||
# define mem_d(x) util_memory_d((void*)(x))
|
||||
# define mem_r(x, n) util_memory_r((void*)(x), (n), __LINE__, __FILE__)
|
||||
# define mem_af(x,f,l) util_memory_a((x), __LINE__, __FILE__)
|
||||
#endif /*! NOTRACK */
|
||||
|
||||
#define util_strdup(X) _util_Estrdup((X), __FILE__, __LINE__)
|
||||
#define util_strdupe(X) _util_Estrdup_empty((X), __FILE__, __LINE__)
|
||||
|
||||
/*
|
||||
* A flexible vector implementation: all vector pointers contain some
|
||||
* data about themselfs exactly - sizeof(vector_t) behind the pointer
|
||||
* this data is represented in the structure below. Doing this allows
|
||||
* us to use the array [] to access individual elements from the vector
|
||||
* opposed to using set/get methods.
|
||||
*/
|
||||
*/
|
||||
typedef struct {
|
||||
size_t allocated;
|
||||
size_t used;
|
||||
|
@ -374,14 +380,6 @@ typedef struct hash_table_t {
|
|||
struct hash_node_t **table;
|
||||
} 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:
|
||||
*
|
||||
|
@ -413,51 +411,16 @@ typedef struct hash_set_t {
|
|||
* util_htdel(foo);
|
||||
*/
|
||||
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_htdel (hash_table_t *ht);
|
||||
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_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_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 ===============================*/
|
||||
|
@ -466,10 +429,8 @@ void util_hsdel(hash_set_t *);
|
|||
void fs_file_close (FILE *);
|
||||
int fs_file_error (FILE *);
|
||||
int fs_file_getc (FILE *);
|
||||
int fs_file_flush (FILE *);
|
||||
int fs_file_printf (FILE *, const char *, ...);
|
||||
int fs_file_puts (FILE *, const char *);
|
||||
int fs_file_putc (FILE *, int);
|
||||
int fs_file_seek (FILE *, long int, int);
|
||||
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 *);
|
||||
|
||||
/* directory handling */
|
||||
int fs_dir_make (const char *);
|
||||
DIR *fs_dir_open (const char *);
|
||||
int fs_dir_close (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 ========================*/
|
||||
/*===================================================================*/
|
||||
struct parser_s;
|
||||
|
||||
bool parser_init ();
|
||||
bool parser_compile_file (const char *);
|
||||
bool parser_compile_string(const char *, const char *, size_t);
|
||||
bool parser_finish (const char *);
|
||||
void parser_cleanup ();
|
||||
struct parser_s *parser_create ();
|
||||
bool parser_compile_file (struct parser_s *parser, const char *);
|
||||
bool parser_compile_string(struct parser_s *parser, const char *, const char *, size_t);
|
||||
bool parser_finish (struct parser_s *parser, const char *);
|
||||
void parser_cleanup (struct parser_s *parser);
|
||||
|
||||
/*===================================================================*/
|
||||
/*====================== ftepp.c commandline ========================*/
|
||||
/*===================================================================*/
|
||||
struct lex_file_s;
|
||||
struct ftepp_s;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
char *(*func)(struct lex_file_s *);
|
||||
|
@ -1047,14 +1010,14 @@ typedef struct {
|
|||
*/
|
||||
#define FTEPP_PREDEF_COUNT 8
|
||||
|
||||
bool ftepp_init ();
|
||||
bool ftepp_preprocess_file (const char *filename);
|
||||
bool ftepp_preprocess_string(const char *name, const char *str);
|
||||
void ftepp_finish ();
|
||||
const char *ftepp_get ();
|
||||
void ftepp_flush ();
|
||||
void ftepp_add_define (const char *source, const char *name);
|
||||
void ftepp_add_macro (const char *name, const char *value);
|
||||
struct ftepp_s *ftepp_create ();
|
||||
bool ftepp_preprocess_file (struct ftepp_s *ftepp, const char *filename);
|
||||
bool ftepp_preprocess_string(struct ftepp_s *ftepp, const char *name, const char *str);
|
||||
void ftepp_finish (struct ftepp_s *ftepp);
|
||||
const char *ftepp_get (struct ftepp_s *ftepp);
|
||||
void ftepp_flush (struct ftepp_s *ftepp);
|
||||
void ftepp_add_define (struct ftepp_s *ftepp, const char *source, const char *name);
|
||||
void ftepp_add_macro (struct ftepp_s *ftepp, const char *name, const char *value);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (self->vtype != TYPE_STRING)
|
||||
return false;
|
||||
self->constval.vstring = ir_strdup(str);
|
||||
self->constval.vstring = util_strdupe(str);
|
||||
self->hasvalue = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -1651,7 +1640,7 @@ void ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
|
|||
* is doing something wrong.
|
||||
*/
|
||||
irerror(self->context, "Invalid entry block for PHI");
|
||||
abort();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pe.value = v;
|
||||
|
@ -3292,6 +3281,8 @@ static void gen_vector_defs(prog_section_def def, const char *name)
|
|||
def.offset++;
|
||||
component[len-1]++;
|
||||
}
|
||||
|
||||
mem_d(component);
|
||||
}
|
||||
|
||||
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++;
|
||||
component[len-1]++;
|
||||
}
|
||||
|
||||
mem_d(component);
|
||||
}
|
||||
|
||||
static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal)
|
||||
|
|
27
lexer.c
27
lexer.c
|
@ -272,7 +272,7 @@ void lex_close(lex_file *lex)
|
|||
static int lex_fgetc(lex_file *lex)
|
||||
{
|
||||
if (lex->file)
|
||||
return fgetc(lex->file);
|
||||
return fs_file_getc(lex->file);
|
||||
if (lex->open_string) {
|
||||
if (lex->open_string_pos >= lex->open_string_length)
|
||||
return EOF;
|
||||
|
@ -483,6 +483,9 @@ static bool lex_try_pragma(lex_file *lex)
|
|||
lex->line = line;
|
||||
while (ch != '\n' && ch != EOF)
|
||||
ch = lex_getch(lex);
|
||||
vec_free(command);
|
||||
vec_free(param);
|
||||
vec_free(pragma);
|
||||
return true;
|
||||
|
||||
unroll:
|
||||
|
@ -495,13 +498,13 @@ unroll:
|
|||
vec_free(command);
|
||||
lex_ungetch(lex, ' ');
|
||||
}
|
||||
if (command) {
|
||||
vec_pop(command);
|
||||
while (vec_size(command)) {
|
||||
lex_ungetch(lex, (unsigned char)vec_last(command));
|
||||
vec_pop(command);
|
||||
if (param) {
|
||||
vec_pop(param);
|
||||
while (vec_size(param)) {
|
||||
lex_ungetch(lex, (unsigned char)vec_last(param));
|
||||
vec_pop(param);
|
||||
}
|
||||
vec_free(command);
|
||||
vec_free(param);
|
||||
lex_ungetch(lex, ' ');
|
||||
}
|
||||
if (pragma) {
|
||||
|
@ -1232,7 +1235,7 @@ int lex_do(lex_file *lex)
|
|||
/*
|
||||
case '+':
|
||||
case '-':
|
||||
*/
|
||||
*/
|
||||
case '*':
|
||||
case '/':
|
||||
case '<':
|
||||
|
@ -1352,7 +1355,7 @@ int lex_do(lex_file *lex)
|
|||
lex_tokench(lex, ch);
|
||||
|
||||
nextch = lex_getch(lex);
|
||||
if (nextch == '=') {
|
||||
if (nextch == '=' || nextch == '*') {
|
||||
lex_tokench(lex, nextch);
|
||||
} else
|
||||
lex_ungetch(lex, nextch);
|
||||
|
@ -1361,6 +1364,12 @@ int lex_do(lex_file *lex)
|
|||
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))
|
||||
{
|
||||
const char *v;
|
||||
|
|
17
lexer.h
17
lexer.h
|
@ -166,18 +166,21 @@ typedef struct {
|
|||
static const oper_info c_operators[] = {
|
||||
{ "(", 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, 15, OP_SUFFIX},
|
||||
{ ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 },
|
||||
{ "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */
|
||||
{ "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */
|
||||
{ "++", 1, opid3('S','+','+'), ASSOC_LEFT, 17, OP_SUFFIX},
|
||||
{ "--", 1, opid3('S','-','-'), ASSOC_LEFT, 17, OP_SUFFIX},
|
||||
{ ".", 2, opid1('.'), ASSOC_LEFT, 17, 0 },
|
||||
{ "(", 0, opid1('('), ASSOC_LEFT, 17, 0 }, /* function call */
|
||||
{ "[", 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, opid3('+','+','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||
{ "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||
/* { "&", 1, opid2('&','P'), ASSOC_RIGHT, 14, OP_PREFIX }, */
|
||||
|
||||
{ "*", 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;
|
||||
size_t itr;
|
||||
char buffer[1024];
|
||||
char *redirout = NULL;
|
||||
char *redirerr = NULL;
|
||||
char *config = NULL;
|
||||
char *redirout = NULL;
|
||||
char *redirerr = NULL;
|
||||
char *config = NULL;
|
||||
char *memdumpcols = NULL;
|
||||
|
||||
while (!argend && argc > 1) {
|
||||
char *argarg;
|
||||
|
@ -223,6 +224,10 @@ static bool options_parse(int argc, char **argv) {
|
|||
config = argarg;
|
||||
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) */
|
||||
if (!strcmp(argv[0]+1, "show-defaults")) {
|
||||
|
@ -403,7 +408,7 @@ static bool options_parse(int argc, char **argv) {
|
|||
return false;
|
||||
}
|
||||
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_setoptimlevel(val);
|
||||
} else {
|
||||
|
@ -541,12 +546,14 @@ static bool progs_nextline(char **out, size_t *alen,FILE *src) {
|
|||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
size_t itr;
|
||||
int retval = 0;
|
||||
bool opts_output_free = false;
|
||||
bool operators_free = false;
|
||||
bool progs_src = false;
|
||||
FILE *outfile = NULL;
|
||||
size_t itr;
|
||||
int retval = 0;
|
||||
bool opts_output_free = false;
|
||||
bool operators_free = false;
|
||||
bool progs_src = false;
|
||||
FILE *outfile = NULL;
|
||||
struct parser_s *parser = NULL;
|
||||
struct ftepp_s *ftepp = NULL;
|
||||
|
||||
app_name = argv[0];
|
||||
con_init ();
|
||||
|
@ -621,7 +628,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
||||
if (!parser_init()) {
|
||||
if (!(parser = parser_create())) {
|
||||
con_err("failed to initialize parser\n");
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
|
@ -629,7 +636,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
|
||||
if (!ftepp_init()) {
|
||||
if (!(ftepp = ftepp_create())) {
|
||||
con_err("failed to initialize parser\n");
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
|
@ -644,7 +651,7 @@ int main(int argc, char **argv) {
|
|||
/* add macros */
|
||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
|
||||
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);
|
||||
|
||||
/* can be null */
|
||||
|
@ -703,6 +710,7 @@ srcdone:
|
|||
con_out("Mode: %s\n", (progs_src ? "progs.src" : "manual"));
|
||||
con_out("There are %lu items to compile:\n", (unsigned long)vec_size(items));
|
||||
}
|
||||
|
||||
for (itr = 0; itr < vec_size(items); ++itr) {
|
||||
if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
|
||||
!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
|
||||
|
@ -717,33 +725,33 @@ srcdone:
|
|||
|
||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
||||
const char *out;
|
||||
if (!ftepp_preprocess_file(items[itr].filename)) {
|
||||
if (!ftepp_preprocess_file(ftepp, items[itr].filename)) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
out = ftepp_get();
|
||||
out = ftepp_get(ftepp);
|
||||
if (out)
|
||||
fs_file_printf(outfile, "%s", out);
|
||||
ftepp_flush();
|
||||
ftepp_flush(ftepp);
|
||||
}
|
||||
else {
|
||||
if (OPTS_FLAG(FTEPP)) {
|
||||
const char *data;
|
||||
if (!ftepp_preprocess_file(items[itr].filename)) {
|
||||
if (!ftepp_preprocess_file(ftepp, items[itr].filename)) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
data = ftepp_get();
|
||||
data = ftepp_get(ftepp);
|
||||
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;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
ftepp_flush();
|
||||
ftepp_flush(ftepp);
|
||||
}
|
||||
else {
|
||||
if (!parser_compile_file(items[itr].filename)) {
|
||||
if (!parser_compile_file(parser, items[itr].filename)) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -756,9 +764,10 @@ srcdone:
|
|||
}
|
||||
}
|
||||
|
||||
ftepp_finish();
|
||||
ftepp_finish(ftepp);
|
||||
ftepp = NULL;
|
||||
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;
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -778,13 +787,14 @@ srcdone:
|
|||
|
||||
cleanup:
|
||||
util_debug("COM", "cleaning ...\n");
|
||||
ftepp_finish();
|
||||
if (ftepp)
|
||||
ftepp_finish(ftepp);
|
||||
con_close();
|
||||
vec_free(items);
|
||||
vec_free(ppems);
|
||||
|
||||
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
|
||||
parser_cleanup();
|
||||
parser_cleanup(parser);
|
||||
if (opts_output_free)
|
||||
mem_d(OPTS_OPTION_STR(OPTION_OUTPUT));
|
||||
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, LEGACY_VECTOR_MATHS, true);
|
||||
opts_set(opts.flags, DARKPLACES_STRING_TABLE_BUG, true);
|
||||
|
||||
}
|
||||
|
||||
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_U32(OPTION_STANDARD) = standard;
|
||||
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) {
|
||||
|
@ -257,7 +259,7 @@ static size_t opts_ini_parse (
|
|||
static bool opts_ini_bool(const char *value) {
|
||||
if (!strcmp(value, "true")) return true;
|
||||
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) {
|
||||
|
|
1
opts.def
1
opts.def
|
@ -109,6 +109,7 @@
|
|||
GMQCC_DEFINE_FLAG(G)
|
||||
GMQCC_DEFINE_FLAG(STANDARD)
|
||||
GMQCC_DEFINE_FLAG(DEBUG)
|
||||
GMQCC_DEFINE_FLAG(MEMDUMPCOLS)
|
||||
GMQCC_DEFINE_FLAG(MEMCHK)
|
||||
GMQCC_DEFINE_FLAG(DUMPFIN)
|
||||
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.
|
||||
*/
|
||||
bool pak_extract_one(pak_file_t *pak, const char *file) {
|
||||
pak_directory_t *dir = NULL;
|
||||
unsigned char *dat = NULL;
|
||||
bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) {
|
||||
pak_directory_t *dir = NULL;
|
||||
unsigned char *dat = NULL;
|
||||
char *local = NULL;
|
||||
FILE *out;
|
||||
|
||||
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);
|
||||
|
||||
/* TODO portable path seperators */
|
||||
util_asprintf(&local, "%s/%s", outdir, file);
|
||||
|
||||
/*
|
||||
* Now create the file, if this operation fails. Then abort
|
||||
* It shouldn't fail though.
|
||||
*/
|
||||
if (!(out = fs_file_open(file, "wb"))) {
|
||||
if (!(out = fs_file_open(local, "wb"))) {
|
||||
mem_d(dat);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* free memory for directory string */
|
||||
mem_d(local);
|
||||
|
||||
/* read */
|
||||
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))
|
||||
return false;
|
||||
|
||||
if (fs_dir_change(dir))
|
||||
return false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -361,7 +364,7 @@ bool pak_insert_one(pak_file_t *pak, const char *file) {
|
|||
return false;
|
||||
}
|
||||
|
||||
strcpy(dir.name, file);
|
||||
strncpy(dir.name, file, strlen(file));
|
||||
|
||||
/*
|
||||
* Allocate some memory for loading in the data that will be
|
||||
|
@ -477,7 +480,6 @@ int main(int argc, char **argv) {
|
|||
bool extract = true;
|
||||
char *redirout = (char*)stdout;
|
||||
char *redirerr = (char*)stderr;
|
||||
char *directory = NULL;
|
||||
char *file = NULL;
|
||||
char **files = NULL;
|
||||
pak_file_t *pak = NULL;
|
||||
|
@ -498,8 +500,6 @@ int main(int argc, char **argv) {
|
|||
continue;
|
||||
if (parsecmd("redirerr", &argc, &argv, &redirerr, 1, false))
|
||||
continue;
|
||||
if (parsecmd("directory", &argc, &argv, &directory, 1, false))
|
||||
continue;
|
||||
if (parsecmd("file", &argc, &argv, &file, 1, false))
|
||||
continue;
|
||||
|
||||
|
@ -542,7 +542,7 @@ int main(int argc, char **argv) {
|
|||
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);
|
||||
pak_close(pak);
|
||||
vec_free(files);
|
||||
|
@ -562,13 +562,6 @@ int main(int argc, char **argv) {
|
|||
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++) {
|
||||
if (!(pak_insert_one(pak, files[iter]))) {
|
||||
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 <stdarg.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "gmqcc.h"
|
||||
#include "lexer.h"
|
||||
|
@ -34,7 +35,7 @@
|
|||
#define PARSER_HT_SIZE 128
|
||||
#define TYPEDEF_HT_SIZE 16
|
||||
|
||||
typedef struct {
|
||||
typedef struct parser_s {
|
||||
lex_file *lex;
|
||||
int tok;
|
||||
|
||||
|
@ -46,6 +47,8 @@ typedef struct {
|
|||
ast_value **imm_vector;
|
||||
size_t translated;
|
||||
|
||||
ht ht_imm_string;
|
||||
|
||||
/* must be deleted first, they reference immediates and values */
|
||||
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)
|
||||
{
|
||||
size_t i;
|
||||
size_t hash = util_hthash(parser->ht_imm_string, str);
|
||||
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) {
|
||||
if (!strcmp(parser->imm_string[i]->constval.vstring, str))
|
||||
return parser->imm_string[i];
|
||||
}
|
||||
*/
|
||||
if (dotranslate) {
|
||||
char name[32];
|
||||
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->constval.vstring = parser_strdup(str);
|
||||
vec_push(parser->imm_string, out);
|
||||
util_htseth(parser->ht_imm_string, str, hash, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -379,6 +393,9 @@ static ast_value* parser_find_typedef(parser_t *parser, const char *name, size_t
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* include intrinsics */
|
||||
#include "intrin.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
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('%','='):
|
||||
compile_error(ctx, "qc does not have a modulo operator");
|
||||
compile_error(ctx, "%= is unimplemented");
|
||||
return false;
|
||||
|
||||
case opid1('|'):
|
||||
case opid1('&'):
|
||||
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]);
|
||||
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 */
|
||||
if (NotSameType(TYPE_FLOAT)) {
|
||||
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]))
|
||||
out = (ast_expression*)parser_const_float(parser, ~(qcint)ConstF(0));
|
||||
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;
|
||||
}
|
||||
#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")) {
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
bool flag = false;
|
||||
bool reverse = false;
|
||||
qcfloat num = 0;
|
||||
ast_value **values = NULL;
|
||||
ast_value *var = NULL;
|
||||
|
@ -3661,11 +3735,37 @@ static bool parse_enum(parser_t *parser)
|
|||
|
||||
ast_expression *old;
|
||||
|
||||
if (!parser_next(parser) || parser->tok != '{') {
|
||||
parseerror(parser, "expected `{` after `enum` keyword");
|
||||
if (!parser_next(parser) || (parser->tok != '{' && parser->tok != ':')) {
|
||||
parseerror(parser, "expected `{` or `:` after `enum` keyword");
|
||||
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) {
|
||||
if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
|
||||
if (parser->tok == '}') {
|
||||
|
@ -3689,8 +3789,9 @@ static bool parse_enum(parser_t *parser)
|
|||
vec_push(values, var);
|
||||
var->cvq = CV_CONST;
|
||||
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);
|
||||
|
||||
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 != '}') {
|
||||
parseerror(parser, "internal error: breaking without `}`");
|
||||
goto onerror;
|
||||
|
@ -4696,6 +4804,8 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
|
|||
on_error:
|
||||
if (argcounter)
|
||||
mem_d(argcounter);
|
||||
if (varparam)
|
||||
ast_delete(varparam);
|
||||
ast_delete(var);
|
||||
for (i = 0; i < vec_size(params); ++i)
|
||||
ast_delete(params[i]);
|
||||
|
@ -5814,16 +5924,15 @@ static void generate_checksum(parser_t *parser)
|
|||
code_crc = crc;
|
||||
}
|
||||
|
||||
static parser_t *parser;
|
||||
|
||||
bool parser_init()
|
||||
parser_t *parser_create()
|
||||
{
|
||||
parser_t *parser;
|
||||
lex_ctx empty_ctx;
|
||||
size_t i;
|
||||
|
||||
parser = (parser_t*)mem_a(sizeof(parser_t));
|
||||
if (!parser)
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
memset(parser, 0, sizeof(*parser));
|
||||
|
||||
|
@ -5836,7 +5945,7 @@ bool parser_init()
|
|||
if (!parser->assign_op) {
|
||||
printf("internal error: initializing parser: failed to find assign operator\n");
|
||||
mem_d(parser);
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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->ht_imm_string = util_htnew(512);
|
||||
|
||||
/* corrector */
|
||||
vec_push(parser->correct_variables, correct_trie_new());
|
||||
vec_push(parser->correct_variables_score, NULL);
|
||||
|
@ -5872,10 +5983,11 @@ bool parser_init()
|
|||
} else {
|
||||
parser->reserved_version = NULL;
|
||||
}
|
||||
return true;
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
bool parser_compile()
|
||||
bool parser_compile(parser_t *parser)
|
||||
{
|
||||
/* initial lexer/parser state */
|
||||
parser->lex->flags.noops = true;
|
||||
|
@ -5907,27 +6019,27 @@ bool parser_compile()
|
|||
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);
|
||||
if (!parser->lex) {
|
||||
con_err("failed to open file \"%s\"\n", filename);
|
||||
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);
|
||||
if (!parser->lex) {
|
||||
con_err("failed to create lexer for string \"%s\"\n", name);
|
||||
return false;
|
||||
}
|
||||
return parser_compile();
|
||||
return parser_compile(parser);
|
||||
}
|
||||
|
||||
void parser_cleanup()
|
||||
void parser_cleanup(parser_t *parser)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < vec_size(parser->accessors); ++i) {
|
||||
|
@ -5957,6 +6069,7 @@ void parser_cleanup()
|
|||
vec_free(parser->functions);
|
||||
vec_free(parser->imm_vector);
|
||||
vec_free(parser->imm_string);
|
||||
util_htdel(parser->ht_imm_string);
|
||||
vec_free(parser->imm_float);
|
||||
vec_free(parser->globals);
|
||||
vec_free(parser->fields);
|
||||
|
@ -5998,10 +6111,12 @@ void parser_cleanup()
|
|||
|
||||
util_htdel(parser->aliases);
|
||||
|
||||
intrin_intrinsics_destroy(parser);
|
||||
|
||||
mem_d(parser);
|
||||
}
|
||||
|
||||
bool parser_finish(const char *output)
|
||||
bool parser_finish(parser_t *parser, const char *output)
|
||||
{
|
||||
size_t i;
|
||||
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 */
|
||||
|
||||
#define TASK_COMPILE 0
|
||||
#define TASK_EXECUTE 1
|
||||
#define TASK_COMPILE 0
|
||||
#define TASK_EXECUTE 1
|
||||
/*
|
||||
* Task template system:
|
||||
* 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) {
|
||||
size_t desclen = 0;
|
||||
size_t filelen = 0;
|
||||
char **destval = NULL;
|
||||
|
||||
if (!tmpl)
|
||||
|
@ -315,7 +316,7 @@ bool task_template_generate(task_template_t *tmpl, char tag, const char *file, s
|
|||
if (strchr(value, '\n'))
|
||||
*strrchr(value, '\n')='\0';
|
||||
else /* cppcheck: possible nullpointer dereference */
|
||||
abort();
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
if ((filelen = strlen(file)) > pad[2])
|
||||
pad[2] = filelen;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -428,7 +432,7 @@ bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size
|
|||
if (strrchr(value, '\n'))
|
||||
*strrchr(value, '\n')='\0';
|
||||
else /* cppcheck: possible null pointer dereference */
|
||||
abort();
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
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);
|
||||
if (tmpl->comparematch)
|
||||
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 {
|
||||
con_err("template compile error: %s invalid procedure type: %s\n", file, tmpl->proceduretype);
|
||||
goto failure;
|
||||
|
@ -644,10 +654,10 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
|||
char buffer[4096];
|
||||
size_t found = 0;
|
||||
|
||||
dir = opendir(curdir);
|
||||
dir = fs_dir_open(curdir);
|
||||
|
||||
while ((files = readdir(dir))) {
|
||||
snprintf(buffer, sizeof(buffer), "%s/%s", curdir, files->d_name);
|
||||
while ((files = fs_dir_read(dir))) {
|
||||
snprintf(buffer, sizeof(buffer), "%s/%s", curdir, files->d_name);
|
||||
|
||||
if (stat(buffer, &directory) == -1) {
|
||||
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
|
||||
* 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
|
||||
|
@ -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
|
||||
* reading the data from the pipe.
|
||||
*/
|
||||
if (qcflags) {
|
||||
if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
|
||||
snprintf(buf, sizeof(buf), "%s %s/%s %s %s -o %s",
|
||||
task_bins[TASK_COMPILE],
|
||||
curdir,
|
||||
tmpl->sourcefile,
|
||||
qcflags,
|
||||
tmpl->compileflags,
|
||||
tmpl->tempfilename
|
||||
);
|
||||
if (strcmp(tmpl->proceduretype, "-pp")) {
|
||||
if (qcflags) {
|
||||
if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
|
||||
snprintf(buf, sizeof(buf), "%s %s/%s %s %s -o %s",
|
||||
task_bins[TASK_COMPILE],
|
||||
curdir,
|
||||
tmpl->sourcefile,
|
||||
qcflags,
|
||||
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 {
|
||||
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
|
||||
);
|
||||
if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
|
||||
snprintf(buf, sizeof(buf), "%s %s/%s %s -o %s",
|
||||
task_bins[TASK_COMPILE],
|
||||
curdir,
|
||||
tmpl->sourcefile,
|
||||
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 {
|
||||
/* Preprocessing (qcflags mean shit all here we don't allow them) */
|
||||
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],
|
||||
curdir,
|
||||
tmpl->sourcefile,
|
||||
tmpl->compileflags,
|
||||
tmpl->tempfilename
|
||||
);
|
||||
} 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],
|
||||
curdir,
|
||||
defs,
|
||||
curdir,
|
||||
tmpl->sourcefile,
|
||||
tmpl->compileflags,
|
||||
tmpl->tempfilename
|
||||
);
|
||||
}
|
||||
|
@ -777,7 +809,7 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
|||
found
|
||||
);
|
||||
|
||||
closedir(dir);
|
||||
fs_dir_close(dir);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@ -790,9 +822,9 @@ void task_precleanup(const char *curdir) {
|
|||
struct dirent *files;
|
||||
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") ||
|
||||
strstr(files->d_name, ".stdout") ||
|
||||
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) {
|
||||
|
@ -854,40 +886,50 @@ void task_destroy(void) {
|
|||
/*
|
||||
* This executes the QCVM task for a specificly compiled progs.dat
|
||||
* 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;
|
||||
FILE *execute;
|
||||
char buffer[4096];
|
||||
memset (buffer,0,sizeof(buffer));
|
||||
|
||||
/*
|
||||
* Drop the execution flags for the QCVM if none where
|
||||
* actually specified.
|
||||
*/
|
||||
if (!strcmp(tmpl->executeflags, "$null")) {
|
||||
snprintf(buffer, sizeof(buffer), "%s %s",
|
||||
task_bins[TASK_EXECUTE],
|
||||
tmpl->tempfilename
|
||||
if (strcmp(tmpl->proceduretype, "-pp")) {
|
||||
/*
|
||||
* Drop the execution flags for the QCVM if none where
|
||||
* actually specified.
|
||||
*/
|
||||
if (!strcmp(tmpl->executeflags, "$null")) {
|
||||
snprintf(buffer, sizeof(buffer), "%s %s",
|
||||
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 {
|
||||
snprintf(buffer, sizeof(buffer), "%s %s %s",
|
||||
task_bins[TASK_EXECUTE],
|
||||
tmpl->executeflags,
|
||||
tmpl->tempfilename
|
||||
);
|
||||
/*
|
||||
* we're preprocessing, which means we need to read int
|
||||
* the produced file and do some really weird shit.
|
||||
*/
|
||||
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
|
||||
* and handle accordingly.
|
||||
|
@ -913,6 +955,13 @@ bool task_execute(task_template_t *tmpl, char ***line) {
|
|||
if (strrchr(data, '\n'))
|
||||
*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 (strcmp(data, tmpl->comparematch[compare++]))
|
||||
success = false;
|
||||
|
@ -933,10 +982,25 @@ bool task_execute(task_template_t *tmpl, char ***line) {
|
|||
mem_d(data);
|
||||
data = NULL;
|
||||
}
|
||||
pclose(execute);
|
||||
|
||||
if (strcmp(tmpl->proceduretype, "-pp"))
|
||||
pclose(execute);
|
||||
else
|
||||
fs_file_close(execute);
|
||||
|
||||
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 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>
|
||||
void task_schedualize(size_t *pad) {
|
||||
char space[2][64];
|
||||
bool execute = false;
|
||||
char *data = NULL;
|
||||
char **match = NULL;
|
||||
|
@ -952,15 +1017,21 @@ void task_schedualize(size_t *pad) {
|
|||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
|
||||
snprintf(space[0], sizeof(space[0]), "%d", (int)vec_size(task_tasks));
|
||||
|
||||
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);
|
||||
/*
|
||||
* Generate a task from thin air if it requires execution in
|
||||
* 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
|
||||
|
@ -979,8 +1050,6 @@ void task_schedualize(size_t *pad) {
|
|||
task_tasks[i].compiled = false;
|
||||
execute = false;
|
||||
}
|
||||
|
||||
fs_file_flush(task_tasks[i].stdoutlog);
|
||||
}
|
||||
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_flush(task_tasks[i].stdoutlog);
|
||||
}
|
||||
|
||||
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->tempfilename,
|
||||
task_tasks[i].tmpl->tempfilename,
|
||||
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("(failed to compile)") - pad[2]),
|
||||
"(failed to compile)"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!execute) {
|
||||
con_out("succeeded: `%s` %*s\n",
|
||||
con_out("succeeded: `%s` %*s %*s\n",
|
||||
task_tasks[i].tmpl->description,
|
||||
(pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) +
|
||||
(strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
|
||||
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(task_type(task_tasks[i].tmpl)) - pad[2]),
|
||||
task_type(task_tasks[i].tmpl)
|
||||
|
||||
);
|
||||
continue;
|
||||
|
@ -1023,14 +1093,24 @@ void task_schedualize(size_t *pad) {
|
|||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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->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
|
||||
* 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(match)
|
||||
);
|
||||
|
@ -1046,10 +1126,10 @@ void task_schedualize(size_t *pad) {
|
|||
char *select = task_tasks[i].tmpl->comparematch[d];
|
||||
size_t length = 40 - strlen(select);
|
||||
|
||||
con_err(" Expected: \"%s\"", select);
|
||||
con_out(" Expected: \"%s\"", select);
|
||||
while (length --)
|
||||
con_err(" ");
|
||||
con_err("| Got: \"%s\"\n", (d >= vec_size(match)) ? "<<nothing else to compare>>" : match[d]);
|
||||
con_out(" ");
|
||||
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)) {
|
||||
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)]
|
||||
);
|
||||
}
|
||||
|
@ -1075,11 +1155,12 @@ void task_schedualize(size_t *pad) {
|
|||
mem_d(match[j]);
|
||||
vec_free(match);
|
||||
|
||||
con_out("succeeded: `%s` %*s\n",
|
||||
con_out("succeeded: `%s` %*s %*s\n",
|
||||
task_tasks[i].tmpl->description,
|
||||
(pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) +
|
||||
(strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
|
||||
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(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";
|
||||
|
||||
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;
|
||||
vector (vector) normalize = #12;
|
||||
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
|
||||
// we support it.
|
||||
__ = (__ - 1),
|
||||
|
@ -27,6 +27,20 @@ enum {
|
|||
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() {
|
||||
print(ftos(A), "\n");
|
||||
print(ftos(B), "\n");
|
||||
|
@ -42,4 +56,13 @@ void main() {
|
|||
print(ftos(L), "\n");
|
||||
print(ftos(M), "\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: 12
|
||||
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
|
||||
D: catch another case of unused vector accesses - should fail
|
||||
D: catch another case of unused vector accesses
|
||||
T: -fail
|
||||
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))
|
||||
ch = 0;
|
||||
if (_end)
|
||||
else if (_end)
|
||||
*_end = _s + st + ln;
|
||||
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))
|
||||
ch = 0;
|
||||
if (_end)
|
||||
else if (_end)
|
||||
*_end = _s + st + ln;
|
||||
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_at = 0;
|
||||
uint64_t mem_dt = 0;
|
||||
uint64_t mem_pk = 0;
|
||||
uint64_t mem_hw = 0;
|
||||
|
||||
struct memblock_t {
|
||||
const char *file;
|
||||
|
@ -39,6 +41,12 @@ struct memblock_t {
|
|||
struct memblock_t *prev;
|
||||
};
|
||||
|
||||
#define PEAK_MEM \
|
||||
do { \
|
||||
if (mem_hw > mem_pk) \
|
||||
mem_pk = mem_hw; \
|
||||
} while (0)
|
||||
|
||||
static struct memblock_t *mem_start = NULL;
|
||||
|
||||
void *util_memory_a(size_t byte, unsigned int line, const char *file) {
|
||||
|
@ -56,6 +64,9 @@ void *util_memory_a(size_t byte, unsigned int line, const char *file) {
|
|||
|
||||
mem_at++;
|
||||
mem_ab += info->byte;
|
||||
mem_hw += info->byte;
|
||||
|
||||
PEAK_MEM;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -67,6 +78,7 @@ void util_memory_d(void *ptrn) {
|
|||
info = ((struct memblock_t*)ptrn - 1);
|
||||
|
||||
mem_db += info->byte;
|
||||
mem_hw -= info->byte;
|
||||
mem_dt++;
|
||||
|
||||
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_ab -= oldinfo->byte;
|
||||
mem_hw -= oldinfo->byte;
|
||||
mem_ab += newinfo->byte;
|
||||
mem_hw += newinfo->byte;
|
||||
|
||||
PEAK_MEM;
|
||||
|
||||
free(oldinfo);
|
||||
|
||||
return newinfo+1;
|
||||
}
|
||||
|
||||
static void util_dumpmem(struct memblock_t *memory, uint16_t cols) {
|
||||
uint32_t i, j;
|
||||
for (i = 0; i < memory->byte + ((memory->byte % cols) ? (cols - memory->byte % cols) : 0); i++) {
|
||||
if (i % cols == 0) con_out(" 0x%06X: ", i);
|
||||
if (i < memory->byte) con_out("%02X " , 0xFF & ((char*)(memory + 1))[i]);
|
||||
else con_out(" ");
|
||||
|
||||
if ((uint16_t)(i % cols) == (cols - 1)) {
|
||||
for (j = i - (cols - 1); j <= i; j++) {
|
||||
con_out("%c",
|
||||
(j >= memory->byte)
|
||||
? ' '
|
||||
: (isprint(((char*)(memory + 1))[j]))
|
||||
? 0xFF & ((char*)(memory + 1)) [j]
|
||||
: '.'
|
||||
);
|
||||
}
|
||||
con_out("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void util_meminfo() {
|
||||
struct memblock_t *info;
|
||||
|
||||
if (!OPTS_OPTION_BOOL(OPTION_MEMCHK))
|
||||
return;
|
||||
|
||||
for (info = mem_start; info; info = info->next) {
|
||||
util_debug("MEM", "lost: % 8u (bytes) at %s:%u\n",
|
||||
info->byte,
|
||||
info->file,
|
||||
info->line);
|
||||
if (OPTS_OPTION_BOOL(OPTION_DEBUG)) {
|
||||
for (info = mem_start; info; info = info->next) {
|
||||
con_out("lost: %u (bytes) at %s:%u\n",
|
||||
info->byte,
|
||||
info->file,
|
||||
info->line);
|
||||
|
||||
util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS));
|
||||
}
|
||||
}
|
||||
|
||||
util_debug("MEM", "Memory information:\n\
|
||||
Total allocations: %llu\n\
|
||||
Total deallocations: %llu\n\
|
||||
Total allocated: %llu (bytes)\n\
|
||||
Total deallocated: %llu (bytes)\n\
|
||||
Leaks found: lost %llu (bytes) in %d allocations\n",
|
||||
mem_at, mem_dt,
|
||||
mem_ab, mem_db,
|
||||
(mem_ab - mem_db),
|
||||
(mem_at - mem_dt)
|
||||
);
|
||||
if (OPTS_OPTION_BOOL(OPTION_DEBUG) ||
|
||||
OPTS_OPTION_BOOL(OPTION_MEMCHK)) {
|
||||
con_out("Memory information:\n\
|
||||
Total allocations: %llu\n\
|
||||
Total deallocations: %llu\n\
|
||||
Total allocated: %f (MB)\n\
|
||||
Total deallocated: %f (MB)\n\
|
||||
Total peak memory: %f (MB)\n\
|
||||
Total leaked memory: %f (MB) in %llu allocations\n",
|
||||
mem_at,
|
||||
mem_dt,
|
||||
(float)(mem_ab) / 1048576.0f,
|
||||
(float)(mem_db) / 1048576.0f,
|
||||
(float)(mem_pk) / 1048576.0f,
|
||||
(float)(mem_ab - mem_db) / 1048576.0f,
|
||||
|
||||
/* could be more clever */
|
||||
(mem_at - mem_dt)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some string utility functions, because strdup uses malloc, and we want
|
||||
* 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;
|
||||
char *ptr = NULL;
|
||||
|
||||
/* in case of -DNOTRACK */
|
||||
(void)file;
|
||||
(void)line;
|
||||
|
||||
if (!s)
|
||||
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);
|
||||
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);
|
||||
return;
|
||||
|
||||
default: abort(); /* please blow the fuck up! */
|
||||
default: exit(EXIT_FAILURE); /* please blow the fuck up! */
|
||||
}
|
||||
# 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))))
|
||||
return NULL;
|
||||
|
||||
if (!(node->key = util_strdup(key))) {
|
||||
if (!(node->key = util_strdupe(key))) {
|
||||
mem_d(node);
|
||||
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
|
||||
* of work.
|
||||
*/
|
||||
void util_htdel(hash_table_t *ht) {
|
||||
void util_htrem(hash_table_t *ht, void (*callback)(void *data)) {
|
||||
size_t i = 0;
|
||||
for (; i < ht->size; i++) {
|
||||
hash_node_t *n = ht->table[i];
|
||||
|
@ -558,6 +630,8 @@ void util_htdel(hash_table_t *ht) {
|
|||
while (n) {
|
||||
if (n->key)
|
||||
mem_d(n->key);
|
||||
if (callback)
|
||||
callback(n->value);
|
||||
p = n;
|
||||
n = n->next;
|
||||
mem_d(p);
|
||||
|
@ -569,146 +643,33 @@ void util_htdel(hash_table_t *ht) {
|
|||
mem_d(ht);
|
||||
}
|
||||
|
||||
/*
|
||||
* A basic implementation of a hash-set. Unlike a hashtable, a hash
|
||||
* set doesn't maintain key-value pairs. It simply maintains a key
|
||||
* that can be set, removed, and checked for.
|
||||
*
|
||||
* See EXPOSED interface comment below
|
||||
*/
|
||||
#define GMQCC_HASHSET_PRIME0 0x0049
|
||||
#define GMQCC_HASHSET_PRIME1 0x1391
|
||||
void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) {
|
||||
hash_node_t **pair = &ht->table[bin];
|
||||
hash_node_t *tmp;
|
||||
|
||||
static int util_hsput(hash_set_t *set, void *item) {
|
||||
size_t hash = (size_t)item; /* shouldn't drop the bits */
|
||||
size_t iter;
|
||||
while (*pair && (*pair)->key && strcmp(key, (*pair)->key) > 0)
|
||||
pair = &(*pair)->next;
|
||||
|
||||
/* a == 0 || a == 1 */
|
||||
if (hash >> 1)
|
||||
return -1;
|
||||
tmp = *pair;
|
||||
if (!tmp || !tmp->key || strcmp(key, tmp->key) != 0)
|
||||
return;
|
||||
|
||||
iter = set->mask & (GMQCC_HASHSET_PRIME0 * hash);
|
||||
if (cb)
|
||||
(*cb)(tmp->value);
|
||||
|
||||
/* while (set->items[iter] != 0 && set->items[iter] != 1) */
|
||||
while (!(set->items[iter] >> 1)) {
|
||||
if (set->items[iter] == hash)
|
||||
return 0;
|
||||
|
||||
iter = set->mask & (iter + GMQCC_HASHSET_PRIME1);
|
||||
}
|
||||
|
||||
set->total ++;
|
||||
set->items[iter] = hash;
|
||||
|
||||
return 1;
|
||||
*pair = tmp->next;
|
||||
mem_d(tmp->key);
|
||||
mem_d(tmp);
|
||||
}
|
||||
|
||||
static void util_hsupdate(hash_set_t *set) {
|
||||
size_t *old;
|
||||
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_htrm(hash_table_t *ht, const char *key, void (*cb)(void*)) {
|
||||
util_htrmh(ht, key, util_hthash(ht, key), cb);
|
||||
}
|
||||
|
||||
/*
|
||||
* EXPOSED interface: all of these functions are exposed to the outside
|
||||
* 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;
|
||||
void util_htdel(hash_table_t *ht) {
|
||||
util_htrem(ht, NULL);
|
||||
}
|
||||
|
||||
/* 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
|
||||
* exists, otherwise compiler error.
|
||||
|
|
Loading…
Reference in a new issue