Compare commits

...

816 commits

Author SHA1 Message Date
Dale Weiler
297eab9e5e reset framevalue on includes like fteqcc 2021-07-09 14:05:01 -04:00
Dale Weiler
da63ad7e07 fix -fsort-operands 2021-07-09 14:04:28 -04:00
Dale Weiler
ddcae703e3 allow dots in frame names to compile hypnotic 2021-07-09 12:17:02 -04:00
Dale Weiler
6cf25c0ec6 allow comparing explicitly against nil 2021-07-07 23:11:17 -04:00
Dale Weiler
663723f00a fixed mixing of old and new framemacro syntax 2021-07-07 22:58:13 -04:00
Dale Weiler
1e8ce1733b fix bug 197, 198, and 199 properly 2021-04-06 14:47:35 -04:00
Dale Weiler
47475bb455 fix bug #188 2021-03-27 20:45:40 -04:00
Dale Weiler
71138cbe1a rewrite dead code elimination for conditionals 2021-03-27 20:32:24 -04:00
Dale Weiler
85c79d2f1c fclose when fopen actually succeeds 2021-03-26 19:02:27 -04:00
Dale Weiler
13bcb5c5b1 set m_op as well when doing a-(-b) => a+b peephole 2021-03-26 18:57:31 -04:00
Dale Weiler
465941f357 pass parent scope to parse_statement_or_block
previous behavior when parsing a statement where a block is typically expected would fail to associate the statement with the parent block it's in, resulting in variable declarations ending up in global scope.

this fixes #197
2021-03-02 10:46:05 -05:00
Dale Weiler
237722c0b2 fix crash when cleaning up functions related to [[accumulate]] 2020-10-27 19:40:30 -04:00
Dale Weiler
f971f89e1e new makefile 2020-04-17 13:28:27 -04:00
Wolfgang Bumiller
94c2936bfa tests: xor peephole optimization regression test
Signed-off-by: Wolfgang Bumiller <wry.git@bumiller.com>
2019-09-15 10:27:26 +02:00
Wolfgang Bumiller
2d4a054440 ir: fix generation of multi-op vinstrs
Do not assume that the destination is a temporary location,
as our peephole optimizer will break this. For example, the
following IR code (generated via from `x ^= gety()`):

    (0) binst6 <- BITXOR   x,      call5
    (0) x <- STORE_F       binst6

after peephole optimization becomes:

    (7) x <- BITXOR        x,      call5

Therefore we cannot assume that the output of the virtual
xor instruction can be utilized as a temporary value.

BITXOR becomes `(x | y) - (x & y)`, which would wrongly be
generated as:
    x = x | y;
    temp0 = x & y;
    x = x - temp0;

While this particular case can be fixed by using temp0 first
and then x, the cross-product case would not be so simple.

Signed-off-by: Wolfgang Bumiller <wry.git@bumiller.com>
Fixes #190
2019-09-15 10:23:47 +02:00
Wolfgang Bumiller
031f827da5 introduce another vinstr temp
Some vinstrs are currently broken when using peephole
optimization as they appear as writing to a temporary ssa
output before being stored into their real destination,
causing the store to be optimized out, but the generated
code relies on having the destination as another temporary
value available.

Let's just add a 2nd temp to be used in those cases.

Signed-off-by: Wolfgang Bumiller <wry.git@bumiller.com>
2019-09-15 10:12:40 +02:00
Dale Weiler
451873ae52
Merge pull request #187 from divVerent/patch-1
Fix printing of floating poing values in -dumpfin.
2019-02-04 09:20:23 -05:00
divVerent
9c81ff263a
Fix printing of floating poing values in -dumpfin.
%g is not lossless for single precision floats - %.9g is (other than distinguishing NaNs, who cares).
2019-02-04 06:14:58 -08:00
Dale Weiler
620bd76e76 fix __builtin_nan and add some missing builtins 2018-11-14 08:43:22 -05:00
Dale Weiler
2d99ce609d fix octals 2018-10-30 17:32:21 -04:00
Dale Weiler
0904a1ceb7 fixes for progs.src 2018-09-01 00:48:18 -04:00
Dale Weiler
c74fabffda Merge branch 'master' of github.com:graphitemaster/gmqcc 2018-05-09 21:19:39 -04:00
Dale Weiler
092067482f added -fdefault-eraseable which is the same as adding [[eraseable]] to all definitions
instead the opposite behavior can be controlled with [[noerase]] attribute
2018-05-09 21:18:37 -04:00
Dale Weiler
dac058107a
Delete .travis.yml 2018-05-05 15:44:21 -04:00
Dale Weiler
9a21c638fa error if a function is called from global scope opposed to crashing 2018-05-05 15:38:12 -04:00
Wolfgang Bumiller
97a74eb677 catch broken vector member access
These kinds of expressions currently cannot be handled
without pionter support in the qcvm without scanning the
ast from within ast_member::codegen for an assignments as
seen in the added test case.

This change makes code like that return a pointer type which
will cause an error that we did not get a vector or field
back. With pointer support this pointer could actually be
used instead.

So at least it shouldn't silently produce broken code
anymore.

Signed-off-by: Wolfgang Bumiller <wry.git@bumiller.com>
2018-01-14 10:58:29 +01:00
Wolfgang Bumiller
f84c8ea629 add variable search order test
Signed-off-by: Wolfgang Bumiller <wry.git@bumiller.com>
2018-01-14 09:33:05 +01:00
Wolfgang Bumiller
e920766b10 Make parser_find_local only actually search locals
Fixes #163
Signed-off-by: Wolfgang Bumiller <wry.git@bumiller.com>
2018-01-14 09:33:05 +01:00
Wolfgang Bumiller
e006aa8238 Revert "search for funciton param first before function locals, this fixes #163"
This reverts commit 3cf2c52fce.
2018-01-14 09:33:05 +01:00
Dale Weiler
73d3d7eec1 fix some UB 2017-12-01 13:55:19 -05:00
Dale Weiler
3cf2c52fce search for funciton param first before function locals, this fixes #163 2017-12-01 12:24:50 -05:00
Dale Weiler
1580c23556 Merge branch 'master' of github.com:graphitemaster/gmqcc 2017-11-26 17:48:13 -05:00
Dale Weiler
b14a02e735 don't generate storep for vector field unless it's an ent field 2017-11-26 17:47:27 -05:00
Dale Weiler
679e3771de
Merge pull request #177 from xonotic/terencehill/warning_removal
Get rid of a warning on Windows
2017-11-26 17:30:42 -05:00
Dale Weiler
d9127bf28a
Merge pull request #180 from xonotic/mem_leak_fix_on_failure_paths
two small memory leak fixes on failure paths
2017-11-26 17:30:30 -05:00
Dale Weiler
fa7dce495b fix writing of globaldefs for vector subcomponents so that FTE field remapping works 2017-11-26 17:26:00 -05:00
Dale Weiler
02b20dbd09 fix member binops on entity fields to generate STOREP, this fixes stuff like ent.vec.x += value. 2017-11-26 17:09:38 -05:00
Wolfgang Bumiller
6ad5f18ef1 cleanup: 'move of a temporary object prevents copy elision' 2017-07-23 10:11:31 +02:00
Wolfgang Bumiller
047ecd426f move more parser code to c++, fix crashes with gcc
we initialized the parser with malloc -> memset to zero ->
placement new. With gcc the latter caused the memset to be
optimized out, causing uninitialized value accesses.
2017-07-23 10:11:31 +02:00
Wolfgang Bumiller
fb3af2831b cleanup some silly more warnings 2017-07-23 10:11:31 +02:00
Wolfgang Bumiller
5a0d645ede cleanup: silence fallthrough warnings 2017-07-23 10:11:31 +02:00
terencehill
27c0886ffb Get rid of a warning on Windows 2017-06-23 16:21:22 +02:00
Wolfgang Bumiller
163c4b99a4 tests: add check for vector negation 2017-06-22 08:45:38 +02:00
Wolfgang Bumiller
eb2d478770 qcvm: add stov builtin #16 2017-06-22 08:45:18 +02:00
Wolfgang Bumiller
3f5305af58 ir: fix vector negation using the nil value
We cannot use OFS_NULL as it is only a single value and
overlaps with OFS_RETURN.
2017-06-22 08:44:36 +02:00
David Carlier
8538658e83 two small memory leak fixes on failure paths 2017-05-23 21:56:03 +01:00
Wolfgang Bumiller
8b2149e315 sanitize: shift 1u (unsigned) for flag bits 2017-02-14 19:24:04 +01:00
Wolfgang Bumiller
c285eb385d c++: exec.cpp 2017-02-11 11:43:58 +01:00
Wolfgang Bumiller
2dde6d903e c++: ir_function::m_params 2016-12-03 21:42:15 +01:00
Wolfgang Bumiller
4bf63bb379 c++: ir: function_allocator 2016-12-03 21:39:09 +01:00
Wolfgang Bumiller
95d232ca72 c++: ir_block::m_instr 2016-12-03 21:30:33 +01:00
Wolfgang Bumiller
90f190f5e1 c++: ir_block::m_exits 2016-12-03 20:34:42 +01:00
Wolfgang Bumiller
566c17a964 c++: ir_block::m_entries 2016-12-03 20:32:26 +01:00
Dale Weiler
a5636899f2 Cleaner way to set the mask for -Wunused-component 2016-11-24 19:54:17 +00:00
Dale Weiler
17c0812ae4 Just mark LOCAL_RETURN noref instead of checking for '#' in the name 2016-11-24 15:50:48 +00:00
Dale Weiler
3a7848d67c Remove parser m_uses in favor of {IR,AST}_FLAG_NOREF instead 2016-11-24 15:33:58 +00:00
Dale Weiler
def1a26b12 Add -Wunused-component like -Wunused-variable but warns about unused components of vector 2016-11-24 14:52:57 +00:00
Dale Weiler
eab20602b1 more intelligent handling of unused vector fields 2016-11-24 14:44:28 +00:00
Dale Weiler
69fa4f8dbd Fix #158 2016-11-24 14:08:38 +00:00
Dale Weiler
966991601c Fix #161 2016-11-24 13:41:26 +00:00
Dale Weiler
01f3447e5b Fix #171 2016-11-24 13:40:22 +00:00
Dale Weiler
9821b6a075 Fix fieldfuncs test and track unused variables through writes as well. 2016-11-19 12:19:00 +00:00
Dale Weiler
6938567c6c Don't generate unused warnings for unused constants 2016-11-19 11:46:32 +00:00
Wolfgang Bumiller
0b94d7583c fix access to fields of vector members
When ast_member encounters the result of an ast_entfield it
has to replace the ast_entfield's codegen as we cannot
evaluate the field access first.

We then perform the same action as ast_entfield but call
vectorMember on the field before issuing the load/address
instruction.

This effectively turns the codegen of the following ast
structure:
    member_of {
        field_of {
            entity,
            a_vector
        }
        memberid
    }
into the one of this structure:
    field_of {
        entity,
        member_of {
            a_vector
            memberid
        }
    }
2016-11-19 16:22:18 +01:00
Wolfgang Bumiller
4c48bae203 Revert "Fix ent.vec.{x,y,z} writes"
This reverts commit ad1cfcfeaa.
2016-11-19 16:22:13 +01:00
Dale Weiler
ad1cfcfeaa Fix ent.vec.{x,y,z} writes 2016-11-19 10:42:33 +00:00
Dale Weiler
eca4e2c309 Unused globals even if they have an initial value should produce unused diagnostic 2016-11-19 10:05:58 +00:00
Dale Weiler
167207e98c Warning 2016-05-23 16:47:40 -04:00
Wolfgang Bumiller
e06ad170de update .gitignore 2016-02-10 19:01:12 +01:00
Dale Weiler
3714a507c2 Merge pull request #172 from TimePath/cmake
Add CMakeLists.txt
2016-01-03 01:15:18 -05:00
TimePath
63c679ee81 Add CMakeLists.txt 2016-01-03 17:14:02 +11:00
Dale Weiler
be64736dd4 Fixes 2016-01-03 00:38:58 -05:00
Dale Weiler
f6bc9705d2 eh 2016-01-03 00:35:12 -05:00
Dale Weiler
5d8c18dcab Fix makefile 2016-01-03 00:34:29 -05:00
Dale Weiler
1a18ff5294 Merge branch 'master' into cleanup 2016-01-02 22:30:35 -05:00
Dale Weiler
3f4659b5d5 oops 2015-12-28 08:00:54 -05:00
Dale Weiler
6024e377ba Fix unary negation (-) 2015-12-28 07:58:54 -05:00
Wolfgang Bumiller
ee3c1e43c9 tempcommitting a whole bunch of to-c++ conversions 2015-05-02 09:48:24 +02:00
Wolfgang Bumiller
a9ac6987a6 remove a bunch of unnecessary c-casts to ast_expression* 2015-02-01 12:15:30 +01:00
Wolfgang Bumiller
fab640da4c Merge branch 'cleanup' of git://github.com/graphitemaster/gmqcc into cleanup 2015-02-01 12:13:59 +01:00
Wolfgang Bumiller
fd0cc40b9c fix std::string constructed from nullptr 2015-02-01 12:13:22 +01:00
Wolfgang Bumiller
6d4539814e ast_unary::make: safer double-negation optimization check 2015-02-01 12:13:05 +01:00
Wolfgang Bumiller
896d4c53a3 fix backward propagateSideEffect impl 2015-02-01 12:12:40 +01:00
Wolfgang Bumiller
d8e9b1b35d destructor call order is important here 2015-02-01 11:52:58 +01:00
Wolfgang Bumiller
66d908f39b ir_instr_delete_quick needs to clear _m_ops 2015-02-01 11:49:46 +01:00
Wolfgang Bumiller
45236a644f ast conversion mostly finished 2015-02-01 11:44:00 +01:00
Dale Weiler
fa21d85820 Same on the cleanup branch 2015-01-30 00:46:25 -05:00
Dale Weiler
e922403aa8 Don't allocate globals for constants that aren't read 2015-01-30 00:40:59 -05:00
Dale Weiler
ff37abb0c7 Constant folding for strings 2015-01-30 00:25:10 -05:00
Dale Weiler
90b5a6538a Merge branch 'cleanup' of github.com:graphitemaster/gmqcc into cleanup 2015-01-30 00:20:41 -05:00
Dale Weiler
866fc3e247 Constant folding for string comparisons too 2015-01-30 00:18:52 -05:00
Dale Weiler
41a76ab91d Fix for loops 2015-01-29 23:33:59 -05:00
Dale Weiler
b640049912 For now 2015-01-29 23:13:55 -05:00
Wolfgang Bumiller
9335bc2f4f BROKEN: more ast nodes converted 2015-01-29 20:29:34 +01:00
Wolfgang Bumiller
49f4fedecf add another test that we just didn't have anywhere else yet 2015-01-25 09:29:02 +01:00
Wolfgang Bumiller
6149f6a1d0 BROKEN: in the middle of converting ast nodes to c++ with constructors and methods 2015-01-25 09:24:26 +01:00
Wolfgang Bumiller
9d98805dfb a whole lotta 'm_'s 2015-01-24 12:25:46 +01:00
Wolfgang Bumiller
e7d1e701c4 why didn't gcc catch that... 2015-01-24 10:26:43 +01:00
Wolfgang Bumiller
5c64437189 fix for loops 2015-01-20 20:55:27 +01:00
Wolfgang Bumiller
5968e3faa0 for now just call the dtors like this 2015-01-20 20:33:07 +01:00
Wolfgang Bumiller
566e761546 more c++ migration for ast/ir/code; reached a working condition here 2015-01-20 20:25:56 +01:00
Wolfgang Bumiller
f09c6a5d63 temp committing major c++ification 2015-01-20 16:43:58 +01:00
Wolfgang Bumiller
794396df79 making ast nodes derive from ast_expression 2015-01-19 14:00:04 +01:00
Wolfgang Bumiller
380fb3d44f this can be a move 2015-01-19 13:46:30 +01:00
Wolfgang Bumiller
dedb3a49bd ast_expression: params -> type_params 2015-01-19 13:46:10 +01:00
Wolfgang Bumiller
9535805c02 renaming ast_function::vtype to function_type 2015-01-19 13:37:22 +01:00
Wolfgang Bumiller
44b0d7f658 ast_expression now derives from ast_node 2015-01-19 13:33:39 +01:00
Wolfgang Bumiller
1826971301 renaming some ast_node members before making ast_expression an ast_node to use the compiler to help find possible clashes 2015-01-19 13:32:26 +01:00
Dale Weiler
db9c37d18b Rewrite constant folder in C++ 2015-01-15 20:27:17 -05:00
Dale Weiler
7e0e041527 Forgot about this file 2015-01-15 18:12:54 -05:00
Dale Weiler
e2ba77a546 Rewrite intrinsic system in C++ 2015-01-15 18:11:41 -05:00
Dale Weiler
76278e8b97 s/NULL/nullptr/ 2015-01-15 15:18:33 -05:00
Dale Weiler
6e68526680 Use std::vector for static_names 2015-01-15 15:15:35 -05:00
Dale Weiler
0ecfe18f49 Cleanup 2015-01-15 15:11:30 -05:00
Dale Weiler
e8fbae4b3e Not needed 2015-01-15 15:10:02 -05:00
Dale Weiler
f38e6b48db Use std::vector for SYA 2015-01-15 15:08:50 -05:00
Dale Weiler
a1f13499f9 Use std::vector for break and continue ast blocks 2015-01-15 14:22:22 -05:00
Dale Weiler
539dc4a3dc Use std::vector for ast switch cases 2015-01-15 14:19:07 -05:00
Dale Weiler
2e037832d3 Use std::vector for ast blocks 2015-01-15 14:15:44 -05:00
Dale Weiler
987f765c20 std::vector for initlist 2015-01-15 14:07:26 -05:00
Dale Weiler
b345b4e21b Eliminate use of vec_ in intrin.cpp 2015-01-15 03:01:26 -05:00
Dale Weiler
9c31c53cc5 Eliminate use of vec_ in fold.c 2015-01-15 02:47:42 -05:00
Dale Weiler
fe95b28a35 More std::vector 2015-01-15 02:17:37 -05:00
Dale Weiler
317e0499f7 More std::vector 2015-01-15 01:57:40 -05:00
Dale Weiler
b5d8b44503 More std::vector 2015-01-15 01:35:56 -05:00
Dale Weiler
35a8c3c9af More std::vector migration 2015-01-15 01:22:21 -05:00
Dale Weiler
2e3b3569bf Stop using vec_* in testsuite code 2015-01-15 00:29:37 -05:00
Dale Weiler
878195bdec Use C++ naming for structures 2015-01-15 00:05:48 -05:00
Dale Weiler
aabefd1bfe Use C++ naming for structures 2015-01-14 23:56:52 -05:00
Dale Weiler
4de08db0e7 More std::vector migration 2015-01-14 23:45:00 -05:00
Dale Weiler
67a3c9b031 Initial movement to std::vector 2015-01-14 23:34:43 -05:00
Dale Weiler
d4deaa35ca Fast math is too fast for clang 2015-01-14 21:58:04 -05:00
Dale Weiler
51a7b8e6a7 Make travis update to newer compilers 2015-01-14 21:54:41 -05:00
Dale Weiler
65362d93aa .c -> .cpp 2015-01-14 21:48:47 -05:00
Dale Weiler
a7b45ea14d More cleanup 2015-01-13 21:46:52 -05:00
Dale Weiler
9d89a059aa More cleanup 2015-01-13 21:43:48 -05:00
Dale Weiler
dc510baf4f This is supposted in C99 2015-01-13 21:39:19 -05:00
Dale Weiler
b5ac2745d6 Remove license headers. The LICENSE file is sufficent 2015-01-13 21:38:40 -05:00
Dale Weiler
0a00807e57 More cleanup 2015-01-13 21:36:09 -05:00
Dale Weiler
ff526954b6 Minifi README 2015-01-13 21:30:23 -05:00
Dale Weiler
42b3640bc5 Remove these too 2015-01-13 21:29:09 -05:00
Dale Weiler
6caaedd269 Remove msvc project files and misc stuff 2015-01-13 21:28:26 -05:00
Dale Weiler
8b250457ab Remove hash.c 2015-01-13 21:27:36 -05:00
Dale Weiler
644a807731 Remove all the support stuff 2015-01-13 21:26:44 -05:00
Dale Weiler
724bca0eec Remove fs.c ansi.c and PORTING guide 2015-01-13 21:25:17 -05:00
Dale Weiler
2c421c3b71 Major cleanup of platform/fs stuff 2015-01-13 21:18:47 -05:00
Dale Weiler
5b9e0a62ab Add qcvm rule to makefile 2015-01-13 20:36:25 -05:00
Dale Weiler
d6bf906647 Update travis file 2015-01-13 20:30:28 -05:00
Dale Weiler
1ad849d939 Include dependencies in the makefile 2015-01-13 20:29:46 -05:00
Dale Weiler
044f8b396d Linker flags after objects 2015-01-13 20:27:45 -05:00
Dale Weiler
893f204b30 Remove stat_info calls 2015-01-13 20:25:44 -05:00
Dale Weiler
486b215706 Remove memory tracker 2015-01-13 20:25:01 -05:00
Dale Weiler
d8c09c200a Simpler hash function 2015-01-13 20:10:44 -05:00
Dale Weiler
e452c176b4 Remove MSVC support code. Simplified makefile 2015-01-13 20:07:17 -05:00
Dale Weiler
833f315a16 Remove gmpak 2015-01-13 19:55:49 -05:00
Dale Weiler
a77797d6a6 Remove spelling corrector 2015-01-13 19:48:57 -05:00
Dale Weiler
783b7b6594 Update license headers 2015-01-09 14:53:35 -05:00
Dale Weiler
114a1d3b14 Fix variable declarations in for-loop initializers 2015-01-08 23:42:46 -05:00
Dale Weiler
6fee3ec363 More comments 2015-01-06 20:39:20 -05:00
Dale Weiler
2b10d588e4 grammar 2015-01-06 20:33:31 -05:00
Dale Weiler
e3577912c8 Fix the soft float implementation. Comment it as well. 2015-01-06 20:30:17 -05:00
Dale Weiler
ac8c7d730a Merge branch 'cooking'
Conflicts:
	test.c
2014-12-10 02:43:42 -05:00
Dale Weiler
5d5b9a379a When storing to a vector member as part of an entity field we must use STOREP 2014-12-10 02:40:35 -05:00
Dale Weiler
8f7242d314 Implement support for #include MACRO and #include __LINE__ 2014-11-07 03:12:34 -05:00
Dale Weiler
103e549615 Don't emit whitespace when stringifying TOKEN_WHITE.
Other aspects of the preprocessor already skip whitespace leading up to a token. The only situation in which a TOKEN_WHITE can
exist as part of the token stream during stringification, is when the whitespace is trailing after a token. This is situation is
really only possible in the context of a macro argument. This behaviour is inconsistent.

Consider the following
FOO( space_before)
FOO(space_after )

The former will reduce to "space_before" since the preprocessor will skip whitespace leading up to the token `space_before', while
the latter will reduce to "space_after ".

The C preprocessor doesn't preserve whitespace, so we won't either. This doesn't break any existing code.
2014-11-07 02:01:17 -05:00
Dale Weiler
ab841b94f7 Allow negation to propagate inexactness in constant folder by using neg(x) = x*-1 2014-11-04 14:32:56 -05:00
Wolfgang Bumiller
624e6201e8 manpage/init: -fsplit-vector-parameters description 2014-10-18 14:39:14 +02:00
Wolfgang Bumiller
8b25e95553 we like to spell things properly - if this commit message contains a typo I don't catch before pushing then that's totally intentional 2014-10-18 14:27:16 +02:00
Wolfgang Bumiller
ddb0b7dd9d ir_builder_imm_float: add IR_FLAG_ERASEABLE 2014-10-18 14:25:28 +02:00
Wolfgang Bumiller
806850e408 ir_builder_imm_float: mark them as const, otherwise they end up getting saved 2014-10-18 13:53:15 +02:00
Wolfgang Bumiller
09109bb176 split-vectors test 2014-10-18 13:51:25 +02:00
Wolfgang Bumiller
3df51c5979 adding -fsplit-vector-parameters, todo: float-lookup should get optimized as commented 2014-10-18 13:49:13 +02:00
Wolfgang Bumiller
2a00b386ba renaming the length operator to _length and fixing the lexing of that operator, generic names for operators is really a bad idea 2014-10-18 13:47:23 +02:00
Dale Weiler
15b31e7dc5 Support text type escape sequences \b and \s. 2014-10-17 19:37:01 -04:00
Dale Weiler
fa7d44e0c7 Converting a literal to null pointer produces a warning 2014-10-16 22:55:16 -04:00
Dale Weiler
859e9fe3da Fix tests 2014-09-29 03:38:08 -04:00
Dale Weiler
de22dec56b Some fixes 2014-09-28 20:28:56 -04:00
Dale Weiler
641136fee3 Make it a function 2014-09-27 04:50:50 -04:00
Dale Weiler
b08195e2da Implemented length operator. This closes #130 2014-09-27 04:15:32 -04:00
Dale Weiler
31cd263e33 Implement ini [includes] area like Trac. This closes #65 2014-09-27 02:32:02 -04:00
Dale Weiler
a502a5453f Make that unsigned 2014-09-27 01:52:33 -04:00
Dale Weiler
2208136403 Implement support for indirect macro expansions in the preprocessor. This closes #36 2014-09-27 01:48:03 -04:00
Dale Weiler
faacfa018a silly clang warning is silly 2014-09-26 19:58:32 -04:00
Dale Weiler
1a8bb31d2a Fix hash strlen properly instead of blindly disabling it 2014-09-26 19:53:50 -04:00
Wolfgang Bumiller
459356a48d accidentally left those in 2014-09-26 15:32:14 +02:00
Wolfgang Bumiller
beaba494b5 For now I'll just disable this 2014-09-26 15:25:33 +02:00
Wolfgang Bumiller
3e576bd1f3 hopefully sanitize field creation logic a bit 2014-09-26 15:08:49 +02:00
Dale Weiler
25caf4b8e8 Fix 2014-08-11 20:59:34 -04:00
Dale Weiler
d5690074e1 Set name for is_varargs too. 2014-07-31 13:13:43 -04:00
Dale Weiler
823b053e60 Fix T...name 2014-07-31 12:37:26 -04:00
Dale Weiler
4c1c1bc051 Remove debug info from parse error. 2014-07-31 00:44:42 -04:00
Dale Weiler
bca1a7143d Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2014-07-31 00:43:42 -04:00
Dale Weiler
161bbec262 Parameter omitting in fteqcc is disallowed. 2014-07-31 00:43:08 -04:00
Wolfgang Bumiller
3e43056f5f fixing wrong paths in the uninstall target 2014-06-15 11:05:16 +02:00
Dale Weiler
c33755b007 Handle encoding errors for platform_vasprintf 2014-05-28 21:51:29 -04:00
Dale Weiler
e7d81937ae Make it compile as C++ code. 2014-05-26 21:36:13 -04:00
Dale Weiler
53e9ed0d96 Merge branch 'arithmetic_exceptions' into cooking
Conflicts:
	doc/gmqcc.1
	gmqcc.ini.example
	opts.def
	parser.c
2014-05-25 03:01:47 -04:00
Dale Weiler
05b349c72f Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2014-05-25 02:56:40 -04:00
Dale Weiler
463426ad47 Some fixes 2014-05-25 02:27:02 -04:00
Dale Weiler
655c2482c9 Fix vec3_cross. Added optimization to Makefile since we've been compiling gmqcc without it since forever. 2014-05-25 02:04:10 -04:00
Dale Weiler
0c85bac71b More work on vector arithmetic exceptions. 2014-05-25 02:00:41 -04:00
Dale Weiler
aed893b6b8 More work for arithmetic exception on vectors. 2014-05-24 23:21:20 -04:00
Dale Weiler
337d7ddbf4 soft float state defaults. 2014-05-24 22:40:14 -04:00
Dale Weiler
ff80bf1aa2 Only when arithmetic exceptions are enabled. 2014-05-24 22:13:47 -04:00
Dale Weiler
1497191e3c Perliminary work in arithmetic exception handling for vector operations in constant evaluator / folder. 2014-05-24 22:12:05 -04:00
Dale Weiler
3945f26d92 Put this back in global scope, we have a local scope test 2014-05-24 20:36:09 -04:00
Dale Weiler
4fa694fe82 Some CLZ for other toolchains. 2014-05-24 20:33:57 -04:00
Wolfgang Bumiller
edb38ce70e local compile-time const values are now created as globals, thus they're now subject to constant-folding 2014-05-24 19:13:49 +02:00
Wolfgang Bumiller
536138273f propagate the 'inexact' flag on when initializing a constant 2014-05-24 17:53:29 +02:00
Dale Weiler
68c2baa7c1 Mage inexact travel across constants. 2014-05-24 11:50:16 -04:00
Dale Weiler
05e20bcdda Some things. Fix testsuite as well. One test will fail (inexact). 2014-05-24 11:42:10 -04:00
Wolfgang Bumiller
f1ab19ba0b this should be NULL 2014-05-24 17:15:25 +02:00
Wolfgang Bumiller
b7b60e7468 Merge branch 'master' into cooking 2014-05-24 17:13:05 +02:00
Dale Weiler
bbeb2517c0 Arithmetic exception flag and a plethora of tests. 2014-05-24 10:38:02 -04:00
Dale Weiler
2917d39ef1 Don't forget the BSDmakefile too. 2014-05-24 10:04:14 -04:00
Dale Weiler
cc20d7e4e9 Disable stupid clang warning. 2014-05-24 10:02:58 -04:00
Dale Weiler
5dc7e62b19 Use flags instead. 2014-05-24 09:59:43 -04:00
Dale Weiler
6424ebaf98 Perliminary work on arithmetic exception handling in the constant evaluator. We can safely check for arithmetic underflow, overflow, divison by zero and inexactness now. Inexactness of expressions are propagated through the AST such that using an inexact value in a comparison will trigger a warning with -Winexact-compares. 2014-05-24 09:53:38 -04:00
Dale Weiler
7024ebfe7f Merge branch 'master' into cooking 2014-05-13 23:22:25 -04:00
Dale Weiler
a371c4ee27 On platforms that the byte order check fails on the runtime test is concluded instead. It still needs these swap functions at compile time since the runtime test has to run. This fixes a FTBFS on BE selected ARMs. 2014-05-09 02:39:25 -04:00
Wolfgang Bumiller
ba0ac97372 add tests for INSTR_STATE and -femulate-state 2014-04-08 14:35:11 +02:00
Wolfgang Bumiller
8dafdfc5e2 use INSTR_STATE by default, add -femulate-state to switch to emulation, and -state-fps=NUM to set its emulation FPS 2014-04-08 14:34:55 +02:00
Wolfgang Bumiller
0d8b0d419c implement INSTR_STATE in the qcvm 2014-04-08 14:34:26 +02:00
Dale Weiler
0d1a740bc7 Fix style 2014-04-08 05:06:16 -04:00
Dale Weiler
0db41f4279 Only increment the buffer location for macro output whitespace stripping if the situation is actually stripable, otherwise macros like #define foo(X) bar(#X), with foo(test) will expand to bartest) instead of bar(test). This should fix Xonotic builds. 2014-04-08 04:02:23 -04:00
Dale Weiler
15d1277158 Added memory protection to prevent mismatching of mem_d or vec_free on pointers which are otherwise unknown to be allocated memory or allocated vectors. Also fixed the preprocessor to only strip on ' ' and '\t' around macros. 2014-04-08 03:26:08 -04:00
Wolfgang Bumiller
2b7b2ea455 fix a silly macro issue 2014-04-07 14:28:11 +02:00
Wolfgang Bumiller
e8133893a0 Merge remote-tracking branch 'origin/master' into cooking 2014-04-07 14:23:35 +02:00
Dale Weiler
f1650c42d9 Match C's preprocessor semantics for token pasting with '##'. 2014-04-07 06:00:04 -04:00
Dale Weiler
606d7ac110 Eliminate debug log 2014-04-05 05:16:36 -04:00
Dale Weiler
90533079c8 Rework distro package build system. 2014-04-05 05:16:15 -04:00
Dale Weiler
fe14d1b056 Order 2014-04-05 02:53:03 -04:00
Dale Weiler
8250124c51 Consistency 2014-04-05 02:52:01 -04:00
Dale Weiler
8c0a280a3e Fixed Windows builds. Now we also build Win64 packages. 2014-04-05 02:50:07 -04:00
Dale Weiler
9e5d02dab0 Less parens 2014-03-17 10:24:48 -04:00
Dale Weiler
827826b9f9 Remove the qcint cast. 2014-03-17 10:23:13 -04:00
Dale Weiler
763e85b3ae Use powf instead of pow. 2014-03-17 09:43:17 -04:00
Dale Weiler
b21e967581 Fix left/right shift constant fold. 2014-03-17 09:41:53 -04:00
Dale Weiler
06e2cb2b1b Add qc_pow. 2014-03-17 09:39:59 -04:00
Wolfgang Bumiller
581c48e337 Merge pull request #142 from CurrentResident/big_endian_testsuite
Big endian testsuite
2014-02-23 12:31:01 +01:00
Jim Thoenen
56edc3db9c White space tweak 2014-02-22 22:21:29 -06:00
Jim Thoenen
52adc2113f Tweak for coding convention 2014-02-22 21:22:41 -06:00
Jim Thoenen
69b89dc6ac Allow testsuite to pass on big endian
Move the progs header and body byteswapping into util functions and
call those functions when either reading or writing the progs.
2014-02-10 20:31:54 -06:00
Wolfgang Bumiller
f7e074d88f Merge branch 'master' into cooking 2014-02-08 10:33:50 +01:00
Dale Weiler
7ffda37513 s/atanhf/atanh/ 2014-02-08 02:50:06 -05:00
Wolfgang Bumiller
24763aad65 moving the length multiplication for 64 bit types from util_endianswap into util_swap64; renaming length parameter to count 2014-02-02 11:04:18 +01:00
Dale Weiler
360389638b Merge pull request #141 from CurrentResident/big_endian_swap_fix
Big endian swap fix
2014-02-02 02:00:15 -08:00
Jim Thoenen
2ddb5ad50d Update per IRC peer review feedback
Restore the swap function's original name, remove convenience function,
use %u in log message, whitespace tweak.
2014-02-02 02:32:50 -06:00
Jim Thoenen
3070c03fc0 Oops, scale int64 count into int32 count for swapper. 2014-02-02 01:52:50 -06:00
Jim Thoenen
1bf9ebabcc Big-endian: Byteswap only the field contents when writing progs.dat
The previous code swapped not just the fields' contents themselves, but
also field positions within several of the structs, resulting in a
non-working progs.dat when compiled on big endian (ppc in my case).
Swapping on a field-by-field basis now.

Also:
* Addresses weird swap size requests (30+ bytes in one case)

* Take a guess at the right way to log a weird swap request before dying

* Fix swap array length scaling

* Rename the main swap function to reflect its native->little-endian
  purpose.  Figued that was okay because progs.dat is required to be
  always little-endian...

* Add a non-array version of the swap function for convenience
2014-02-02 00:57:02 -06:00
Wolfgang Bumiller
9cc4fe1ed2 Merge branch 'master' into cooking 2014-01-26 12:38:00 +01:00
Wolfgang Bumiller
fee2986907 Merge pull request #140 from Sicness/gmqcc.1-hyphen
Fix hyphen-used-as-minus-sign in gmqcc.1
2014-01-26 03:37:33 -08:00
Anton Balashov
669a055594 Fix hyphen-used-as-minus-sign in gmqcc.1
I: gmqcc: hyphen-used-as-minus-sign usr/share/man/man1/gmqcc.1.gz:338
N:
N:    This manual page seems to contain a hyphen where a minus sign was
N:    intended. By default, "-" chars are interpreted as hyphens (U+2010) by
N:    groff, not as minus signs (U+002D). Since options to programs use
minus
N:    signs (U+002D), this means for example in UTF-8 locales that you
cannot
N:    cut and paste options, nor search for them easily. The Debian
groff
N:    package currently forces "-" to be interpreted as a minus sign due
to
N:    the number of manual pages with this problem, but this is a
N:    Debian-specific modification and hopefully eventually can be
removed.
N:
N:    "-" must be escaped ("\-") to be interpreted as minus. If you
really
N:    intend a hyphen (normally you don't), write it as "\(hy" to
emphasise
N:    that fact. See groff(7) and especially groff_char(7) for details,
and
N:    also the thread starting with
N:
http://lists.debian.org/debian-devel/2003/debian-devel-200303/msg01481.html
N:
N:    If you use some tool that converts your documentation to groff
format,
N:    this tag may indicate a bug in the tool. Some tools convert dashes
of
N:    any kind to hyphens. The safe way of converting dashes is to
convert
N:    them to "\-".
N:
N:    Because this error can occur very often, Lintian shows only the
first 10
N:    occurrences for each man page and give the number of suppressed
N:    occurrences. If you want to see all warnings, run Lintian with the
N:    -d/--debug option.
N:
N:    Refer to /usr/share/doc/groff-base/README.Debian and the
groff_char(7)
N:    manual page for details.
N:
N:    Severity: wishlist, Certainty: possible")"
2014-01-26 12:14:18 +04:00
Dale Weiler
24f9313952 Screw clang 2014-01-07 13:13:25 -05:00
Dale Weiler
a140b749ff Fix lshift/rshift for runtime and const-fold consistency. 2014-01-07 12:58:53 -05:00
Wolfgang Bumiller
0f506e768b sometimes I hate travis 2014-01-07 15:04:29 +01:00
Wolfgang Bumiller
792c1afd95 Do not create coverage calls on array accessors. 2014-01-07 15:01:52 +01:00
Wolfgang Bumiller
4ff68e07e8 Adding coverage support:
The -coverage option causes all values have AST_FLAG_BLOCK_COVERAGE
set by default.
The coverage attribute can be used to control coverage:
It takes an optional list of coverage types, currently only "block"
and "none" is recognized.
[[coverage]] defaults to [[coverage(block)]].
Use [[coverage(none)]] or [[coverage()]] to disable.
2014-01-07 14:36:00 +01:00
Dale Weiler
5a160b0e88 Happy new year redux! 2014-01-01 06:25:00 -05:00
Dale Weiler
a934e0fe4b Happy new year! 2014-01-01 06:24:16 -05:00
Wolfgang Bumiller
b6b4a87cbf That's not how it should fail :P 2014-01-01 12:21:00 +01:00
Wolfgang Bumiller
acdc559d1f improved test of last attribute 2014-01-01 12:18:54 +01:00
Wolfgang Bumiller
5319caaaea definite -> last keyword; testcase updated too 2014-01-01 12:16:19 +01:00
Dale Weiler
0b6637cc67 Cleanup some code duplication. This whole parser ugh I just want to rm -rf all of it. Time for GMQCC2. 2014-01-01 05:32:24 -05:00
Dale Weiler
1e30c2b81d Remove final attribute and bareword. [[definite]] is now old [[final]]. There is no bareword definite either. 2014-01-01 05:12:21 -05:00
Dale Weiler
26ab792f9c More cleanup 2013-12-15 01:45:36 -05:00
Dale Weiler
7e88247ed5 hash cleanups. 2013-12-15 01:37:24 -05:00
Dale Weiler
f24bdced10 Remove SSE hash, t's just too much effort to maintain. 2013-12-14 17:30:51 -05:00
Dale Weiler
31e13e6e64 Fix some stuff 2013-12-14 15:07:04 -05:00
Dale Weiler
103bca7284 Partially fix that. 2013-12-14 14:57:10 -05:00
Dale Weiler
d43a270142 typo 2013-12-14 06:02:39 -05:00
Dale Weiler
4c5a0ff662 Do not include this function unless !defined(__SSE__) 2013-12-14 01:34:33 -05:00
Dale Weiler
4d4851e179 Faster hashing reaching 16 GB/s on Phenom II X4. 2013-12-14 01:23:39 -05:00
Dale Weiler
58cd326d85 Only optimize (a - (-b)) into (a + b) when the unary operand is a negation. This fixes (a - (!b)) being turned into (a + b). 2013-12-08 19:01:44 -05:00
Wolfgang Bumiller
50f905b821 adding 'final' 2013-12-06 22:41:15 +01:00
Dale Weiler
072bff44e6 Bitshifting operators <<, >>, and compound assignment versions now work in non-constant expressions 2013-12-03 17:40:15 -05:00
Dale Weiler
af53c0cb83 Mask out the math constant precedence stuff unless -fftepp-mathdefs 2013-12-01 10:52:42 -05:00
Dale Weiler
6a44b72db3 Mask ftepp math constants with a compiler flag 2013-12-01 10:45:43 -05:00
Dale Weiler
b20e2a9d34 User supplied math constants take precedence 2013-12-01 10:30:24 -05:00
Dale Weiler
11ecc6cb0b Ignore emitting implicit math constants in the preprocessor if they exist. 2013-12-01 10:26:36 -05:00
Dale Weiler
2024b3bd71 Merge branch 'master' into cooking 2013-11-30 13:14:04 -05:00
Dale Weiler
78b615fce5 Merge pull request #139 from ignatenkobrain/update_fedora
fedora: Update .spec and INSTALL
2013-11-30 10:13:26 -08:00
Dale Weiler
892746056e Merge pull request #138 from ignatenkobrain/fix_authors
s/brian/brain/ ;)
2013-11-30 10:13:19 -08:00
Dale Weiler
d14c757076 Merge pull request #137 from ignatenkobrain/fix_build_big_endian
fix build on big endian arches
2013-11-30 10:13:12 -08:00
Igor Gnatenko
320784b20d fedora: Update .spec and INSTALL
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2013-11-30 12:35:07 +04:00
Igor Gnatenko
7b7d012255 s/brian/brain/ ;)
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2013-11-30 12:31:21 +04:00
Igor Gnatenko
a20127b063 fix build on big endian arches
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2013-11-30 12:28:59 +04:00
Dale Weiler
9b92cb0897 Simplify 2013-11-29 13:50:06 -05:00
Dale Weiler
43e9885a08 Fix fold_op_cmp 2013-11-29 13:48:03 -05:00
Dale Weiler
ac7e1a557d Fixes 2013-11-29 13:36:35 -05:00
Dale Weiler
ea801acdb8 oops 2013-11-29 13:18:50 -05:00
Dale Weiler
4583cb8280 cleanup 2013-11-29 13:13:39 -05:00
Dale Weiler
cb97b7f672 Cleanup lexer old cruft 2013-11-29 07:15:49 -05:00
Dale Weiler
1d347eaf66 Handle byte order mark for unicode. (0xEFBBBF) 2013-11-29 07:03:55 -05:00
Wolfgang Bumiller
c3cc6f184e static variables now don't get re-initialized in functions; cannot be initialized with non-constants anymore; and a counter has been added so you can use the same name in a different scope for another static variable again. 2013-11-28 12:04:01 +01:00
Dale Weiler
bf127088ca Make log use the slightly improved algorithm for small values. 2013-11-25 14:08:05 -05:00
Dale Weiler
9749ec350a Reorder intrinsics table 2013-11-25 13:44:00 -05:00
Dale Weiler
e5fc8fdded out isn't used 2013-11-25 13:42:17 -05:00
Dale Weiler
2d0f0a3607 Never mind 2013-11-25 13:32:02 -05:00
Dale Weiler
25e86c04eb Only g++ is this retarded 2013-11-25 13:30:45 -05:00
Dale Weiler
f19d32b29b Another one 2013-11-25 13:26:24 -05:00
Dale Weiler
dc48af195d Pregenerate 2.0 for const folder since it's used often 2013-11-25 13:25:29 -05:00
Dale Weiler
33c0c83d59 Implemented __builtin_ln, __builtin_log, __builtin_log10, __builtin_log2 and __builtin_logb. This algorithm is nuts. 2013-11-25 13:21:27 -05:00
Dale Weiler
02c6076bfd Fix 2013-11-25 11:29:36 -05:00
Dale Weiler
3209aaa996 Implement __builtin_nan, __builtin_inf and __builtin_epsilon to generate machine nan, inf and epsilon values (at runtime). 2013-11-25 11:26:16 -05:00
Dale Weiler
8a26ed7664 Fix CRC16 2013-11-25 02:11:45 -05:00
Dale Weiler
50d1bfe783 Fix 2013-11-23 21:17:35 -05:00
Dale Weiler
63c0917d24 More compiler intrinsics for math functions 2013-11-23 21:14:13 -05:00
Dale Weiler
87a43777ab strength reduct (a - (-b)) into (a + b) 2013-11-23 13:13:21 -05:00
Dale Weiler
23904bad52 Better exp algorithm from divVerent 2013-11-23 12:45:22 -05:00
Dale Weiler
52cda620b2 Fix comments 2013-11-23 11:15:28 -05:00
Dale Weiler
1c33bcfceb Fixed pow 2013-11-23 11:14:42 -05:00
Dale Weiler
db182819ae Guard against nullfunc 2013-11-23 10:58:03 -05:00
Dale Weiler
ab2a4f1318 Some math constants 2013-11-23 10:31:51 -05:00
Dale Weiler
80adfebd23 Implement isinf intrinsic 2013-11-23 10:16:48 -05:00
Dale Weiler
aee68d80ea Cull back on the TODO 2013-11-23 08:02:56 -05:00
Dale Weiler
457a1b9690 Undefine macros after using them 2013-11-23 07:47:16 -05:00
Dale Weiler
943cb2ca64 Mark restrict on input too 2013-11-23 07:45:45 -05:00
Dale Weiler
556a84a46f Mark const for better generated code 2013-11-23 07:44:34 -05:00
Dale Weiler
b52cf4d47e Add comment abotu CRC16 2013-11-23 07:42:38 -05:00
Dale Weiler
e2bfaf8109 Implemented exp2 intrinsic 2013-11-23 07:37:26 -05:00
Dale Weiler
c68a5c29e1 Simplify 2013-11-23 07:27:09 -05:00
Dale Weiler
11f79bb1a6 Use '#' in nullfun identifier to prevent it from being used in code 2013-11-23 07:25:24 -05:00
Dale Weiler
54f331a64a Fix intrinsics for self-inclusion of other intrinsics. 2013-11-23 07:21:12 -05:00
Dale Weiler
74b58c5bb8 Cleaner handling since intrin_func deals with alias 2013-11-23 07:02:45 -05:00
Dale Weiler
292c8150b4 Resolve undefined functions to compiler builtins if they exist. 2013-11-23 06:57:40 -05:00
Dale Weiler
b1fd85b711 Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2013-11-23 06:41:24 -05:00
Dale Weiler
d9572e3e30 Fixed pow/exp using fast approximation until the fractional part is hit. Once fractional is reached a binary search is used to get close to the value. 2013-11-23 06:40:27 -05:00
Wolfgang Bumiller
0860b7a68b crc16 slice-by-8 table generator code included for reference 2013-11-23 11:58:20 +01:00
Wolfgang Bumiller
759fca6921 slice-by-8 crc16 2013-11-23 11:50:30 +01:00
Dale Weiler
3b6e7d0ce1 indent 2013-11-23 03:54:11 -05:00
Dale Weiler
ae9d3d42cf A better mod implementation 2013-11-23 03:53:07 -05:00
Dale Weiler
29f2cc302b Add reference tool 2013-11-23 03:10:09 -05:00
Dale Weiler
7011a2ef2c Faster CRC16 algorithm based on the Slicing-by-8 algorithm, by Michael E. Kounavis and Frank L. Berry from Intel Corp. 2013-11-23 01:00:32 -05:00
Wolfgang Bumiller
ec03b55d1a now it parses and has the desired precedence 2013-11-16 14:34:24 +01:00
Wolfgang Bumiller
9131644412 ** precedence was wrong 2013-11-16 14:26:46 +01:00
Wolfgang Bumiller
49bb172a09 folder: change ~ for floats too 2013-11-14 11:41:11 +01:00
Dale Weiler
73c4015046 Fix unary minus on vector 2013-11-13 08:57:14 -05:00
Dale Weiler
1900262df4 Use a branch instead of math on enum types 2013-11-13 04:57:18 -05:00
Wolfgang Bumiller
f43106017f bit more concise 2013-11-12 16:28:11 +01:00
Wolfgang Bumiller
eb4486a7ac working fold_op_cmp implementation 2013-11-12 16:15:02 +01:00
Wolfgang Bumiller
1d5229ee8c vec3_not: be consistent with compile-time behavior here 2013-11-12 16:05:54 +01:00
Wolfgang Bumiller
eee7d0aac1 vec3_pbool: or, not and 2013-11-12 15:56:04 +01:00
Wolfgang Bumiller
de12a24bc9 folder: fix -fperl-logic 2013-11-12 14:39:25 +01:00
Wolfgang Bumiller
6ea88c9a3f subtracting != adding 2013-11-12 14:31:11 +01:00
Wolfgang Bumiller
de14d514f3 fix 0-x being turned into x 2013-11-06 16:57:04 +01:00
Wolfgang Bumiller
99de3cf4f5 regular procedure... bumping PKGBUILDs, GMQCC_VERSION macros, adding back GMQCC_VERSION_TYPE_DEVEL 2013-10-31 22:17:53 +01:00
Wolfgang Bumiller
7f2b2061e6 0.3.5 commit 2013-10-31 22:13:42 +01:00
Dale Weiler
1d745fd1f9 Merge branch 'cooking' 2013-10-31 08:22:54 -04:00
Wolfgang Bumiller
7a29f65683 Nothing in there requires unistd.h 2013-10-28 11:37:08 +01:00
Wolfgang Bumiller
1ca36b7e49 Revert "oh my god, make it stop >.<"
This reverts commit a120209567.
2013-10-27 20:11:41 +01:00
Wolfgang Bumiller
a120209567 oh my god, make it stop >.< 2013-10-27 19:19:11 +01:00
Wolfgang Bumiller
b1016c7f48 fold_binary now used instead of ast_binary_new, which calls fold_superfluous 2013-10-25 13:40:31 +02:00
Dale Weiler
91c894d4da Disable it on master too since Xonotic compiles are failing. 2013-10-24 11:56:23 -04:00
Wolfgang Bumiller
065a870e7a build again 2013-10-23 14:04:20 +02:00
Wolfgang Bumiller
b87eb89853 This is not allowed 2013-10-23 14:01:56 +02:00
Dale Weiler
c90807dec6 Some correctly-sized type flags for the AST and IR, this culls back memory usage a little. 2013-10-19 23:39:37 -04:00
Dale Weiler
0695ad1659 Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2013-10-19 02:53:46 -04:00
Dale Weiler
b5b9559d6f Make preprocessor predefs use their own context opposed to the lexer context. 2013-10-19 02:52:47 -04:00
Wolfgang Bumiller
3988aae73e type and argument parsing improved to handle the field/vararg ambiguity; tests added 2013-10-18 16:28:28 +02:00
Dale Weiler
0f6c44d671 We're doing it this way. 2013-10-18 05:37:26 -04:00
Wolfgang Bumiller
8d5e719026 replacing the current [[accumulate]] implementation: shorter and simpler, and also supports non-void return types 2013-10-18 11:26:41 +02:00
Dale Weiler
0cfc275f82 Fix 2013-10-17 20:35:56 -04:00
Dale Weiler
c210340081 Undo fix and actually use a macro in the accumulation test .. just incase. 2013-10-17 20:34:16 -04:00
Dale Weiler
c675ba8086 Does this fix it? 2013-10-17 20:25:02 -04:00
Dale Weiler
9f54610fbd Implement support for octal constants, this closes #97. 2013-10-17 05:17:30 -04:00
Dale Weiler
02a1d9f4a1 Fix 'declaration does not declare anything' regression i.e this closes #132. 2013-10-17 05:06:09 -04:00
Dale Weiler
97217b55d1 Ignore generating a return instruction in accumulated functions, eventually we'll have a way to merge these into one function but for now the RETURN is a waste. 2013-10-17 04:45:24 -04:00
Dale Weiler
dd33f4e498 Update deps 2013-10-17 04:27:34 -04:00
Dale Weiler
f8949e17c8 Cleaner traces 2013-10-17 04:23:53 -04:00
Dale Weiler
d6f020fd6a Fix memory dump console printing alignment and also trace expressions for allocations. 2013-10-17 04:21:25 -04:00
Dale Weiler
05ac126d6f Use "##" to ensure the names of the accumulated functions are striped by the IR. 2013-10-17 03:47:26 -04:00
Dale Weiler
cfea900afd Update changes 2013-10-17 03:44:33 -04:00
Dale Weiler
8a9c4edce8 Add a test for function accumulation attribute 2013-10-17 03:43:05 -04:00
Dale Weiler
4da820ef61 Enforce void type on accumulatable functions. 2013-10-17 03:39:14 -04:00
Dale Weiler
2c975bb344 Implemented [[accumulate]] attribute. This will hopefully be used by Xonotic to replace it's ACCUMULATE_FUNCTION stuff. 2013-10-17 03:21:30 -04:00
Dale Weiler
1b14c49815 Use .dat extension on generated binaries in testsuite to prevent them from being sourced as task template files. This will fix the async builds on travis.ci 2013-10-17 00:18:07 -04:00
Dale Weiler
8699053887 Fix handling on intrinsic folding, this closes #118. 2013-10-17 00:14:42 -04:00
Dale Weiler
003bb9dfb4 Prevent aliasing functions through forward declared prototypes. This closes #125 2013-10-16 23:37:39 -04:00
Dale Weiler
0f479f3e88 Another one 2013-10-16 21:47:12 -04:00
Dale Weiler
c63bebd7d8 float and double shouldn't be used here, this is what qcfloat_t is for. This fixes the memcmp bug in the folder. 2013-10-16 21:32:31 -04:00
Dale Weiler
b147602d78 Fix option string allocated/non allocated storage. 2013-10-16 20:14:49 -04:00
Dale Weiler
f53502c9ca Make it valid C++ code, such that it can compile as C++ code. 2013-10-16 19:54:21 -04:00
Dale Weiler
50d165e173 Some intrinsic code cleanup. The args check is handled anyways in the parser. We use a generated array alongside to prevent generating the intrinsic multiple times instead of using static storage. Other various cleanups as well. 2013-10-16 00:04:39 -04:00
Dale Weiler
eca82511c6 divVerent suggestion to use memcmp here 2013-10-14 22:40:36 -04:00
Dale Weiler
6d8d7ee923 Make divVerent happy about handling divison by zero/inf/nan and negitive versions. This code now assumes IEEE 754. 2013-10-14 22:31:37 -04:00
Dale Weiler
c8413a9a04 Clang is so anal 2013-10-14 21:03:24 -04:00
Dale Weiler
8e8b3608fb Cleanups 2013-10-14 20:58:36 -04:00
Dale Weiler
65a2b83abd Cleanup for builds 2013-10-14 02:17:45 -04:00
Wolfgang Bumiller
19331ee385 who let the cat out? 2013-10-11 15:53:59 +02:00
Dale Weiler
ef51b30387 Fix windows builds, add strip target for makefiles, update distro build makefiles to use it for release builds. 2013-10-11 09:51:08 -04:00
Dale Weiler
f008cc257d Some cleanups 2013-10-11 09:32:46 -04:00
Dale Weiler
ccb46d7e3b Update README 2013-10-11 08:14:37 -04:00
Wolfgang Bumiller
42a9784804 Merge branch 'cooking' of git://github.com/graphitemaster/gmqcc into cooking 2013-10-11 14:11:40 +02:00
Wolfgang Bumiller
82afdb1e2c Merge branch 'cooking' of git://github.com/graphitemaster/gmqcc into cooking 2013-10-11 14:10:57 +02:00
Wolfgang Bumiller
62ac7e9966 first part of parsing TOKEN_DOTS as part of a type when needed; allows declarations like: ...float x; 2013-10-11 14:10:47 +02:00
Dale Weiler
6da151eba1 Update dependencies 2013-10-11 08:10:32 -04:00
Dale Weiler
856949a5f9 I need to test this code on msvc now. 2013-10-11 08:08:36 -04:00
Dale Weiler
d8b3faa871 Fix that (newer clang will fail on it) 2013-10-11 08:06:10 -04:00
Dale Weiler
92c0d6157c Merge branch 'cleanup' into cooking 2013-10-11 08:04:02 -04:00
Dale Weiler
fa14550d38 Last piece of documentation for platform.h 2013-10-11 08:02:28 -04:00
Dale Weiler
604c9d25bf More documentation for platform.h 2013-10-11 07:40:31 -04:00
Dale Weiler
4d0bf1607a Some documentation 2013-10-11 07:16:48 -04:00
Dale Weiler
63fdab8422 Some more cleanup 2013-10-11 06:36:05 -04:00
Dale Weiler
87d9371a5c Refactor some util/platform usage and extend file system file interface to accept its own flags and EOF 2013-10-11 06:12:56 -04:00
Wolfgang Bumiller
3d5fedcf39 distro/archlinux/this/Makefile: TARCOMP variable contains the compression flag, rather than using -J in the makerule but provide the .xz extension in a variable 2013-10-11 11:17:03 +02:00
Wolfgang Bumiller
637651f4e1 distro/archlinux/this/Makefile: tar -> bsdtar 2013-10-11 11:14:46 +02:00
Dale Weiler
e9bde1e4e4 Add back the correct directory handling for msvc 2013-10-11 05:09:55 -04:00
Dale Weiler
34c18ab860 Make it compile with mingw32 again 2013-10-11 04:58:49 -04:00
Dale Weiler
dab528acda Add a porting guide 2013-10-11 04:55:26 -04:00
Dale Weiler
e8955f17ea More cleanups, gmqcc.h doesn't need to include stdio.h now! 2013-10-11 04:06:52 -04:00
Dale Weiler
033cf7c7d3 More cleanups 2013-10-11 03:59:25 -04:00
Dale Weiler
5138a25420 More cleanup 2013-10-11 03:21:44 -04:00
Dale Weiler
12a864abf5 Some more platform / compiler specific code refactoring. 2013-10-11 03:02:38 -04:00
Dale Weiler
151606e255 Initial platform / compiler specific code refactoring. 2013-10-11 02:39:30 -04:00
Dale Weiler
14ef6a1c42 This can actually be much smaller, 204 bytes! 2013-10-11 00:22:27 -04:00
Dale Weiler
9dabb68d7f More typos 2013-10-10 22:12:03 -04:00
Dale Weiler
f73f2f1ba9 typo 2013-10-10 22:11:03 -04:00
Dale Weiler
e263506b3f Document what the utf8 table actually is 2013-10-10 22:10:36 -04:00
Dale Weiler
3e362e872c Wrong operand order it's 0xf4u-0xc2u i.e 0x32. 2013-10-10 22:03:13 -04:00
Dale Weiler
f83cc1b91d Less flexible more economical utf8 decoder. 2013-10-10 21:44:40 -04:00
Dale Weiler
6bd6379c87 Don't echo it 2013-10-05 23:39:05 -04:00
Dale Weiler
a02e44100e Fix some things: get all the Quake mods to compile again (I broke binary expressions .. oops) Fix the check-proj script, using $? for status was invalid because of pipes. The ir now properly considers negation virtual instruction to be operations (as it should). 2013-10-05 23:36:48 -04:00
Dale Weiler
99e3ae9773 Update CHANGES files 2013-10-05 22:34:55 -04:00
Dale Weiler
300fb9905b Fix fold_superfluous 2013-10-04 07:10:58 -04:00
Dale Weiler
ffdd6df828 Only when peephole optimization is on 2013-10-04 07:02:06 -04:00
Dale Weiler
2cf5046d38 Handle proper expression type assignment 2013-10-04 06:53:09 -04:00
Dale Weiler
cc69370575 Another peephole optimization which removes superfluous expressions such as (A + 0), (A - 0), (A * 1) and (A / 1). 2013-10-04 06:46:54 -04:00
Dale Weiler
263fcfbc2f Refactor intrinsic stuff 2013-10-02 13:00:34 -04:00
Dale Weiler
2ebf571129 Update documentation 2013-09-30 16:03:22 -04:00
Dale Weiler
90824c2093 Add seperate warning flag for directive in macro. 2013-09-30 15:59:36 -04:00
Dale Weiler
8f359f3849 Warn when preprocessor directive is found inside a macro body. 2013-09-30 15:57:01 -04:00
Dale Weiler
08891068c8 Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2013-09-30 14:33:57 -04:00
Dale Weiler
b6f08e7fb1 Fix negation type for VINSTR_NEG_V. Source operand for optimization instead of the expression (to handle double negation elision properly.) 2013-09-30 14:32:21 -04:00
Wolfgang Bumiller
fa14ca93d2 Merge branch 'master' into cooking 2013-09-30 15:02:03 +02:00
Wolfgang Bumiller
dfbd093348 Merge pull request #134 from Sicness/hyphen
Fixed hyphen-used-as-minus-sign in gmqcc.1
2013-09-30 06:01:22 -07:00
Anton Balashov
e928cabfb2 Fixed hyphen-used-as-minus-sign in gmqcc.1
Accortding to lintian report:
I: gmqcc: hyphen-used-as-minus-sign usr/share/man/man1/gmqcc.1.gz:156
N:
N:    This manual page seems to contain a hyphen where a minus sign was
N:    intended. By default, "-" chars are interpreted as hyphens (U+2010) by
N:    groff, not as minus signs (U+002D). Since options to programs use minus
N:    signs (U+002D), this means for example in UTF-8 locales that you cannot
N:    cut and paste options, nor search for them easily. The Debian groff
N:    package currently forces "-" to be interpreted as a minus sign due to
N:    the number of manual pages with this problem, but this is a
N:    Debian-specific modification and hopefully eventually can be removed.
N:
N:    "-" must be escaped ("\-") to be interpreted as minus. If you really
N:    intend a hyphen (normally you don't), write it as "\(hy" to emphasise
N:    that fact. See groff(7) and especially groff_char(7) for details, and
N:    also the thread starting with
N:    http://lists.debian.org/debian-devel/2003/debian-devel-200303/msg01481.html
N:
N:    If you use some tool that converts your documentation to groff format,
N:    this tag may indicate a bug in the tool. Some tools convert dashes of
N:    any kind to hyphens. The safe way of converting dashes is to convert
N:    them to "\-".
N:
N:    Because this error can occur very often, Lintian shows only the first 10
N:    occurrences for each man page and give the number of suppressed
N:    occurrences. If you want to see all warnings, run Lintian with the
N:    -d/--debug option.
N:
N:    Refer to /usr/share/doc/groff-base/README.Debian and the groff_char(7)
N:    manual page for details.
N:
N:    Severity: wishlist, Certainty: possible
N:
N:    Check: manpages, Type: binary
N:
I: gmqcc: hyphen-used-as-minus-sign usr/share/man/man1/gmqcc.1.gz:354
I: gmqcc: hyphen-used-as-minus-sign usr/share/man/man1/gmqcc.1.gz:676
2013-09-30 16:43:57 +04:00
Dale Weiler
03b56bd41f Handle double negation case specially. Update TODO 2013-09-30 05:12:28 -04:00
Dale Weiler
7249c2ec18 Simplify parse stage for unary - operator. 2013-09-29 22:08:09 -04:00
Dale Weiler
353455e1ad Remove pointless thinking comment, fix builds for clang. 2013-09-29 22:06:26 -04:00
Dale Weiler
b10de1b240 Make unary - operator act as an ast_unary node. This allows for consistency (no sense in making unary use binstore nodes, it doesn't make much sense). It also allows for the peephole optimization on unary chains that cancel each other to take place; i.e code like "-(-a)" simplifies to "a", thus eliminating instructions. 2013-09-29 22:01:46 -04:00
Dale Weiler
3c931ecbf1 Eh, only if peephole optimizations are turned on. 2013-09-28 06:41:40 -04:00
Dale Weiler
c6056d441b Less casts. 2013-09-28 06:36:00 -04:00
Dale Weiler
7c25af973c It was much easier in the AST, really. 2013-09-28 06:33:15 -04:00
Dale Weiler
81df8fa139 Remove the rest of it. 2013-09-28 06:10:02 -04:00
Dale Weiler
8a294683bb Remove it, maybe it can be done in the AST instead. 2013-09-28 06:09:24 -04:00
Dale Weiler
c4e92df106 Eh. 2013-09-28 05:36:09 -04:00
Dale Weiler
2b3663e18d Optimize for superfluous cases of NOT, i.e !!!!x can be simplified to !!x. 2013-09-28 05:34:53 -04:00
Dale Weiler
0d1f20fea3 Move it over 2013-09-28 03:41:18 -04:00
Igor Gnatenko
95b7056427 Optimizng compile flags
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2013-09-28 03:37:58 -04:00
Igor Gnatenko
c8a1b6563e Update to 0.3.0 (improved new package: gmqpak)
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2013-09-28 03:37:58 -04:00
Igor Gnatenko
48211572e5 Initial release
Add spec and patch

Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2013-09-28 03:37:58 -04:00
Dale Weiler
d61c5d3b16 Fix alias type check 2013-09-26 08:09:55 -04:00
Dale Weiler
15b0555546 Implement constant folding on ternary operations via fold_cond. 2013-09-26 06:51:49 -04:00
Dale Weiler
cf2352893f Consistency 2013-09-25 16:19:33 -04:00
Dale Weiler
894e1976e3 Cheap quick hack for ignoring #pragma to EOL 2013-09-25 15:35:18 -04:00
Wolfgang Bumiller
904c45060b remove -printf option from find; remove the misplaced 'local's 2013-09-25 11:16:15 +02:00
Wolfgang Bumiller
87fcf8d8e8 there's no pushd/popd in my sh 2013-09-25 11:14:59 +02:00
Dale Weiler
d2405a9ad8 Some grammar 2013-09-25 04:24:09 -04:00
Dale Weiler
d664b9f607 Fix some stuff for xonotic and make check-proj actually use the options line correctly. 2013-09-25 04:23:06 -04:00
Dale Weiler
13ef558fff Add export utility for Nexuiz, now check-proj handles it. 2013-09-25 04:03:37 -04:00
Dale Weiler
3968dc84fd Got Xonotic stuff for check-proj to function. 2013-09-25 03:52:48 -04:00
Dale Weiler
330111d5fc Fix the xonotic export script for check-proj.sh 2013-09-24 07:53:51 -04:00
Dale Weiler
fac4e411bf Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2013-09-24 07:32:23 -04:00
Dale Weiler
73eca0848c Fix QuakeWorld compilation by treating assignment to constants as a warning when -std=qcc. 2013-09-24 07:31:53 -04:00
Dale Weiler
37a4265e06 Update .travis.yml 2013-09-22 08:43:47 -04:00
Dale Weiler
69efb404bf Update .travis.yml 2013-09-22 08:43:24 -04:00
Wolfgang Bumiller
99422d0cf4 this is still there twice... 2013-09-19 21:05:40 +02:00
Wolfgang Bumiller
8d2a6ca419 moving the QCVM_EXECUTOR ifdef in conout.c - these are used in the executor 2013-09-19 21:05:39 +02:00
Dale Weiler
f25fff1e3d Remove debug printfs 2013-09-18 19:18:10 -04:00
Dale Weiler
e18849fa42 Generate (non_const_float * (1.0 / constant_float)) for (non_const_float / constant_float) expressions. 2013-09-18 19:15:24 -04:00
Wolfgang Bumiller
5a47dd5e62 since we don't bail on some of the warnings right away, (that is, with -Werror), also check the compile_errors count in main rather than just the return values 2013-09-18 16:20:25 +02:00
Wolfgang Bumiller
b6da3613ac making irwarning warn on an unused result 2013-09-18 16:20:24 +02:00
Dale Weiler
241637a980 Don't need that, each directory already has its own progs.src 2013-09-12 17:18:47 -04:00
Dale Weiler
9726d80e05 Output the dat name for xonotic export tool (first line of prog.src) 2013-09-12 17:08:40 -04:00
Dale Weiler
94e477e466 Added -progsrc commandline switch to specify progs.src files of different names. Cleaned up xonotic export script, fixed check-doc on linux systems by disabling mandoc check. 2013-09-12 17:06:20 -04:00
Dale Weiler
5bb245a33a Added xonotic_export.sh utility that when run from a xonotic-data.pk3dir will eliminate redundant files and create prog.src files for csprogs, progs(server) and menu. This tool will be used for check-proj.sh for exporting xonotic changes to our server. 2013-09-12 15:06:36 -04:00
Dale Weiler
6a235dc25f Support options for check-proj now 2013-09-11 17:09:03 -04:00
Dale Weiler
207d391fcd Allow running from root of gmqcc repo as well. 2013-09-11 16:50:33 -04:00
Dale Weiler
f44c127fbd Proper gmqcc sourcing for check-proj 2013-09-11 16:48:01 -04:00
Dale Weiler
c52ad67a7c Test for gmqcc in check-proj 2013-09-11 16:38:18 -04:00
Wolfgang Bumiller
35f9aef729 fix: declaring locals with the name of a parameter now treats the parameter as the local's prototype to avoid it being double-freed later 2013-09-11 11:25:44 +02:00
Dale Weiler
46fa12cb26 Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2013-09-10 19:16:14 -04:00
Dale Weiler
8ddd126378 Added check-proj misc tool that downloads various QuakeC projects and tries to compile them with gmqcc, sort of like an additional test. 2013-09-10 19:15:28 -04:00
Wolfgang Bumiller
ce07e8fe28 distro/archbsd/this - as we don't depend on glibc there, just libc; also changed DESTDIR in archlinux/this/Makefile so it can be easily changed from the bsd Makefile 2013-09-09 12:18:30 +02:00
Wolfgang Bumiller
7af8c70bf9 distro/archlinux/this: generate the .MTREE file 2013-09-09 12:08:57 +02:00
Wolfgang Bumiller
3f151321f6 qcvm: exit on error 2013-09-08 21:31:56 +02:00
Dale Weiler
c2cf41baf9 Merge branch 'master' into cooking 2013-09-08 13:05:20 -04:00
Dale Weiler
9908209f58 Fix dependincies 2013-09-08 13:04:07 -04:00
Dale Weiler
6800d15872 Always print the char the lexer fails on for a token. 2013-08-31 16:52:46 -04:00
Dale Weiler
b2c8f3ebc5 Vector cross product virtual instruction, now >< operator works for non-constant vectors. Thanks divVerent for the help. 2013-08-31 14:49:06 -04:00
Dale Weiler
64661f54ea Implemented >< (vector cross product operator). Currently support for constants only. 2013-08-31 13:41:25 -04:00
Dale Weiler
69252071ba Prevent divide by zero for / and % operations in constant folding (previously caused compiler SIGFPE), instead "inf" is generated for both cases. This closes #124 2013-08-31 12:57:24 -04:00
Dale Weiler
9032e78349 There is no bug since the testsuite uses -o for preprocessed output (thus the printf never gets involved) if the testsuite read the preprocessor output from stdout than things would be wrong, since however it isn't there is no bug. 2013-08-31 09:53:19 -04:00
Wolfgang Bumiller
702a7664de Don't allow a stale 'some_type;' declaration without an actual variable name; Same for typedef; closes #119 2013-08-31 11:35:12 +02:00
Wolfgang Bumiller
2ff9adecb2 this one can be reached - make it a little more helpful 2013-08-31 10:55:03 +02:00
Wolfgang Bumiller
4600f1d7ff more thorough check for whether an ast node starts a new label; closes #121 2013-08-31 10:48:24 +02:00
Wolfgang Bumiller
79219ae201 factor check for assignment-to-constant into a function; improve its error output; closes #122 2013-08-31 10:39:31 +02:00
Wolfgang Bumiller
87b9fca732 fix unhelpful error message; fixes #123 2013-08-31 10:19:10 +02:00
Dale Weiler
98cb23ca63 Logic elsewhere handles this (no need to duplicate) 2013-08-30 07:23:15 -04:00
Dale Weiler
a50635bcd7 intrinsic folding cleanups (and improvements.) 2013-08-30 07:12:16 -04:00
Dale Weiler
76c37d9cc0 Rid of util_debug 2013-08-30 06:49:24 -04:00
Dale Weiler
c8b4eac618 Make -fshort-logic -funtyped-nil -fvariadic-args default for -std=gmqcc 2013-08-29 07:56:22 -04:00
Dale Weiler
f8af7adcd7 Remove &~= operator from gmqccs operator table, only fteqcc supports it. 2013-08-29 07:19:19 -04:00
Dale Weiler
dd289ed0e1 Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2013-08-29 07:08:03 -04:00
Dale Weiler
3ed200d08a Some changes changes 2013-08-29 07:07:43 -04:00
Wolfgang Bumiller
ff6d55aafc this should allow for better detection of precedence issues 2013-08-29 10:22:48 +02:00
Wolfgang Bumiller
fa468e0673 also warn about mixing logical and/or operations without parenthesis 2013-08-29 08:26:17 +02:00
Wolfgang Bumiller
f140c39063 warn when mixing different bitops without parenthesis around them 2013-08-29 08:18:06 +02:00
Dale Weiler
51ef277e21 Fix folding logic for conditions. 2013-08-29 00:18:48 -04:00
Dale Weiler
a7c1f6f021 Implement [[eraseable]] attribute. When used with a function it instructs the AST (which than transfers logic to the IR) that the function (or variable) is potentially unused (verified by checking the read count). This than propogates through the IR and prevents the IR from generating both the definition and global/function. The intrinsics system uses this as well to prevent intrinsic functions from being generated unless they're used. 2013-08-29 00:05:37 -04:00
Dale Weiler
ceb79f1897 Fix build on clang 2013-08-28 13:01:46 -04:00
Dale Weiler
3b4a5667ea Constant fold intrinsics if their arguments are constant. TODO: reference count intrinsics such that they're not generated unless they're used, currently when an intrinsic can be folded-away it's marked for generation and makes it to the final output binary even though it isn't used. 2013-08-28 12:46:22 -04:00
Dale Weiler
bbe4927a20 Implemented a __builtin_fabs intrinsic. 2013-08-28 11:28:27 -04:00
Dale Weiler
ee428b9081 Fix fold-dce for if(0) 2013-08-28 10:39:48 -04:00
Wolfgang Bumiller
40bcec5044 Add missing -width to .Bl in doc/gmqpak.1 2013-08-28 14:40:23 +02:00
Wolfgang Bumiller
a80aa89e09 Fix bad use of .D1 in doc/qcvm.1 2013-08-28 14:38:51 +02:00
Wolfgang Bumiller
660a22d647 misc/check-doc.sh: run mandoc -Tlint -Wall on the manpages 2013-08-28 14:33:09 +02:00
Wolfgang Bumiller
494c30a239 allow initializing shadowed locals outside of -std=gmqcc - in this case it becomes a regular assignment to the old declaration which is consistent with fteqcc 2013-08-28 14:20:33 +02:00
Dale Weiler
71e7db63aa Cleanups 2013-08-28 03:45:40 -04:00
Dale Weiler
8aaa268423 Handle return status from compiler, this fixes false positivies in the testsuite when the compiler segfaults and the testsuite still reports succeeded, now it won't hopefully. 2013-08-28 03:40:35 -04:00
Dale Weiler
a75746d610 Don't ignore empty newlines when match in the testsuite, instead only ignore when procedure type is -pp (i.e preprocessing). 2013-08-28 03:34:05 -04:00
Dale Weiler
045bd4dbda Some style fixes for tests 2013-08-27 06:41:03 -04:00
Dale Weiler
28cd3a3f8f Forgot this one 2013-08-27 06:39:51 -04:00
Dale Weiler
f21216ecad A test for that xor stuff (the same one I used to cause the bug to manifest in the first place). 2013-08-27 06:35:58 -04:00
Rudolf Polzer
abfe98ce8a Fix XOR maths for overlapping inputs by setting the lifetimes correctly.
Signed-off-by: Rudolf Polzer <divverent@xonotic.org>
2013-08-27 12:27:20 +02:00
Wolfgang Bumiller
988b4b4960 ast_binary->right_first and an execution order check 2013-08-27 10:42:13 +02:00
Dale Weiler
4937fa51c0 Merge divVerent/ftypeless-stores, but rid of the macro abuse. 2013-08-27 04:28:22 -04:00
Dale Weiler
1b3d515777 Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2013-08-27 04:28:11 -04:00
Wolfgang Bumiller
b26f53125d error on uninitialized arrays of unspecified size; otherwise it errors about a size overflow 2013-08-27 10:19:05 +02:00
Wolfgang Bumiller
844e84fc16 bail out when encountering an invalid array size in the ast as it's likely to cause breakage when trying to generate them anyway 2013-08-27 10:09:31 +02:00
Dale Weiler
581d0dfc15 Merge branch 'divVerent/ftypeless-stores' of git://git.xonotic.org/xonotic/gmqcc into cooking 2013-08-27 04:07:17 -04:00
Wolfgang Bumiller
147a6df629 fix testcase workarounds 2013-08-27 10:00:24 +02:00
Dale Weiler
b3c1b46925 And there she goes, them space swallowing whores. 2013-08-27 03:57:09 -04:00
Rudolf Polzer
f4f805f4c9 New options: -ftypeless-stores and -fsort-operands
These flags reduce entropy, but not size, of the generated assembly
code. This helps compressability of the files.

Additionally, -ftypeless-stores might SLIGHTLY improve engine
performance due to less instructions being used (so branch prediction
might work better). Probably cannot be measured though.

Signed-off-by: Rudolf Polzer <divverent@xonotic.org>
2013-08-27 09:55:00 +02:00
Dale Weiler
fc57fa4064 Add support for columns to LNOF files. 2013-08-26 14:14:33 -04:00
Dale Weiler
0e077c6e42 Fix testsuite for when a process crashes (do not consider it a success) 2013-08-26 13:10:38 -04:00
Dale Weiler
a1f1ec6d65 Fix testsuite 2013-08-26 13:05:54 -04:00
Wolfgang Bumiller
ba94df47f0 reset the column counter on a newline 2013-08-26 18:53:09 +02:00
Dale Weiler
454234ef5f Merge branch 'divVerent/submit/vector-bitops' of git://git.xonotic.org/xonotic/gmqcc into cooking 2013-08-26 12:36:17 -04:00
Rudolf Polzer
e50b7a2719 Support vector bitor/bitand/bitxor.
Signed-off-by: Rudolf Polzer <divverent@xonotic.org>
2013-08-26 18:32:28 +02:00
Wolfgang Bumiller
5958687795 error when trying to pass a TYPE_NOEXPR value to ir_instr_op 2013-08-26 10:23:20 +02:00
Wolfgang Bumiller
69cecb74df ir_builder now has a vinstr_temp array, a bunch of temps (currently 1) which can be used for virtual instruction translation 2013-08-26 10:23:03 +02:00
Dale Weiler
95138b1e5b Some typos 2013-08-21 23:28:49 -04:00
Dale Weiler
efa571043b Make makes output consistent with BSD makes output for make 2013-08-21 09:49:26 -04:00
Wolfgang Bumiller
4990434db7 archlinux PKGBUILDs: don't use install's -D switch - now they should work for both ArchLinux and ArchBSD 2013-08-21 10:45:28 +02:00
Dale Weiler
bbab8969d1 Generate PDF documentation from man pages for windows releases. 2013-08-21 04:29:33 +00:00
Dale Weiler
834e8d0d7d Mark the beginning of the next release, master is now stable. 2013-08-19 23:31:57 +00:00
Dale Weiler
a7fdbbe35b Fix that 2013-08-19 23:18:03 +00:00
Dale Weiler
6a4e175f86 Slackware support to website generation. 2013-08-19 23:15:41 +00:00
Dale Weiler
a93a28230d Merge pull request #117 from matthiaskrgr/master_PKGBUILD
Master pkgbuild
2013-08-19 16:06:03 -07:00
Matthias Krüger
701363347f Merge remote-tracking branch 'upstream/master' into master_PKGBUILD 2013-08-20 00:06:01 +02:00
Matthias Krüger
a1a9438319 PKGBUILD: release: update 2013-08-20 00:04:55 +02:00
Matthias Krüger
491a706610 PKGBUILD: git: update 2013-08-19 23:50:10 +02:00
Dale Weiler
963e93e8e8 This should be the tag 2013-08-19 21:38:18 +00:00
Dale Weiler
c13285092c Mark release, ready to tag it and bag it. 2013-08-19 21:34:49 +00:00
Dale Weiler
ccd8f1acc6 Added style + indent rule, fixed some indenting as well 2013-08-19 02:16:16 +00:00
Dale Weiler
a31eacf1bd Newline rule 2013-08-19 00:59:41 +00:00
Dale Weiler
e15046d66c Please the Samual 2013-08-18 23:44:23 +00:00
Dale Weiler
78a3c5d571 Fix that rule 2013-08-17 23:50:21 +00:00
Dale Weiler
e6809acf63 Added whitespace fix rule to include.mk 2013-08-17 23:49:47 +00:00
Dale Weiler
c64005966f Remove some trailing whitespace 2013-08-17 23:43:41 +00:00
Dale Weiler
2a79339735 Remove that idiom, and use GMQCC_ARRAY_COUNT. 2013-08-17 23:39:06 +00:00
Dale Weiler
dd512ec36a Forgot about this one 2013-08-17 22:19:40 +00:00
Dale Weiler
e7dab06f82 They don't go there, fuck you grep. 2013-08-17 22:17:14 +00:00
Dale Weiler
94139513db Cleanups and update CHANGES 2013-08-17 22:16:40 +00:00
Dale Weiler
7108c61bec Fix the build 2013-08-16 09:09:56 +00:00
Dale Weiler
772dbfae26 Make it compile in visual studio again, without warnings. 2013-08-16 09:03:36 +00:00
Dale Weiler
b30c3ff8d4 Update documentation 2013-08-16 08:16:03 +00:00
Dale Weiler
d5d38e94ef Some testing for valgrind in the makefile 2013-08-16 07:33:57 +00:00
Dale Weiler
89893f9a24 Valgrind integration for our memory allocator. 2013-08-16 07:22:01 +00:00
Dale Weiler
079ed491a9 Update the ini example, holy hell we have more options than I imagined. 2013-08-16 04:22:53 +00:00
Dale Weiler
a622d5163b Rework some build stuff for better output and to enable strict prototypes 2013-08-16 03:28:02 +00:00
Dale Weiler
7df42c95d2 Make our allocator slightly faster with branch hinting. 2013-08-15 06:09:28 +00:00
Dale Weiler
91c7209146 Track constant folds in opts_optimization list .. this could be handled better I assume. 2013-08-15 03:45:50 +00:00
Dale Weiler
ade8626df7 Perform some strict aliasing all over this biatch. We ain't trippin on code that breaks it. 2013-08-14 10:16:04 +00:00
Wolfgang Bumiller
3ece4a964f remove the 'opts' global from test.c and exec.c as opts.c defines it and is linked into both the testsuite and qcvm 2013-08-14 12:09:26 +02:00
Dale Weiler
586a70ea1d Handle some more errors 2013-08-14 07:41:09 +00:00
Dale Weiler
bee14a6df7 Some bug fixes 2013-08-14 07:19:49 +00:00
Dale Weiler
0a5353532b Remove my MT impl for PRNG, it's full of buffer overflows that I don't want to fix. Just fallback to using srand/rand 2013-08-14 06:22:32 +00:00
Dale Weiler
1201f06a55 Remove vec_upload 2013-08-14 06:19:48 +00:00
Dale Weiler
f82097b6b8 Update deps 2013-08-14 06:12:43 +00:00
Dale Weiler
73d9aa29c4 Made intrinsics seperate from the parser. 2013-08-14 06:02:15 +00:00
Dale Weiler
85ee52128c Fix 2013-08-14 04:27:11 +00:00
Dale Weiler
a68f0fcb35 Cleanups 2013-08-14 04:24:06 +00:00
Dale Weiler
5e54db46c4 Some statistics as Samual wanted. 2013-08-14 04:08:00 +00:00
Dale Weiler
b654594adb Disable statistics that are irrelevant to QuakeC coders 2013-08-14 03:24:00 +00:00
Dale Weiler
b10a2d1fd5 Remove the attempt at ast_intrinsic node 2013-08-14 03:05:14 +00:00
Dale Weiler
216330a7e2 Some intrinsic cleanups 2013-08-14 03:03:49 +00:00
Dale Weiler
90e2e5a4ad Some typos 2013-08-14 02:07:12 +00:00
Dale Weiler
7669a99c7f increment the optimization counter for DCE'd folds, also enable -O3 for compilation. 2013-08-01 14:24:10 +00:00
Dale Weiler
69c4dce477 Testsuite now returns the correct value on test failures (also prints how many tests failed .. if any fail) 2013-08-01 07:20:02 +00:00
Dale Weiler
db69d14995 Disable the macros to keep clang happy (just uncomment them for when more constant folding optimizations need them) 2013-08-01 07:12:21 +00:00
Dale Weiler
6f749d61b1 Added -Oconst-fold-dce (dead code elimination optimization for when constant expressions form the basis of the dead code, i.e if else with constant expression). Fixed deps and added documentation. Cleaned up folds for ir_value (can now use the same macros as the ast_value ones). 2013-08-01 07:07:59 +00:00
Dale Weiler
24fc2e5146 Fix that typecast 2013-07-31 19:36:09 +00:00
Dale Weiler
10b75fd8b9 Move const-branch-elision into fold.c 2013-07-31 19:34:38 +00:00
Dale Weiler
3e24b5a74b Remove debugging aid and left over cruft. 2013-07-31 18:54:38 +00:00
Dale Weiler
960cb7034a The problem was so subtle 2013-07-31 18:53:00 +00:00
Dale Weiler
3fa74da2b5 Fixes 2013-07-31 17:24:32 +00:00
Dale Weiler
5f2b7e3d57 fixed vector ops constant folding. 2013-07-31 17:05:43 +00:00
Dale Weiler
d0ee56f25f more fixes 2013-07-31 16:31:45 +00:00
Dale Weiler
1538e69f93 Fixes 2013-07-31 15:56:56 +00:00
Dale Weiler
fa5ad1212e Operator constant folding rewrite almost complete, just need to track down why two tests are failing. 2013-07-31 15:49:45 +00:00
Dale Weiler
86adb94d7d folding for lteqgt (less than equal to or greater than) operator a.k.a <=> which maps values to -1,0,1 depending on the result (think of the result as a troolan) .. it's a perl thing :P 2013-07-31 12:59:34 +00:00
Dale Weiler
9ed62eee58 Feed clang demon 2013-07-31 12:17:52 +00:00
Dale Weiler
c3da9b237b && and || op folding 2013-07-31 12:11:03 +00:00
Dale Weiler
b0460de935 Fold for div op 2013-07-31 11:48:43 +00:00
Dale Weiler
8dd125c8f3 Added constant folding support for '*' .. Clever ascii trick prevail :D 2013-07-31 10:40:17 +00:00
Dale Weiler
5e38c800f6 Some cleanups and more support for constant folding. 2013-07-31 09:56:45 +00:00
Dale Weiler
920dbaf1e0 Work in progress constant-folding rewrite. 2013-07-31 09:04:19 +00:00
Dale Weiler
d8b931fbcf Experimental/Initial try at in-ast constant folding. (for TYPE_FLOAT currently .. since comparisions on UTF8 strings need to be worked out yet ..) 2013-07-30 18:06:42 +00:00
Dale Weiler
2c975fe48f I'm in a state of confusion as to why constant folding was never done on comparisions, now it is ;) 2013-07-30 17:27:54 +00:00
Dale Weiler
d6ca5673dc Use the _t consistency naming scheme. Also various cleanups. 2013-07-30 16:00:51 +00:00
Dale Weiler
a9ab865add Move some things around 2013-07-30 15:32:24 +00:00
Dale Weiler
c8c25ef6f7 Some cleanups and smaller binaries! 2013-07-28 00:23:15 +00:00
Dale Weiler
6c0c7aac0f cherry-pick diagnostics testsuite into cooking. We can now create compiler diagnostic tests, i.e if the compiler errors on syntax, we can match the error messages. 2013-07-28 00:02:48 +00:00
Dale Weiler
9e2b17e715 Merge pull request #116 from ignatenkobrain/cooking
Add instruction for Fedora and other RPM distros
2013-07-27 11:29:14 -07:00
Igor Gnatenko
ab79dbd22a add instruction
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2013-07-27 22:24:43 +04:00
Igor Gnatenko
23af0c0209 add updated spec and rename it
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2013-07-27 22:09:39 +04:00
Igor Gnatenko
bee93f28b3 not needed yet
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2013-07-27 22:08:43 +04:00
Dale Weiler
d684e99d86 Clear out for now. 2013-07-27 17:57:29 +00:00
Dale Weiler
557ad9da1a Make COMPILER_QCC default to please the stuborn Quake community. 2013-07-27 17:56:46 +00:00
Dale Weiler
ec0aaa72a3 Some typos 2013-07-27 16:39:17 +00:00
Dale Weiler
ce7a9d5a3d Not to be included 2013-07-27 16:35:15 +00:00
Dale Weiler
0291726c09 Fedora spec files (0.2.9 and 0.3.0) + INSTALL documentation, thanks Igor Gnatenko. 2013-07-27 16:33:33 +00:00
Dale Weiler
c7679722fb Please the whitespace gods 2013-07-27 11:48:55 +00:00
Dale Weiler
8db9724c5d Revert "Smaller memory footprint, 4/8 bytes vs 12/24 for individual token lex_ctx's. Use to be a 'shallow' copy of the details in lex_file, now it's a pointer to the contents in lex_file."
This reverts commit cddf70f46b.
2013-07-26 16:17:41 +00:00
Dale Weiler
cddf70f46b Smaller memory footprint, 4/8 bytes vs 12/24 for individual token lex_ctx's. Use to be a 'shallow' copy of the details in lex_file, now it's a pointer to the contents in lex_file. 2013-07-26 16:09:26 +00:00
Dale Weiler
4a3794ea2b Track strdup memory too 2013-07-26 14:57:21 +00:00
Dale Weiler
44d5481828 There was too many 16-sized buckets when compiling xonotic, increase the size: this is cheaper on memory and slightly faster. 2013-07-26 14:50:37 +00:00
Dale Weiler
629fe05083 Fix the ctype replacements to work with macro arguments that have side-effect, with exception to isspace which *might* need to become a function. 2013-07-26 12:28:02 +00:00
Dale Weiler
d411d60685 Eeasy fix for that 2013-07-21 22:07:22 +00:00
Dale Weiler
2bfea938b3 One last one 2013-07-21 22:00:07 +00:00
Dale Weiler
96ec279663 Another one 2013-07-21 21:56:03 +00:00
Dale Weiler
697ad9d3a7 Technically GCC was wrong here, since opts_ini_parse is guranteed to change error. 2013-07-21 21:51:34 +00:00
Dale Weiler
764b9abaf4 Cleanups 2013-07-19 11:43:22 +00:00
Dale Weiler
84ad8ec37a Update gmqcc.ini.example 2013-07-04 15:24:55 -04:00
Wolfgang Bumiller
17318af62f fix typo 2013-07-01 10:37:51 +02:00
Wolfgang Bumiller
b39a748984 actually no :) 2013-06-22 20:31:50 +02:00
Dale Weiler
b534aca263 Fix a case of the uninitialized blues 2013-06-22 02:25:19 +00:00
Dale Weiler
adc9e7bf22 Fix some more bugs (coverity you're a life saver) 2013-06-22 02:05:04 +00:00
Dale Weiler
560b45dd16 Buffer overflow! 2013-06-22 01:58:20 +00:00
Dale Weiler
bbffdde2dc Fix some bugs and a memleak in the testsuite. 2013-06-22 01:56:22 +00:00
Dale Weiler
063c50fce4 More bug fixes and dead code elimination 2013-06-22 01:23:59 +00:00
Dale Weiler
5429b6f189 Fix out of bound access 2013-06-22 01:16:24 +00:00
Dale Weiler
d39fb653aa Fix some more bugs, and use dup2 because dup leaks on some implementations. 2013-06-22 01:14:13 +00:00
Dale Weiler
e08f00bfcd Update clean rules in makefiles to remove coverity stuff 2013-06-22 00:16:44 +00:00
Dale Weiler
edf59e4f73 Fixed possible bug in VM. Added coverity rules to makefiles. 2013-06-22 00:15:25 +00:00
Dale Weiler
52e7394418 Fix uninitialized data 2013-06-22 00:00:17 +00:00
Dale Weiler
a982d4e524 Fix a sizeof bug 2013-06-21 23:55:47 +00:00
Dale Weiler
458cfcb48c I'm assuming this is a bug since all other read tests compare with itself's ir_value, and only this one doesn't. Otherwise why would you need to load to an ir_value for vec? 2013-06-21 23:54:09 +00:00
Dale Weiler
5bdf0aff81 Catch that one too 2013-06-21 23:51:49 +00:00
Dale Weiler
1929b129ee Improper use of a possible negative value. 2013-06-21 23:49:08 +00:00
Dale Weiler
ce23e95d0b Remove a ton of dead code and document the one really insane case. 2013-06-21 23:40:51 +00:00
Dale Weiler
684112474b cppcheck had the right idea, but the wrong scope on this one. 2013-06-21 23:29:50 +00:00
Dale Weiler
fe296de42f Fix more bugs (mostly possible NULL pointer dereferences) 2013-06-21 23:26:49 +00:00
Dale Weiler
996d998ebb Fix possible NULL pointer dereference 2013-06-21 23:21:12 +00:00
Dale Weiler
125d039e3d Fix some bugs 2013-06-21 23:16:00 +00:00
Dale Weiler
6db2e69f9a Oh my god microsoft you suck 2013-06-20 11:20:56 +00:00
Dale Weiler
82fd7fcf68 Move code generator into ir_builder for earlier free. It's also a much more cleaner design than load parser->code for all ast/ir operations. We also have a proper chain'd design now (so making this a library will be easier). 2013-06-20 10:52:58 +00:00
Dale Weiler
a2c3388e49 Fix some comments 2013-06-18 07:31:09 +00:00
Dale Weiler
944ec75687 Retarded clang warning is retarded. 2013-06-18 07:26:07 +00:00
Dale Weiler
3b8b76328c Holy mexicans 15% better hashing == 5% faster compiles. 2013-06-18 07:22:03 +00:00
Dale Weiler
e6c1d66c35 Merge branch 'master' into cooking
Conflicts:
	opts.def
2013-06-17 20:14:26 +00:00
Dale Weiler
51eb94f251 Enable it for gmqcc and fteqcc modes. 2013-06-17 20:13:21 +00:00
Dale Weiler
7e76b42f11 Merge branch 'master' of github.com:graphitemaster/gmqcc 2013-06-17 20:12:02 +00:00
Dale Weiler
23cb7f4e09 Fix some bugs 2013-06-17 20:11:37 +00:00
Dale Weiler
a04c0d2aa2 make source a dependency for the c.o rule 2013-06-16 08:35:58 +00:00
Dale Weiler
ad8d76b212 Fixed 2013-06-16 08:24:13 +00:00
Dale Weiler
de8974d03e Use includes for makefile consistency. Added make depend rule for BSDmakefile. 2013-06-16 08:21:23 +00:00
Wolfgang Bumiller
f8db5a7c6d reclassify_token should only deal with tokens < TOKEN_START... should fix #113 2013-06-16 09:56:21 +02:00
Wolfgang Bumiller
e6bb7697f9 reclassify_token should only deal with tokens < TOKEN_START... should fix #113 2013-06-16 09:53:11 +02:00
Dale Weiler
a3e1342bdb Update 2013-06-16 07:51:55 +00:00
Dale Weiler
ba85107a85 Better scheme 2013-06-16 07:48:41 +00:00
Dale Weiler
0e392f91d2 A new batch of fresh hot dependencies for both 2013-06-16 07:23:51 +00:00
Dale Weiler
685925398c Dependency consistency 2013-06-16 07:22:37 +00:00
Dale Weiler
ec6de55d3c Update some things 2013-06-16 07:21:40 +00:00
Dale Weiler
00d1d237bc Update install file 2013-06-16 07:16:44 +00:00
Dale Weiler
6de7c45618 A Makefile for BSD make. 2013-06-16 07:08:07 +00:00
Dale Weiler
004832f6ec Make it compile with g++ again 2013-06-16 05:59:41 +00:00
Dale Weiler
82e92811e4 Uhh forgot to save file 2013-06-16 03:46:07 +00:00
Dale Weiler
9a6316221c Fix memleak 2013-06-16 03:45:06 +00:00
Dale Weiler
2d654ddcff Update 2013-06-16 02:48:31 +00:00
Dale Weiler
5d2b57394e Add the good old xor swap trick to the xor test, yes it works :P 2013-06-16 02:24:10 +00:00
Dale Weiler
17ae2dbe4d Make ^ legal for vector ^ vector, and vector ^ float (read the huge comment that explains why and what this does). Currently only works for constants (don't know how to do expression for multiple vector components yet). 2013-06-16 02:17:29 +00:00
Dale Weiler
a27b7ee6a5 Make them tests work now 2013-06-15 11:05:25 +00:00
Dale Weiler
5694c77d16 I added it for a reason, because I was smart. I forgot about it because of life :( 2013-06-15 11:04:08 +00:00
Dale Weiler
0c58509417 This is easier 2013-06-15 09:53:12 +00:00
Dale Weiler
202fc67f93 Correct order 2013-06-15 09:52:22 +00:00
Dale Weiler
b9cf1f1262 Fix bug 2013-06-15 09:50:02 +00:00
Dale Weiler
a8fddbb7d3 Implemented bitwise xor operator. 2013-06-15 09:48:40 +00:00
Dale Weiler
04406b191f Less terse, it confuses people. 2013-06-15 08:56:34 +00:00
Wolfgang Bumiller
290d065a79 again with the comments... 2013-06-15 09:49:15 +02:00
Wolfgang Bumiller
3fab06941a fix a call typecheck issue 2013-06-15 09:46:44 +02:00
Wolfgang Bumiller
f78d653b1e manpage update 2013-06-15 09:46:44 +02:00
Wolfgang Bumiller
179da9241c working on vararg piping: detecting several error cases, adding -Wunsafe-types and -funsafe-varargs 2013-06-15 09:46:44 +02:00
Dale Weiler
7115176c0e Strlen idiot 2013-06-15 07:42:01 +00:00
Dale Weiler
fee7794789 Limit corrections on strings to <= 16 bytes. Otherwise memory usage spikes instantly on errors, and causes Windows DEP to kill gmqcc. 2013-06-15 07:40:42 +00:00
Dale Weiler
5012616cb0 Limit corrections on strings to <= 16 bytes. Otherwise memory usage spikes instantly on errors, and causes Windows DEP to kill gmqcc. 2013-06-15 07:39:36 +00:00
Dale Weiler
90a016c6e0 Fix a possible issue 2013-06-15 05:28:38 +00:00
Dale Weiler
6617684a8d Some fixes 2013-06-15 02:25:19 +00:00
Dale Weiler
8afd373e4f Fixed whitespace 2013-06-14 21:36:16 +00:00
Dale Weiler
3e75750ad6 What the fuck are we talking about? 2013-06-14 21:26:33 +00:00
Dale Weiler
17fd017d6f Revert "Actually works now"
This reverts commit daa1487aef.
2013-06-13 22:23:07 +00:00
Dale Weiler
daa1487aef Actually works now 2013-06-13 22:20:17 +00:00
Wolfgang Bumiller
f023b7097f fix pedantic compile issue 2013-06-12 16:04:40 +02:00
Wolfgang Bumiller
2c59385633 fixing double-free in initialzied string arrays, using them in the testcase 2013-06-12 15:53:07 +02:00
Wolfgang Bumiller
b30368f026 array testcase for previous commit 2013-06-12 15:47:59 +02:00
Wolfgang Bumiller
8ce331b563 allow array size to be inferred from the initializer 2013-06-12 15:47:11 +02:00
Wolfgang Bumiller
dc91918c1f error about too many elements in initializer; added test for initialized arrays: arrays2.tmpl/qc 2013-06-12 14:41:38 +02:00
Wolfgang Bumiller
633d2ba8a4 make the ast use the initlist 2013-06-12 14:36:59 +02:00
Wolfgang Bumiller
bc4a66e9f7 setting initializing values 2013-06-12 14:32:34 +02:00
Wolfgang Bumiller
7a36a8bdd8 parsing array initializers 2013-06-12 14:32:12 +02:00
Wolfgang Bumiller
d631c517b6 forgot to add that one 2013-06-12 13:56:40 +02:00
Dale Weiler
b773702a47 Fix builds 2013-06-09 00:11:52 +00:00
Dale Weiler
0eab97283f Merge branch 'cooking'
Conflicts:
	.gitignore
2013-06-06 06:20:58 +00:00
Dale Weiler
ad92a5f27d Fix indexing 2013-06-06 06:20:11 +00:00
Dale Weiler
144672fada Strict prototyping 2013-06-06 02:51:13 +00:00
Dale Weiler
4f02d4b556 Update 2013-06-04 18:38:16 +00:00
Wolfgang Bumiller
923e0187bd Merge branch 'cooking' of git://github.com/graphitemaster/gmqcc into cooking 2013-06-04 20:36:58 +02:00
Wolfgang Bumiller
52d39b7260 slackware pkg build files 2013-06-04 20:32:06 +02:00
Dale Weiler
81b27ea84a Consistency 2013-06-04 18:07:18 +00:00
Dale Weiler
0d52f1ae7c Update changelog 2013-06-04 18:02:02 +00:00
Dale Weiler
0f98f0fd4a Some typos. 2013-06-04 17:44:45 +00:00
Dale Weiler
af80d9956b Gentoo ebuilds 2013-06-04 17:43:20 +00:00
Dale Weiler
e29b4d35b3 Add license header 2013-06-04 02:53:44 +00:00
Dale Weiler
77cf1f8685 Doh 2013-06-04 02:49:49 +00:00
Dale Weiler
11179a2a71 Major header reworking, this respects the namespaces properly. Makes object dependency more obvious, allows for better make caches, and prevents misuse of library features, i.e use con_* instead of printf. 2013-06-04 02:47:07 +00:00
Wolfgang Bumiller
b2348e1de0 remove the ast tree earlier - saves over 3% peak memory usage 2013-06-02 12:35:53 +02:00
Dale Weiler
06cccbb646 Fix a divide by zero error 2013-06-02 09:50:39 +00:00
Dale Weiler
c1a9ce3404 Fix output 2013-06-02 08:52:30 +00:00
Dale Weiler
c569e87bd0 Fix two bugs 2013-06-02 08:49:16 +00:00
Dale Weiler
100eaf9137 Merge pull request #112 from matthiaskrgr/master
mmmeeerging eeeet
2013-06-02 01:38:47 -07:00
Dale Weiler
ee42d2a570 Some cleanups 2013-06-02 08:37:22 +00:00
Dale Weiler
564cac859a Fix the peak 2013-06-02 08:28:56 +00:00
Matthias Krüger
69b55ccc03 gitignore: add gmqcc, gmqpak, qmcvm, testsuite, pak. 2013-06-02 10:26:27 +02:00
Dale Weiler
7ea67748fa Holy whoops 2013-06-02 08:25:00 +00:00
Dale Weiler
9af3c502da Major utility rewrite for compiler memory utilization statistics. Cleanups everywhere, no more NOTRACK stuff, all allocates are tracked. Major identifier cleanups as well. 2013-06-02 08:21:06 +00:00
Dale Weiler
ec7bf4767a Some static 2013-06-02 05:32:37 +00:00
Dale Weiler
1ce8d2ea6e Hashtable statistics too 2013-06-02 05:09:28 +00:00
Dale Weiler
f884bd2217 Track hashtables too 2013-06-02 04:45:04 +00:00
Dale Weiler
79a7aa70b9 Track strdups too in the statistics 2013-06-02 04:38:20 +00:00
Dale Weiler
c8daf483f3 This was an experiment that snuk it's way inside that commit. 2013-06-02 04:32:20 +00:00
Dale Weiler
166b79720c Vector tracing, step two in determining how to lower memory usage. 2013-06-02 04:29:53 +00:00
Dale Weiler
121e080697 Guart statistics by option. 2013-06-02 00:07:54 +00:00
Dale Weiler
280dfdd3f8 Add statistics for vector usage to the output. Step one in lowering memory usage. ONE FUCKING MILLION VECTORS for XONOTIC.. 2013-06-02 00:03:27 +00:00
Wolfgang Bumiller
d85e86141c fix a leak on a parse-error 2013-06-01 23:36:05 +02:00
Dale Weiler
655822ec1a Doh 2013-06-01 20:20:25 +00:00
Dale Weiler
062180e9a8 Fix some possible memleaks. 2013-06-01 20:18:53 +00:00
Wolfgang Bumiller
9f2b9e1b46 Merge branch 'master' into cooking 2013-06-01 20:12:27 +02:00
Wolfgang Bumiller
ff63e5bd73 fix the INCLUDE_DEF flag getting applied regardless of dotranslate... 2013-06-01 20:12:14 +02:00
Wolfgang Bumiller
1dce501b70 Merge branch 'master' into cooking 2013-06-01 18:16:56 +02:00
Wolfgang Bumiller
ed585f8c04 fix: dotranslate now sets AST_FLAG_INCLUDE_DEF to not get removed by -Ostrip-constant-names 2013-06-01 18:16:50 +02:00
Dale Weiler
b0a0769534 Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2013-05-30 19:36:37 +00:00
Dale Weiler
0b6269f607 column printing for warnings and errors now 2013-05-30 19:36:01 +00:00
Wolfgang Bumiller
ba781c53ef now a bare 'return;' is not required anymore if return has been assigned anywhere 2013-05-29 17:08:03 +02:00
Wolfgang Bumiller
a76702cb36 make sure missing return values still warn 2013-05-29 17:01:26 +02:00
Wolfgang Bumiller
5aba29006b return assignment factorial test 2013-05-29 16:58:18 +02:00
Wolfgang Bumiller
9167de1631 fixing that comment... 2013-05-29 16:56:39 +02:00
Wolfgang Bumiller
afdc0c9dc8 assignable return value now lives in ast_function, as globals can get overwritten randomly; removed parser_find_retval; updated parse_return 2013-05-29 16:51:59 +02:00
Dale Weiler
db6ca6c5f8 Make static 2013-05-29 11:32:42 +00:00
Dale Weiler
fd5506b376 Update test template. 2013-05-29 11:30:26 +00:00
Dale Weiler
1b71caa1fe Update man page 2013-05-29 11:29:52 +00:00
Dale Weiler
6d6a2efada Experimental support for implicit return assignments. This closes #107. To enable return assignment support use -freturn-assignments. This allows you to do the following in QC code. T name() { return = expr_eval_T; return; /* returns expr_eval_T */ }. It allows for concise code and to rid locals in functions. It also saves a tremendous amount of space since only types of certian globals need to be allocated for returns. 2013-05-29 11:13:42 +00:00
Dale Weiler
2923b718e1 Merge branch 'union-replacement' into cooking
Conflicts:
	ast.c
2013-05-29 03:43:49 +00:00
Dale Weiler
e3f4ae3038 Add back that splint flag 2013-05-29 03:39:38 +00:00
Dale Weiler
d45956f55e Fix that memory leak that I spent hours trying to find months ago and didn't succeed at. 2013-05-29 03:35:51 +00:00
Dale Weiler
f892b32335 Major export cleanup. Anything that was exported but wasn't used outside where it was implemented has been turned into static, and their exports have been removed. This actually makes the compiler compile slightly faster. 2013-05-29 03:29:04 +00:00
Dale Weiler
df8b486c98 Prevent negitive numbers from being used as the left operand of shift operator. 2013-05-29 02:37:45 +00:00
Dale Weiler
e02ebfe486 Result of shift operation on signed integers is bad. 2013-05-29 02:24:12 +00:00
Dale Weiler
f281de7a3c Cleanups and fixes 2013-05-29 02:16:50 +00:00
Wolfgang Bumiller
d70b571769 killing the union types 2013-05-11 22:34:01 +02:00
Wolfgang Bumiller
ef6e2bd583 first step to getting rid of those unions we don't use anyway 2013-05-11 22:05:30 +02:00
Wolfgang Bumiller
a0fa90ddd5 less confusing 2013-05-07 20:35:20 +02:00
Wolfgang Bumiller
802005f571 be more strict here 2013-05-07 20:13:19 +02:00
Wolfgang Bumiller
4d0a5af475 removing this dead code_init call 2013-05-07 19:59:06 +02:00
Wolfgang Bumiller
c5225b2fa1 fixing a few leaks - code_write doesn't delete the code object anymore, code_cleanup has to be called 2013-05-07 19:56:41 +02:00
Wolfgang Bumiller
8c8ae71d65 changing a few ast_delete to ast_unref in places where the to-be-deleted maybe coming from some other place 2013-05-07 19:39:10 +02:00
Wolfgang Bumiller
3e7cd8a98b Merge pull request #111 from matthiaskrgr/cooking_stuff
.gitignore: add binarys
2013-05-05 04:12:14 -07:00
Matthias Krüger
9823b294df .gitignore: add binarys 2013-05-05 12:53:58 +02:00
Dale Weiler
c07c78c666 Escape strings in executor for -printdefs 2013-05-02 19:18:59 +00:00
Dale Weiler
79a5ed0482 Implemented support for having codegen (and lno files) be wrote out to memory, this essentially allows us to embed the compiler in applications now. 2013-04-28 04:29:20 +00:00
Dale Weiler
721b581376 Fix deps (remove duplicates with clever make tricks) 2013-04-28 03:50:22 +00:00
Dale Weiler
3d115760a0 Merge branch 'cooking' of github.com:graphitemaster/gmqcc into cooking 2013-04-28 03:42:04 +00:00
Dale Weiler
a8e2a47da8 Less general name for PAK utility, added install targets for PAK utility, added manpag for PAK utility, this closes #108 2013-04-28 03:41:03 +00:00
Wolfgang Bumiller
f6792c3a05 Merge branch 'master' into cooking 2013-04-27 19:05:06 +02:00
Wolfgang Bumiller
bc4749d95a Merge pull request #109 from matthiaskrgr/PKGBUILD_master
PKGBUILD: archlinux: fix build by applying a patch (4c4aa5534c) on 0.2.9 package.
Accepting this with a patch in order for it to keep the 0.2.9 version info.
2013-04-27 10:04:43 -07:00
Matthias Krüger
90eed12e97 PKGBUILD: archlinux: fix build by applying a patch (4c4aa5534c) on 0.2.9 package. 2013-04-27 18:45:26 +02:00
Wolfgang Bumiller
2058ce69a4 Merge branch 'master' into cooking 2013-04-27 17:52:54 +02:00
Wolfgang Bumiller
4c4aa5534c dup is marked as warn-unused-result 2013-04-27 17:51:51 +02:00
Dale Weiler
dc6a7436ee Expression has undefined behavior (left operand modifies code->globals->used, used by right operand): (code->globals)[(((vector_t*)((void *)code->globals)) - 1)->used++] = (code_genstring(code, global->constval.vstring)) Code has unspecified behavior. Order of evaluation of function parameters or subexpressions is not defined, so if a value is used and modified in different places not separated by a sequence point constraining evaluation order, then the result of the expression is unspecified. 2013-04-27 15:20:01 +00:00
Wolfgang Bumiller
35120caf80 debian Makefile had the same flaw as archlinux/this... fixing 2013-04-27 17:00:27 +02:00
Wolfgang Bumiller
9ace0811ce Merge branch 'master' into cooking 2013-04-27 16:55:28 +02:00
Wolfgang Bumiller
d4b0e1f588 updating archbsd and archlinux release/PKGBUILD files 2013-04-27 16:54:53 +02:00
Wolfgang Bumiller
18cf3641b1 Merge branch 'master' into cooking 2013-04-27 16:33:55 +02:00
Wolfgang Bumiller
01ead27dd9 Update CHANGES file 2013-04-27 16:33:47 +02:00
Wolfgang Bumiller
b8e536d409 Starting point of 0.3.0 2013-04-27 16:30:35 +02:00
Wolfgang Bumiller
219508e478 this should be tagged 0.2.9 2013-04-27 16:30:03 +02:00
Wolfgang Bumiller
75ceab8f51 fix distro/ Makefiles 2013-04-26 17:56:08 +02:00
Wolfgang Bumiller
5007fd7f71 don't overwrite ldflags/libs env vars 2013-04-26 17:44:44 +02:00
Dale Weiler
50ff9e4fd0 Fix OSX compiles 2013-04-26 15:43:13 +00:00
Wolfgang Bumiller
7e0d6bdd87 don't overwrite ldflags/libs env vars 2013-04-26 17:33:56 +02:00
Wolfgang Bumiller
9f8bee4bf1 ast_value now has an initializer list array, still unused but it's there for later 2013-04-26 10:47:55 +02:00
Wolfgang Bumiller
b3e9ef3ad9 an = before an { is also always required when the declared variable is not a function; adding because of planned array initializers 2013-04-26 10:31:38 +02:00
Dale Weiler
1077eb2061 Add expressions for builtins test 2013-04-25 17:39:05 +00:00
Wolfgang Bumiller
d4f8e4a0dd solve it, not hide it 2013-04-25 19:18:50 +02:00
Wolfgang Bumiller
35692c0b57 Revert "Just fucking initialize everything"
This reverts commit aed2b1031c.
2013-04-25 19:18:11 +02:00
Wolfgang Bumiller
b9fb29d740 manpage and ini update 2013-04-25 19:17:58 +02:00
Dale Weiler
aed2b1031c Just fucking initialize everything 2013-04-25 17:11:15 +00:00
Dale Weiler
68ca2c4962 Pushing the -fexpressions-for-builtins stuff and the modff for catching fractional-part builtin numbers. 2013-04-25 17:08:02 +00:00
Wolfgang Bumiller
ce73074d51 this allows builtin numbers to be constant expressions, not just constants 2013-04-25 18:47:54 +02:00
Wolfgang Bumiller
c3f4b7153b change the value of TOKEN_EOF 2013-04-25 17:39:12 +02:00
Dale Weiler
2eddc464d5 Less extern 2013-04-25 12:22:34 +00:00
Dale Weiler
3d8e8cd80d cleaner 2013-04-25 12:08:43 +00:00
Dale Weiler
9fee84f250 less globals 2013-04-25 12:08:13 +00:00
Dale Weiler
785ab7c072 No more globals for codegen 2013-04-25 09:35:30 +00:00
164 changed files with 20098 additions and 19969 deletions

15
.gitignore vendored
View file

@ -1,14 +1,15 @@
*.o
*.d
*.orig
*.rej
*.patch
*.diff
*.exe
distro/archlinux/*
distro/archbsd/*
!distro/archlinux/git/PKGBUILD
!distro/archlinux/release/PKGBUILD
!distro/archbsd/release/PKGBUILD
!distro/archbsd/git/PKGBUILD
!distro/archlinux/this/Makefile
gmqcc
gmqpak
qcvm
testsuite
build/
.idea/

View file

@ -1,14 +0,0 @@
language: c
compiler:
- gcc
- clang
# Change this to your needs
script: make && make check
notifications:
irc:
channels:
- "irc.freenode.org#kf-engine"
template:
- "[%{commit} : %{author}] %{message}"
- "%{build_url}"
skip_join: true

View file

@ -1,9 +1,10 @@
Authors:
Dale Weiler - Charismatic Visionary / Programmer
Wolfgang Bumiller - Main Programmer
Dale `graphitemaster` Weiler - Charismatic Visionary / Programmer
Wolfgang `Blub\w` Bumiller - Main Programmer
Thanks to:
Forest `LordHavoc` Hale - Technical support and assistance
Rudolf `divVerent` Polzer - Technical support and assistance
Matthias `matthiaskrgr` Krüger - Miscellaneous assistance
Samual `Samual` Lenks - Preprocessor assistance
Igor `ignatenkobrain` Gnatenko - Fedora packages

90
CHANGES
View file

@ -1,90 +0,0 @@
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.
- Added generic attribute syntax and reintroduced `noreturn`
as [[noreturn]].
- Added [[deprecated]] and [[deprecated("message")]].
- Support for `static` variables in functions.
- Support for labeled loops.
- UTF-8 Support
- enum support: without enum-types
(ie no `typedef enum { } foo;`)
- Accessing vector components via the dot operator on all
expressions. Eg: (3 * v).y
- 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
variables on error.
- Some problems with VM related vector-instructions issues
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
- Compiler intrinsics: __builtin_floor, __builtin_mod,
__builtin_exp, __builtin_isnan
- Improved memory tracing
- Speed improvements
* QCVM:
- Improved commandline argument handling.
- More builtins: sqrt(), normalize(), floor()
* 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
* Crashes
2012-12-23 Hotfix v0.2.1
* General bugfixes
2012-12-23 Release 0.2
* Preprocessor:
- Added xonotic compatible preprocessor.
* Language
- Basic xonotic compatibility
- Array support
- Added fteqcc's string escape sequences.
- Support for `noref`.
- Support for `goto` with labels like in fteqcc.
- `break` and `continue`.
- Short circuit logic.
- Support for translatable strings via _("str") like in
fteqcc.
* Compilation
- Warnings about uninitialized values
2012-11-17 Release 0.1
* Compiles id1 code

35
CMakeLists.txt Normal file
View file

@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 2.8)
project(gmqcc)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
set(SOURCE_FILES
algo.h
ast.cpp ast.h
code.cpp
conout.cpp
fold.cpp fold.h
ftepp.cpp
gmqcc.h
intrin.cpp intrin.h
ir.cpp
ir.h
lexer.cpp lexer.h
opts.cpp
parser.cpp parser.h
stat.cpp
utf8.cpp
util.cpp)
add_library(gmqcclib ${SOURCE_FILES})
add_executable(gmqcc main.cpp)
target_link_libraries(gmqcc gmqcclib)
add_executable(testsuite test.cpp)
target_link_libraries(testsuite gmqcclib)
add_executable(qcvm exec.cpp)
target_link_libraries(qcvm gmqcclib)

44
INSTALL
View file

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

View file

@ -1,4 +1,4 @@
Copyright (C) 2012, 2013
Copyright (C) 2012, 2013, 2014, 2015
Dale Weiler
Wolfgang Bumiller

420
Makefile
View file

@ -1,266 +1,204 @@
DESTDIR :=
OPTIONAL:=
PREFIX := /usr/local
BINDIR := $(PREFIX)/bin
DATADIR := $(PREFIX)/share
MANDIR := $(DATADIR)/man
# Compilation options:
# * LTO - Link time optimization [default=0]
# * ASAN - Address sanitizer [default=0]
# * UBSAN - Undefined behavior sanitizer [default=0]
# * DEBUG - Debug build [default=0]
# * UNUSED - Remove unused references [default=1]
# * SRCDIR - Out of tree builds [default=./]
LTO ?= 0
ASAN ?= 0
UBSAN ?= 0
DEBUG ?= 0
UNUSED ?= 1
SRCDIR ?= ./
UNAME ?= $(shell uname)
CYGWIN = $(findstring CYGWIN, $(UNAME))
MINGW = $(findstring MINGW32, $(UNAME))
CC ?= clang
# linker flags and optional additional libraries if required
LDFLAGS :=
LIBS := -lm
CFLAGS += -Wall -Wextra -Werror -I. -fno-strict-aliasing $(OPTIONAL)
ifneq ($(shell git describe --always 2>/dev/null),)
CFLAGS += -DGMQCC_GITINFO="\"$(shell git describe --always)\""
endif
#turn on tons of warnings if clang is present
# 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-unknown-warning-option
# Determine if we're building for Windows or not so we can set the right file
# extensions for the binaries and exclude the testsuite because it doesn't build
# for that platform.
ifeq ($(OS),Windows_NT)
GMQCC := gmqcc.exe
QCVM := qcvm.exe
else
#Tiny C Compiler doesn't know what -pedantic-errors is
# and instead of ignoring .. just errors.
ifneq ($(CC), tcc)
CFLAGS +=-pedantic-errors -ffunction-sections -fdata-sections -Wl,-gc-sections
GMQCC := gmqcc
QCVM := qcvm
TESTSUITE := testsuite
endif
# C++ compiler
CXX ?= clang++
# Build artifact directories
OBJDIR := .build/objs
DEPDIR := .build/deps
# Collect all the source files for GMQCC.
GSRCS := ast.cpp
GSRCS += code.cpp
GSRCS += conout.cpp
GSRCS += fold.cpp
GSRCS += ftepp.cpp
GSRCS += intrin.cpp
GSRCS += ir.cpp
GSRCS += lexer.cpp
GSRCS += main.cpp
GSRCS += opts.cpp
GSRCS += parser.cpp
GSRCS += stat.cpp
GSRCS += utf8.cpp
GSRCS += util.cpp
# Collect all the source files for QCVM.
QSRCS := exec.cpp
QSRCS += stat.cpp
QSRCS += util.cpp
# Collect all the source files for TESTSUITE.
TSRCS := conout.cpp
TSRCS += opts.cpp
TSRCS += stat.cpp
TSRCS += test.cpp
TSRCS += util.cpp
#
# Compilation flags
#
CXXFLAGS := -Wall
CXXFLAGS += -Wextra
CXXFLAGS += -Wno-parentheses
CXXFLAGS += -Wno-class-memaccess
CXXFLAGS += -Wno-implicit-fallthrough
CXXFLAGS += -std=c++11
# Disable some unneeded features.
CXXFLAGS += -fno-exceptions
CXXFLAGS += -fno-rtti
CXXFLAGS += -fno-asynchronous-unwind-tables
# Give each function and data it's own section so the linker can remove unused
# references to each, producing smaller, tighter binaries.
ifeq ($(UNUSED),1)
CXXFLAGS += -ffunction-sections
CXXFLAGS += -fdata-sections
endif
# Enable link-time optimizations if requested.
ifeq ($(LTO),1)
CXXFLAGS += -flto
endif
ifeq ($(DEBUG),1)
# Ensure there is a frame-pointer in debug builds.
CXXFLAGS += -fno-omit-frame-pointer
# Disable all optimizations in debug builds.
CXXFLAGS += -O0
# Enable debug symbols.
CXXFLAGS += -g
else
# Disable all the stack protection features in release builds.
CXXFLAGS += -fno-stack-protector
CXXFLAGS += -fno-stack-check
# Disable frame pointer in release builds when AddressSanitizer isn't present.
ifeq ($(ASAN),1)
CXXFLAGS += -fno-omit-frame-pointer
else
CFLAGS += -Wno-pointer-sign -fno-common
CXXFLAGS += -fomit-frame-pointer
endif
# Highest optimization flag in release builds.
CXXFLAGS += -O3
endif
ifeq ($(track), no)
CFLAGS += -DNOTRACK
# Sanitizer selection
ifeq ($(ASAN),1)
CXXFLAGS += -fsanitize=address
endif
ifeq ($(UBSAN),1)
CXXFLAGS += -fsanitize=undefined
endif
OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o
OBJ_P = util.o fs.o conout.o opts.o pak.o
OBJ_T = test.o util.o conout.o fs.o
OBJ_C = main.o lexer.o parser.o fs.o
OBJ_X = exec-standalone.o util.o conout.o fs.o
#
# Dependency flags
#
DEPFLAGS := -MMD
DEPFLAGS += -MP
ifneq ("$(CYGWIN)", "")
#nullify the common variables that
#most *nix systems have (for windows)
PREFIX :=
BINDIR :=
DATADIR :=
MANDIR :=
QCVM = qcvm.exe
GMQCC = gmqcc.exe
TESTSUITE = testsuite.exe
PAK = pak.exe
#
# Linker flags
#
LDFLAGS :=
# Remove unreferenced sections
ifeq ($(UNUSED),1)
LDFLAGS += -Wl,--gc-sections
endif
# Enable link-time optimizations if request.
ifeq ($(LTO),1)
LDFLAGS += -flto
endif
# Sanitizer selection
ifeq ($(ASAN),1)
LDFLAGS += -fsanitize=address
endif
ifeq ($(UBSAN),1)
LDFLAGS += -fsanitize=undefined
endif
# Strip the binaries when not a debug build
ifneq (,$(findstring -g,$(CXXFLAGS)))
STRIP := true
else
ifneq ("$(MINGW)", "")
#nullify the common variables that
#most *nix systems have (for windows)
PREFIX :=
BINDIR :=
DATADIR :=
MANDIR :=
QCVM = qcvm.exe
GMQCC = gmqcc.exe
TESTSUITE = testsuite.exe
PAK = pak.exe
else
QCVM = qcvm
GMQCC = gmqcc
TESTSUITE = testsuite
PAK = pak
endif
STRIP := strip
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 \
--logo doc/html/gmqcc.png \
-1280x720
all: $(GMQCC) $(QCVM) $(TESTSUITE)
#ffmpeg flags for gource
FFMPEGFLAGS= \
-y \
-r 60 \
-f image2pipe \
-vcodec ppm \
-i - \
-vcodec libx264 \
-preset ultrafast \
-crf 1 \
-threads 0 \
-bf 0
# Build artifact directories.
$(DEPDIR):
@mkdir -p $(DEPDIR)
$(OBJDIR):
@mkdir -p $(OBJDIR)
#splint flags
SPLINTFLAGS = \
-redef \
-noeffect \
-nullderef \
-usedef \
-type \
-mustfreeonly \
-nullstate \
-varuse \
-mustfreefresh \
-compdestroy \
-compmempass \
-nullpass \
-onlytrans \
-predboolint \
-boolops \
-exportlocal \
-incondefs \
-macroredef \
-retvalint \
-nullret \
-predboolothers \
-globstate \
-dependenttrans \
-branchstate \
-compdef \
-temptrans \
-usereleased \
-warnposix \
-shiftimplementation \
+charindex \
-kepttrans \
-unqualifiedtrans \
+matchanyintegral \
+voidabstract \
-nullassign \
-unrecog \
-casebreak \
-retvalbool \
-retvalother \
-mayaliasunique \
-realcompare \
-observertrans \
-shiftnegative \
-freshtrans \
-abstract \
-statictrans \
-castfcnptr
$(OBJDIR)/%.o: %.cpp $(DEPDIR)/%.d | $(OBJDIR) $(DEPDIR)
$(CXX) -MT $@ $(DEPFLAGS) -MF $(DEPDIR)/$*.Td $(CXXFLAGS) -c -o $@ $<
@mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d
#standard rules
default: all
%.o: %.c
$(CC) -c $< -o $@ $(CPPFLAGS) $(CFLAGS)
$(GMQCC): $(filter %.o,$(GSRCS:%.cpp=$(OBJDIR)/%.o))
$(CXX) $^ $(LDFLAGS) -o $@
$(STRIP) $@
exec-standalone.o: exec.c
$(CC) -c $< -o $@ $(CPPFLAGS) $(CFLAGS) -DQCVM_EXECUTOR=1
$(QCVM): $(filter %.o,$(QSRCS:%.cpp=$(OBJDIR)/%.o))
$(CXX) $^ $(LDFLAGS) -o $@
$(STRIP) $@
$(QCVM): $(OBJ_X)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
$(TESTSUITE): $(filter %.o,$(TSRCS:%.cpp=$(OBJDIR)/%.o))
$(CXX) $^ $(LDFLAGS) -o $@
$(STRIP) $@
$(GMQCC): $(OBJ_C) $(OBJ_D)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
# Determine if the tests should be run.
RUNTESTS := true
ifdef TESTSUITE
RUNTESTS := ./$(TESTSUITE)
endif
$(TESTSUITE): $(OBJ_T)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
$(PAK): $(OBJ_P)
$(CC) -o $@ $^ $(LDFLAGS)
all: $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK)
check: all
@ ./$(TESTSUITE)
test: all
@ ./$(TESTSUITE)
test: $(QCVM) $(TESTSUITE)
@$(RUNTESTS)
clean:
rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat gource.mp4 *.exe
rm -rf $(DEPDIR) $(OBJDIR)
splint:
@ splint $(SPLINTFLAGS) *.c *.h
.PHONY: test clean $(DEPDIR) $(OBJDIR)
gource:
@ gource $(GOURCEFLAGS)
# Dependencies
$(filter %.d,$(GSRCS:%.cpp=$(DEPDIR)/%.d)):
include $(wildcard $@)
gource-record:
@ gource $(GOURCEFLAGS) -o - | ffmpeg $(FFMPEGFLAGS) gource.mp4
$(filter %.d,$(QSRCS:%.cpp=$(DEPDIR)/%.d)):
include $(wildcard $@)
depend:
@makedepend -Y -w 65536 2> /dev/null \
$(subst .o,.c,$(OBJ_D))
@makedepend -a -Y -w 65536 2> /dev/null \
$(subst .o,.c,$(OBJ_T))
@makedepend -a -Y -w 65536 2> /dev/null \
$(subst .o,.c,$(OBJ_C))
@makedepend -a -Y -w 65536 2> /dev/null \
$(subst .o,.c,$(OBJ_X))
@makedepend -a -Y -w 65536 2> /dev/null \
$(subst .o,.c,$(OBJ_P))
#install rules
install: install-gmqcc install-qcvm install-doc
install-gmqcc: $(GMQCC)
install -d -m755 $(DESTDIR)$(BINDIR)
install -m755 $(GMQCC) $(DESTDIR)$(BINDIR)/$(GMQCC)
install-qcvm: $(QCVM)
install -d -m755 $(DESTDIR)$(BINDIR)
install -m755 $(QCVM) $(DESTDIR)$(BINDIR)/$(QCVM)
install-doc:
install -d -m755 $(DESTDIR)$(MANDIR)/man1
install -m644 doc/gmqcc.1 $(DESTDIR)$(MANDIR)/man1/
install -m644 doc/qcvm.1 $(DESTDIR)$(MANDIR)/man1/
uninstall:
rm $(DESTDIR)$(BINDIR)/gmqcc
rm $(DESTDIR)$(BINDIR)/qcvm
rm $(DESTDIR)$(MANDIR)/man1/doc/gmqcc.1
rm $(DESTDIR)$(MANDIR)/man1/doc/qcvm.1
# DO NOT DELETE
util.o: gmqcc.h opts.def
code.o: gmqcc.h opts.def
ast.o: gmqcc.h opts.def ast.h ir.h
ir.o: gmqcc.h opts.def ir.h
conout.o: gmqcc.h opts.def
ftepp.o: gmqcc.h opts.def lexer.h
opts.o: gmqcc.h opts.def
fs.o: gmqcc.h opts.def
utf8.o: gmqcc.h opts.def
correct.o: gmqcc.h opts.def
test.o: gmqcc.h opts.def
util.o: gmqcc.h opts.def
conout.o: gmqcc.h opts.def
fs.o: gmqcc.h opts.def
main.o: gmqcc.h opts.def lexer.h
lexer.o: gmqcc.h opts.def lexer.h
parser.o: gmqcc.h opts.def lexer.h ast.h ir.h intrin.h
fs.o: gmqcc.h opts.def
util.o: gmqcc.h opts.def
conout.o: gmqcc.h opts.def
fs.o: gmqcc.h opts.def
util.o: gmqcc.h opts.def
fs.o: gmqcc.h opts.def
conout.o: gmqcc.h opts.def
opts.o: gmqcc.h opts.def
pak.o: gmqcc.h opts.def
$(filter %.d,$(TSRCS:%.cpp=$(DEPDIR)/%.d)):
include $(wildcard $@)

15
README
View file

@ -1,14 +1 @@
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 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
An improved QuakeC compiler

157
TODO
View file

@ -1,157 +0,0 @@
GMQCC is quite feature complete. But that doesn't address the fact that
it can be improved. This is a list of things that we'd like to support
in the distant future. When the time comes, we can just select a topic
from here and open a ticket for it on the issue tracker. But for the
meantime, this is sort of a cultivating flat file database.
Optimizations:
The following are optimizations that can be implemented after the
transformation into static-single assignment (SSA).
Global Value Numbering:
Eliminate redundancy by constructing a value graph of the source
then determining which values are computed by equivalent expressions.
Similar to Common Subexpression Elimination (CSE), however expressions
are determined via underlying equivalence, opposed to lexically identical
expressions (CSE).
Spare Conditional Constant Propagation:
Simultaneously remove dead code and propagates constants. This is
not the same as individual dead code elimination and constant propagation
passes. This is multipass.
The following are optimizations that can be implemented before the
transformation into a binary (code generator).
Code factoring:
The process of finding sequences of code that are identical,
or can be parameterized or reordered to be identical.
Which can be replaced with calls to a shared subroutine. To
reduce duplicated code. (Size optimization)
The following are optimizations that can be implemented anywhere, ideally
these are functional language optimizations.
Removing Recursion:
Tail recursive algorithms can be converted to iteration, which
does not have to have call overhead.
Language Features:
The following are language features that we'd like to see implemented in the
future.
Enumerations:
Like C
AST Macros:
Macros with sanity. Not textual substiution.
Classes:
Like C++, but minus the stupidity:
- No type operator overloads
- Keep operator overloading for basic operators though.
- No inheritance
- No virtuals / pure virtuals
- Essentially "C structs but with operators" :)
Arrays:
They're currently implemented, but support in the engine
plus implicit bounds checks (and ability to turn the bounds
checking off)
Exceptions:
I feel like all languages suck at implementing this. This would
require support from the engine, but it would help catch bugs. We
could make it fast using a neat method of "frame pointers".
Overloaded Functions:
Ability to make individual functions with the same name, but take
different amount of arguments or type of arguments.
Default Argument Substiution:
Ability to specify default values for arguments in functions.
void foo(string bar, string baz="default");
Supplying just one argument will expand the second argument to
become "default", otherwise if two arguments are specified then
the "default" string is overrode with what ever the user passes.
Character Type:
A char type would be nice to have. Essentially implemented as a
string, we can both "get" and "set" indices inside strings with
the help of builtin functions.
{
string foo = "test";
foo[0] = 'r';
print("it's time to ", foo);
}
Array Accessor With C-Semantics:
Also the ability to use them as array accessors:
{
float hugearray['Z'];
hugearray['a'] = 100.0f;
}
Keep existing "pointer-like" semantics as well. In C arrays
simple work as pointers, a[1] -> *(a+1), or 1[a] -> *(1+a)
so we should allow both forms of syntax. As well as operand
reversal.
{
float h['Z'];
*(h+'a') = 100;
*('a'+h) = 'a'[h];
}
FTEQCC Inline Assembly:
This is still up for debate, mainly because a) it's syntax is
just utter crap. b) If we do an assembler, it should be nice.
we could provide a -std=fteqcc for the assembler itself :P
just like the compiler; although I think that's just insane.
Please see Assembler below.
Namespaces:
There is already a ticket open on this. They'd work just like C++
identically even.
Standalone QCVM:
The following are QCVM additions:
Proper ASM disassembly:
Proper disassembly of compiled .dat files. Annotated if possible
when -g (is used during compilation)
Debugging:
A step-through debugger -d (with separate compilation as well)
Called -> qcdb Optionally alias to qcvm -d :)
We should be able to see the assembly and source it matches to
and the state of OFS_* and calls.
Testsuite:
The following are things we'd like to see added to the testsuite
in the distant future:
Multithreading:
Chances are when we start adding more and more tests, executing
them individually will be midly slow (even if that's a whole minute)
It would be nice to add a -j paramater to allow multiple threads to
be used and so we can execute many tests in parallel.
Interface:
Ability to select individual tests, or set parameters manually
opposed to using the static task-template files. (A method to
override them rather).
Assembler:
Possibly support for a future assembler for QCASM. But we're not
entirely sure if it makes sense.

18
algo.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef GMQCC_ALGO_HDR
#define GMQCC_ALGO_HDR
namespace algo {
template<typename ITER>
void shiftback(ITER element, ITER end) {
//typename ITER::value_type backup(move(*element)); // hold the element
typename std::remove_reference<decltype(*element)>::type backup(move(*element)); // hold the element
ITER p = element++;
for (; element != end; p = element++)
*p = move(*element);
*p = move(backup);
}
} // ::algo
#endif

3084
ast.c

File diff suppressed because it is too large Load diff

3125
ast.cpp Normal file

File diff suppressed because it is too large Load diff

859
ast.h

File diff suppressed because it is too large Load diff

278
code.c
View file

@ -1,278 +0,0 @@
/*
* Copyright (C) 2012, 2013
* Dale Weiler
* Wolfgang Bumiller
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "gmqcc.h"
prog_section_statement *code_statements;
int *code_linenums;
prog_section_def *code_defs;
prog_section_field *code_fields;
prog_section_function *code_functions;
int *code_globals;
char *code_chars;
uint16_t code_crc;
static uint32_t code_entfields;
/* This is outrageous! */
#define QCINT_ENTRY void*
#define QCINT_TO_HASH_ENTRY(q) ((void*)(uintptr_t)(q))
#define HASH_ENTRY_TO_QCINT(h) ((qcint)(uintptr_t)(h))
static ht code_string_cache;
static qcint code_string_cached_empty;
void code_push_statement(prog_section_statement *stmt, int linenum)
{
vec_push(code_statements, *stmt);
vec_push(code_linenums, linenum);
}
void code_pop_statement()
{
vec_pop(code_statements);
vec_pop(code_linenums);
}
void code_init() {
prog_section_function empty_function = {0,0,0,0,0,0,0,{0,0,0,0,0,0,0,0}};
prog_section_statement empty_statement = {0,{0},{0},{0}};
prog_section_def empty_def = {0, 0, 0};
int i = 0;
code_entfields = 0;
code_string_cache = util_htnew(OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS) ? 0x100 : 1024);
/*
* The way progs.dat is suppose to work is odd, there needs to be
* some null (empty) statements, functions, and 28 globals
*/
for(; i < 28; i++)
vec_push(code_globals, 0);
vec_push(code_chars, '\0');
vec_push(code_functions, empty_function);
code_push_statement(&empty_statement, 0);
vec_push(code_defs, empty_def);
vec_push(code_fields, empty_def);
}
void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin);
uint32_t code_genstring(const char *str)
{
uint32_t off;
size_t hash;
QCINT_ENTRY existing;
if (!str)
return 0;
if (!*str) {
if (!code_string_cached_empty) {
code_string_cached_empty = vec_size(code_chars);
vec_push(code_chars, 0);
}
return code_string_cached_empty;
}
if (OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS)) {
hash = ((unsigned char*)str)[strlen(str)-1];
existing = code_util_str_htgeth(code_string_cache, str, hash);
} else {
hash = util_hthash(code_string_cache, str);
existing = util_htgeth(code_string_cache, str, hash);
}
if (existing)
return HASH_ENTRY_TO_QCINT(existing);
off = vec_size(code_chars);
vec_upload(code_chars, str, strlen(str)+1);
util_htseth(code_string_cache, str, hash, QCINT_TO_HASH_ENTRY(off));
return off;
}
qcint code_alloc_field (size_t qcsize)
{
qcint pos = (qcint)code_entfields;
code_entfields += qcsize;
return pos;
}
bool code_write(const char *filename, const char *lnofile) {
prog_header code_header;
FILE *fp = NULL;
size_t it = 2;
code_header.statements.offset = sizeof(prog_header);
code_header.statements.length = vec_size(code_statements);
code_header.defs.offset = code_header.statements.offset + (sizeof(prog_section_statement) * vec_size(code_statements));
code_header.defs.length = vec_size(code_defs);
code_header.fields.offset = code_header.defs.offset + (sizeof(prog_section_def) * vec_size(code_defs));
code_header.fields.length = vec_size(code_fields);
code_header.functions.offset = code_header.fields.offset + (sizeof(prog_section_field) * vec_size(code_fields));
code_header.functions.length = vec_size(code_functions);
code_header.globals.offset = code_header.functions.offset + (sizeof(prog_section_function) * vec_size(code_functions));
code_header.globals.length = vec_size(code_globals);
code_header.strings.offset = code_header.globals.offset + (sizeof(int32_t) * vec_size(code_globals));
code_header.strings.length = vec_size(code_chars);
code_header.version = 6;
if (OPTS_OPTION_BOOL(OPTION_FORCECRC))
code_header.crc16 = OPTS_OPTION_U16(OPTION_FORCED_CRC);
else
code_header.crc16 = code_crc;
code_header.entfield = code_entfields;
if (OPTS_FLAG(DARKPLACES_STRING_TABLE_BUG)) {
util_debug("GEN", "Patching stringtable for -fdarkplaces-stringtablebug\n");
/* >= + P */
vec_push(code_chars, '\0'); /* > */
vec_push(code_chars, '\0'); /* = */
vec_push(code_chars, '\0'); /* P */
}
/* ensure all data is in LE format */
util_endianswap(&code_header.version, 1, sizeof(code_header.version));
util_endianswap(&code_header.crc16, 1, sizeof(code_header.crc16));
util_endianswap(&code_header.statements, 2, sizeof(code_header.statements.offset));
util_endianswap(&code_header.defs, 2, sizeof(code_header.statements.offset));
util_endianswap(&code_header.fields, 2, sizeof(code_header.statements.offset));
util_endianswap(&code_header.functions, 2, sizeof(code_header.statements.offset));
util_endianswap(&code_header.strings, 2, sizeof(code_header.statements.offset));
util_endianswap(&code_header.globals, 2, sizeof(code_header.statements.offset));
util_endianswap(&code_header.entfield, 1, sizeof(code_header.entfield));
util_endianswap(code_statements, vec_size(code_statements), sizeof(prog_section_statement));
util_endianswap(code_defs, vec_size(code_defs), sizeof(prog_section_def));
util_endianswap(code_fields, vec_size(code_fields), sizeof(prog_section_field));
util_endianswap(code_functions, vec_size(code_functions), sizeof(prog_section_function));
util_endianswap(code_globals, vec_size(code_globals), sizeof(int32_t));
if (lnofile) {
uint32_t version = 1;
fp = fs_file_open(lnofile, "wb");
if (!fp)
return false;
util_endianswap(&version, 1, sizeof(version));
util_endianswap(code_linenums, vec_size(code_linenums), sizeof(code_linenums[0]));
if (fs_file_write("LNOF", 4, 1, fp) != 1 ||
fs_file_write(&version, sizeof(version), 1, fp) != 1 ||
fs_file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
fs_file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
fs_file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
fs_file_write(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 ||
fs_file_write(code_linenums, sizeof(code_linenums[0]), vec_size(code_linenums), fp) != vec_size(code_linenums))
{
con_err("failed to write lno file\n");
}
fs_file_close(fp);
fp = NULL;
}
fp = fs_file_open(filename, "wb");
if (!fp)
return false;
if (1 != fs_file_write(&code_header, sizeof(prog_header) , 1 , fp) ||
vec_size(code_statements) != fs_file_write(code_statements, sizeof(prog_section_statement), vec_size(code_statements), fp) ||
vec_size(code_defs) != fs_file_write(code_defs, sizeof(prog_section_def) , vec_size(code_defs) , fp) ||
vec_size(code_fields) != fs_file_write(code_fields, sizeof(prog_section_field) , vec_size(code_fields) , fp) ||
vec_size(code_functions) != fs_file_write(code_functions, sizeof(prog_section_function) , vec_size(code_functions) , fp) ||
vec_size(code_globals) != fs_file_write(code_globals, sizeof(int32_t) , vec_size(code_globals) , fp) ||
vec_size(code_chars) != fs_file_write(code_chars, 1 , vec_size(code_chars) , fp))
{
fs_file_close(fp);
return false;
}
util_debug("GEN","HEADER:\n");
util_debug("GEN"," version: = %d\n", code_header.version );
util_debug("GEN"," crc16: = %d\n", code_header.crc16 );
util_debug("GEN"," entfield: = %d\n", code_header.entfield);
util_debug("GEN"," statements = {.offset = % 8d, .length = % 8d}\n", code_header.statements.offset, code_header.statements.length);
util_debug("GEN"," defs = {.offset = % 8d, .length = % 8d}\n", code_header.defs .offset, code_header.defs .length);
util_debug("GEN"," fields = {.offset = % 8d, .length = % 8d}\n", code_header.fields .offset, code_header.fields .length);
util_debug("GEN"," functions = {.offset = % 8d, .length = % 8d}\n", code_header.functions .offset, code_header.functions .length);
util_debug("GEN"," globals = {.offset = % 8d, .length = % 8d}\n", code_header.globals .offset, code_header.globals .length);
util_debug("GEN"," strings = {.offset = % 8d, .length = % 8d}\n", code_header.strings .offset, code_header.strings .length);
/* FUNCTIONS */
util_debug("GEN", "FUNCTIONS:\n");
for (; it < vec_size(code_functions); it++) {
size_t j = code_functions[it].entry;
util_debug("GEN", " {.entry =% 5d, .firstlocal =% 5d, .locals =% 5d, .profile =% 5d, .name =% 5d, .file =% 5d, .nargs =% 5d, .argsize ={%d,%d,%d,%d,%d,%d,%d,%d} }\n",
code_functions[it].entry,
code_functions[it].firstlocal,
code_functions[it].locals,
code_functions[it].profile,
code_functions[it].name,
code_functions[it].file,
code_functions[it].nargs,
code_functions[it].argsize[0],
code_functions[it].argsize[1],
code_functions[it].argsize[2],
code_functions[it].argsize[3],
code_functions[it].argsize[4],
code_functions[it].argsize[5],
code_functions[it].argsize[6],
code_functions[it].argsize[7]
);
util_debug("GEN", " NAME: %s\n", &code_chars[code_functions[it].name]);
/* Internal functions have no code */
if (code_functions[it].entry >= 0) {
util_debug("GEN", " CODE:\n");
for (;;) {
if (code_statements[j].opcode != INSTR_DONE)
util_debug("GEN", " %-12s {% 5i,% 5i,% 5i}\n",
asm_instr[code_statements[j].opcode].m,
code_statements[j].o1.s1,
code_statements[j].o2.s1,
code_statements[j].o3.s1
);
else {
util_debug("GEN", " DONE {0x00000,0x00000,0x00000}\n");
break;
}
j++;
}
}
}
vec_free(code_statements);
vec_free(code_linenums);
vec_free(code_defs);
vec_free(code_fields);
vec_free(code_functions);
vec_free(code_globals);
vec_free(code_chars);
util_htdel(code_string_cache);
fs_file_close(fp);
return true;
}

348
code.cpp Normal file
View file

@ -0,0 +1,348 @@
#include <string.h>
#include "gmqcc.h"
/*
* We could use the old method of casting to uintptr_t then to void*
* or qcint_t; however, it's incredibly unsafe for two reasons.
* 1) The compilers aliasing optimization can legally make it unstable
* (it's undefined behaviour).
*
* 2) The cast itself depends on fresh storage (newly allocated in which
* ever function is using the cast macros), the contents of which are
* transferred in a way that the obligation to release storage is not
* propagated.
*/
typedef union {
void *enter;
qcint_t leave;
} code_hash_entry_t;
/* Some sanity macros */
#define CODE_HASH_ENTER(ENTRY) ((ENTRY).enter)
#define CODE_HASH_LEAVE(ENTRY) ((ENTRY).leave)
void code_push_statement(code_t *code, prog_section_statement_t *stmt_in, lex_ctx_t ctx)
{
prog_section_statement_t stmt = *stmt_in;
if (OPTS_FLAG(TYPELESS_STORES)) {
switch (stmt.opcode) {
case INSTR_LOAD_S:
case INSTR_LOAD_ENT:
case INSTR_LOAD_FLD:
case INSTR_LOAD_FNC:
stmt.opcode = INSTR_LOAD_F;
break;
case INSTR_STORE_S:
case INSTR_STORE_ENT:
case INSTR_STORE_FLD:
case INSTR_STORE_FNC:
stmt.opcode = INSTR_STORE_F;
break;
case INSTR_STOREP_S:
case INSTR_STOREP_ENT:
case INSTR_STOREP_FLD:
case INSTR_STOREP_FNC:
stmt.opcode = INSTR_STOREP_F;
break;
}
}
if (OPTS_FLAG(SORT_OPERANDS)) {
uint16_t pair;
switch (stmt.opcode) {
case INSTR_MUL_F:
case INSTR_MUL_V:
case INSTR_ADD_F:
case INSTR_EQ_F:
case INSTR_EQ_S:
case INSTR_EQ_E:
case INSTR_EQ_FNC:
case INSTR_NE_F:
case INSTR_NE_V:
case INSTR_NE_S:
case INSTR_NE_E:
case INSTR_NE_FNC:
case INSTR_AND:
case INSTR_OR:
case INSTR_BITAND:
case INSTR_BITOR:
if (stmt.o1.u1 < stmt.o2.u1) {
uint16_t a = stmt.o2.u1;
stmt.o1.u1 = stmt.o2.u1;
stmt.o2.u1 = a;
}
break;
case INSTR_MUL_VF: pair = INSTR_MUL_FV; goto case_pair_gen;
case INSTR_MUL_FV: pair = INSTR_MUL_VF; goto case_pair_gen;
case INSTR_LT: pair = INSTR_GT; goto case_pair_gen;
case INSTR_GT: pair = INSTR_LT; goto case_pair_gen;
case INSTR_LE: pair = INSTR_GE; goto case_pair_gen;
case INSTR_GE: pair = INSTR_LE;
case_pair_gen:
if (stmt.o1.u1 < stmt.o2.u1) {
uint16_t x = stmt.o1.u1;
stmt.o1.u1 = stmt.o2.u1;
stmt.o2.u1 = x;
stmt.opcode = pair;
}
break;
}
}
code->statements.push_back(stmt);
code->linenums.push_back(ctx.line);
code->columnnums.push_back(ctx.column);
}
void code_pop_statement(code_t *code)
{
code->statements.pop_back();
code->linenums.pop_back();
code->columnnums.pop_back();
}
void *code_t::operator new(std::size_t bytes) {
return mem_a(bytes);
}
void code_t::operator delete(void *ptr) {
mem_d(ptr);
}
code_t::code_t()
{
static lex_ctx_t empty_ctx = {0, 0, 0};
static prog_section_function_t empty_function = {0,0,0,0,0,0,0,{0,0,0,0,0,0,0,0}};
static prog_section_statement_t empty_statement = {0,{0},{0},{0}};
static prog_section_def_t empty_def = {0, 0, 0};
string_cache = util_htnew(OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS) ? 0x100 : 1024);
// The way progs.dat is suppose to work is odd, there needs to be
// some null (empty) statements, functions, and 28 globals
globals.insert(globals.begin(), 28, 0);
chars.push_back('\0');
functions.push_back(empty_function);
code_push_statement(this, &empty_statement, empty_ctx);
defs.push_back(empty_def);
fields.push_back(empty_def);
}
code_t::~code_t()
{
util_htdel(string_cache);
}
void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin);
uint32_t code_genstring(code_t *code, const char *str) {
size_t hash;
code_hash_entry_t existing;
if (!str)
return 0;
if (!*str) {
if (!code->string_cached_empty) {
code->string_cached_empty = code->chars.size();
code->chars.push_back(0);
}
return code->string_cached_empty;
}
if (OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS)) {
hash = ((unsigned char*)str)[strlen(str)-1];
CODE_HASH_ENTER(existing) = code_util_str_htgeth(code->string_cache, str, hash);
} else {
hash = util_hthash(code->string_cache, str);
CODE_HASH_ENTER(existing) = util_htgeth(code->string_cache, str, hash);
}
if (CODE_HASH_ENTER(existing))
return CODE_HASH_LEAVE(existing);
CODE_HASH_LEAVE(existing) = code->chars.size();
code->chars.insert(code->chars.end(), str, str + strlen(str) + 1);
util_htseth(code->string_cache, str, hash, CODE_HASH_ENTER(existing));
return CODE_HASH_LEAVE(existing);
}
qcint_t code_alloc_field (code_t *code, size_t qcsize)
{
qcint_t pos = (qcint_t)code->entfields;
code->entfields += qcsize;
return pos;
}
static size_t code_size_generic(code_t *code, prog_header_t *code_header, bool lno) {
size_t size = 0;
if (lno) {
size += 4; /* LNOF */
size += sizeof(uint32_t); /* version */
size += sizeof(code_header->defs.length);
size += sizeof(code_header->globals.length);
size += sizeof(code_header->fields.length);
size += sizeof(code_header->statements.length);
size += sizeof(code->linenums[0]) * code->linenums.size();
size += sizeof(code->columnnums[0]) * code->columnnums.size();
} else {
size += sizeof(prog_header_t);
size += sizeof(prog_section_statement_t) * code->statements.size();
size += sizeof(prog_section_def_t) * code->defs.size();
size += sizeof(prog_section_field_t) * code->fields.size();
size += sizeof(prog_section_function_t) * code->functions.size();
size += sizeof(int32_t) * code->globals.size();
size += 1 * code->chars.size();
}
return size;
}
#define code_size_binary(C, H) code_size_generic((C), (H), false)
#define code_size_debug(C, H) code_size_generic((C), (H), true)
static void code_create_header(code_t *code, prog_header_t *code_header, const char *filename, const char *lnofile) {
size_t i;
code_header->statements.offset = sizeof(prog_header_t);
code_header->statements.length = code->statements.size();
code_header->defs.offset = code_header->statements.offset + (sizeof(prog_section_statement_t) * code->statements.size());
code_header->defs.length = code->defs.size();
code_header->fields.offset = code_header->defs.offset + (sizeof(prog_section_def_t) * code->defs.size());
code_header->fields.length = code->fields.size();
code_header->functions.offset = code_header->fields.offset + (sizeof(prog_section_field_t) * code->fields.size());
code_header->functions.length = code->functions.size();
code_header->globals.offset = code_header->functions.offset + (sizeof(prog_section_function_t) * code->functions.size());
code_header->globals.length = code->globals.size();
code_header->strings.offset = code_header->globals.offset + (sizeof(int32_t) * code->globals.size());
code_header->strings.length = code->chars.size();
code_header->version = 6;
code_header->skip = 0;
if (OPTS_OPTION_BOOL(OPTION_FORCECRC))
code_header->crc16 = OPTS_OPTION_U16(OPTION_FORCED_CRC);
else
code_header->crc16 = code->crc;
code_header->entfield = code->entfields;
if (OPTS_FLAG(DARKPLACES_STRING_TABLE_BUG)) {
/* >= + P */
code->chars.push_back('\0'); /* > */
code->chars.push_back('\0'); /* = */
code->chars.push_back('\0'); /* P */
}
/* ensure all data is in LE format */
util_swap_header(*code_header);
util_swap_statements(code->statements);
util_swap_defs_fields(code->defs);
util_swap_defs_fields(code->fields);
util_swap_functions(code->functions);
util_swap_globals(code->globals);
if (!OPTS_OPTION_BOOL(OPTION_QUIET)) {
if (lnofile)
con_out("writing '%s' and '%s'...\n", filename, lnofile);
else
con_out("writing '%s'\n", filename);
}
if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
{
char buffer[1024];
con_out("\nOptimizations:\n");
for (i = 0; i < COUNT_OPTIMIZATIONS; ++i) {
if (opts_optimizationcount[i]) {
util_optimizationtostr(opts_opt_list[i].name, buffer, sizeof(buffer));
con_out(
" %s: %u\n",
buffer,
(unsigned int)opts_optimizationcount[i]
);
}
}
}
}
static void code_stats(const char *filename, const char *lnofile, code_t *code, prog_header_t *code_header) {
if (OPTS_OPTION_BOOL(OPTION_QUIET) ||
OPTS_OPTION_BOOL(OPTION_PP_ONLY))
return;
con_out("\nFile statistics:\n");
con_out(" dat:\n");
con_out(" name: %s\n", filename);
con_out(" size: %u (bytes)\n", code_size_binary(code, code_header));
con_out(" crc: 0x%04X\n", code->crc);
if (lnofile) {
con_out(" lno:\n");
con_out(" name: %s\n", lnofile);
con_out(" size: %u (bytes)\n", code_size_debug(code, code_header));
}
con_out("\n");
}
bool code_write(code_t *code, const char *filename, const char *lnofile) {
prog_header_t code_header;
FILE *fp = nullptr;
code_create_header(code, &code_header, filename, lnofile);
if (lnofile) {
uint32_t version = 1;
fp = fopen(lnofile, "wb");
if (!fp)
return false;
util_endianswap(&version, 1, sizeof(version));
util_endianswap(&code->linenums[0], code->linenums.size(), sizeof(code->linenums[0]));
util_endianswap(&code->columnnums[0], code->columnnums.size(), sizeof(code->columnnums[0]));
if (fwrite("LNOF", 4, 1, fp) != 1 ||
fwrite(&version, sizeof(version), 1, fp) != 1 ||
fwrite(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
fwrite(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
fwrite(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
fwrite(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 ||
fwrite(&code->linenums[0], sizeof(code->linenums[0]), code->linenums.size(), fp) != code->linenums.size() ||
fwrite(&code->columnnums[0], sizeof(code->columnnums[0]), code->columnnums.size(), fp) != code->columnnums.size())
{
con_err("failed to write lno file\n");
}
fclose(fp);
fp = nullptr;
}
fp = fopen(filename, "wb");
if (!fp)
return false;
if (1 != fwrite(&code_header, sizeof(prog_header_t) , 1 , fp) ||
code->statements.size() != fwrite(&code->statements[0], sizeof(prog_section_statement_t), code->statements.size(), fp) ||
code->defs.size() != fwrite(&code->defs[0], sizeof(prog_section_def_t) , code->defs.size() , fp) ||
code->fields.size() != fwrite(&code->fields[0], sizeof(prog_section_field_t) , code->fields.size() , fp) ||
code->functions.size() != fwrite(&code->functions[0], sizeof(prog_section_function_t) , code->functions.size() , fp) ||
code->globals.size() != fwrite(&code->globals[0], sizeof(int32_t) , code->globals.size() , fp) ||
code->chars.size() != fwrite(&code->chars[0], 1 , code->chars.size() , fp))
{
fclose(fp);
return false;
}
fclose(fp);
code_stats(filename, lnofile, code, &code_header);
return true;
}

448
conout.c
View file

@ -1,448 +0,0 @@
/*
* 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.
*/
#include "gmqcc.h"
#include <stdio.h>
/*
* isatty/STDERR_FILENO/STDOUT_FILNO
* + some other things likewise.
*/
#ifndef _WIN32
# include <unistd.h>
#else
# include <io.h>
/*
* Windows and it's posix underscore bullshit. We simply fix this
* with yay, another macro :P
*/
# define isatty _isatty
#endif
#define GMQCC_IS_STDOUT(X) ((FILE*)((void*)X) == stdout)
#define GMQCC_IS_STDERR(X) ((FILE*)((void*)X) == stderr)
#define GMQCC_IS_DEFINE(X) (GMQCC_IS_STDERR(X) || GMQCC_IS_STDOUT(X))
typedef struct {
FILE *handle_err;
FILE *handle_out;
int color_err;
int color_out;
} con_t;
/*
* Doing colored output on windows is fucking stupid. The linux way is
* the real way. So we emulate it on windows :)
*/
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/*
* Windows doesn't have constants for FILENO, sadly but the docs tell
* use the constant values.
*/
#undef STDERR_FILENO
#undef STDOUT_FILENO
#define STDERR_FILENO 2
#define STDOUT_FILENO 1
enum {
RESET = 0,
BOLD = 1,
BLACK = 30,
RED,
GREEN,
YELLOW,
BLUE,
MAGENTA,
CYAN,
GRAY,
WHITE = GRAY
};
enum {
WBLACK,
WBLUE,
WGREEN = 2,
WRED = 4,
WINTENSE = 8,
WCYAN = WBLUE | WGREEN,
WMAGENTA = WBLUE | WRED,
WYELLOW = WGREEN | WRED,
WWHITE = WBLUE | WGREEN | WRED
};
static const int ansi2win[] = {
WBLACK,
WRED,
WGREEN,
WYELLOW,
WBLUE,
WMAGENTA,
WCYAN,
WWHITE
};
static int win_fputs(FILE *h, const char *str) {
/* state for translate */
int acolor;
int wcolor;
int icolor;
int state = 0;
/* attributes */
int intense = -1;
int colors[] = {-1, -1 };
int colorpos = 1;
int length = 0;
CONSOLE_SCREEN_BUFFER_INFO cinfo;
GetConsoleScreenBufferInfo (
(GMQCC_IS_STDOUT(h)) ?
GetStdHandle(STD_OUTPUT_HANDLE) :
GetStdHandle(STD_ERROR_HANDLE), &cinfo
);
icolor = cinfo.wAttributes;
while (*str) {
if (*str == '\x1B')
state = '\x1B';
else if (state == '\x1B' && *str == '[')
state = '[';
else if (state == '[') {
if (*str != 'm') {
colors[colorpos] = *str;
colorpos--;
} else {
int find;
int mult;
for (find = colorpos + 1, acolor = 0, mult = 1; find < 2; find++) {
acolor += (colors[find] - 48) * mult;
mult *= 10;
}
/* convert to windows color */
if (acolor == BOLD)
intense = WINTENSE;
else if (acolor == RESET) {
intense = WBLACK;
wcolor = icolor;
}
else if (BLACK <= acolor && acolor <= WHITE)
wcolor = ansi2win[acolor - 30];
else if (acolor == 90) {
/* special gray really white man */
wcolor = WWHITE;
intense = WBLACK;
}
SetConsoleTextAttribute (
(GMQCC_IS_STDOUT(h)) ?
GetStdHandle(STD_OUTPUT_HANDLE) :
GetStdHandle(STD_ERROR_HANDLE),
wcolor | intense | (icolor & 0xF0)
);
colorpos = 1;
state = -1;
}
} else {
fs_file_write(str, 1, 1, stdout);
length ++;
}
str++;
}
/* restore */
SetConsoleTextAttribute(
(GMQCC_IS_STDOUT(h)) ?
GetStdHandle(STD_OUTPUT_HANDLE) :
GetStdHandle(STD_ERROR_HANDLE),
icolor
);
return length;
}
#endif
/*
* We use standard files as default. These can be changed at any time
* with con_change(F, F)
*/
static con_t console;
/*
* Enables color on output if supported.
* NOTE: The support for checking colors is NULL. On windows this will
* always work, on *nix it depends if the term has colors.
*
* NOTE: This prevents colored output to piped stdout/err via isatty
* checks.
*/
static void con_enablecolor() {
if (console.handle_err == stderr || console.handle_err == stdout)
console.color_err = !!(isatty(STDERR_FILENO));
if (console.handle_out == stderr || console.handle_out == stdout)
console.color_out = !!(isatty(STDOUT_FILENO));
}
/*
* Does a write to the handle with the format string and list of
* arguments. This colorizes for windows as well via translate
* step.
*/
static int con_write(FILE *handle, const char *fmt, va_list va) {
int ln;
#ifndef _WIN32
ln = vfprintf(handle, fmt, va);
#else
{
char data[4096];
memset(data, 0, sizeof(data));
#ifdef _MSC_VER
vsnprintf_s(data, sizeof(data), sizeof(data), fmt, va);
#else
vsnprintf(data, sizeof(data), fmt, va);
#endif
ln = (GMQCC_IS_DEFINE(handle)) ? win_fputs(handle, data) : fs_file_puts(handle, data);
}
#endif
return ln;
}
/**********************************************************************
* EXPOSED INTERFACE BEGINS
*********************************************************************/
void con_close() {
if (!GMQCC_IS_DEFINE(console.handle_err))
fs_file_close(console.handle_err);
if (!GMQCC_IS_DEFINE(console.handle_out))
fs_file_close(console.handle_out);
}
void con_color(int state) {
if (state)
con_enablecolor();
else {
console.color_err = 0;
console.color_out = 0;
}
}
void con_init() {
console.handle_err = stderr;
console.handle_out = stdout;
con_enablecolor();
}
void con_reset() {
con_close();
con_init ();
}
/*
* This is clever, say you want to change the console to use two
* files for out/err. You pass in two strings, it will properly
* close the existing handles (if they're not std* handles) and
* open them. Now say you want TO use stdout and stderr, this
* allows you to do that so long as you cast them to (char*).
* Say you need stdout for out, but want a file for error, you can
* do this too, just cast the stdout for (char*) and stick to a
* string for the error file.
*/
int con_change(const char *out, const char *err) {
con_close();
if (!out) out = (const char *)((!console.handle_out) ? stdout : console.handle_out);
if (!err) err = (const char *)((!console.handle_err) ? stderr : console.handle_err);
if (GMQCC_IS_DEFINE(out)) {
console.handle_out = GMQCC_IS_STDOUT(out) ? stdout : stderr;
con_enablecolor();
} else if (!(console.handle_out = fs_file_open(out, "w"))) return 0;
if (GMQCC_IS_DEFINE(err)) {
console.handle_err = GMQCC_IS_STDOUT(err) ? stdout : stderr;
con_enablecolor();
} else if (!(console.handle_err = fs_file_open(err, "w"))) return 0;
return 1;
}
/*
* Defaultizer because stdio.h shouldn't be used anywhere except here
* and inside file.c To prevent mis-match of wrapper-interfaces.
*/
FILE *con_default_out() {
return (console.handle_out = stdout);
}
FILE *con_default_err() {
return (console.handle_err = stderr);
}
int con_verr(const char *fmt, va_list va) {
return con_write(console.handle_err, fmt, va);
}
int con_vout(const char *fmt, va_list va) {
return con_write(console.handle_out, fmt, va);
}
/*
* Standard stdout/stderr printf functions used generally where they need
* to be used.
*/
int con_err(const char *fmt, ...) {
va_list va;
int ln = 0;
va_start(va, fmt);
con_verr(fmt, va);
va_end (va);
return ln;
}
int con_out(const char *fmt, ...) {
va_list va;
int ln = 0;
va_start(va, fmt);
con_vout(fmt, va);
va_end (va);
return ln;
}
/*
* Utility console message writes for lexer contexts. These will allow
* for reporting of file:line based on lexer context, These are used
* heavily in the parser/ir/ast.
*/
void con_vprintmsg_c(int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap, const char *condname) {
/* color selection table */
static int sel[] = {
CON_WHITE,
CON_CYAN,
CON_RED
};
int err = !!(level == LVL_ERROR);
int color = (err) ? console.color_err : console.color_out;
int (*print) (const char *, ...) = (err) ? &con_err : &con_out;
int (*vprint)(const char *, va_list) = (err) ? &con_verr : &con_vout;
if (color)
print("\033[0;%dm%s:%d: \033[0;%dm%s: \033[0m", CON_CYAN, name, (int)line, sel[level], msgtype);
else
print("%s:%d: %s: ", name, (int)line, msgtype);
vprint(msg, ap);
if (condname)
print(" [%s]\n", condname);
else
print("\n");
}
void con_vprintmsg(int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap) {
con_vprintmsg_c(level, name, line, msgtype, msg, ap, NULL);
}
void con_printmsg(int level, const char *name, size_t line, const char *msgtype, const char *msg, ...) {
va_list va;
va_start(va, msg);
con_vprintmsg(level, name, line, msgtype, msg, va);
va_end (va);
}
void con_cvprintmsg(void *ctx, int lvl, const char *msgtype, const char *msg, va_list ap) {
con_vprintmsg(lvl, ((lex_ctx*)ctx)->file, ((lex_ctx*)ctx)->line, msgtype, msg, ap);
}
void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, ...) {
va_list va;
va_start(va, msg);
con_cvprintmsg(ctx, lvl, msgtype, msg, va);
va_end (va);
}
/* General error interface */
size_t compile_errors = 0;
size_t compile_warnings = 0;
size_t compile_Werrors = 0;
static lex_ctx first_werror;
void compile_show_werrors()
{
con_cprintmsg((void*)&first_werror, LVL_ERROR, "first warning", "was here");
}
void vcompile_error(lex_ctx ctx, const char *msg, va_list ap)
{
++compile_errors;
con_cvprintmsg((void*)&ctx, LVL_ERROR, "error", msg, ap);
}
void compile_error(lex_ctx ctx, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vcompile_error(ctx, msg, ap);
va_end(ap);
}
bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list ap)
{
const char *msgtype = "warning";
int lvl = LVL_WARNING;
char warn_name[1024];
if (!OPTS_WARN(warntype))
return false;
warn_name[0] = '-';
warn_name[1] = 'W';
(void)util_strtononcmd(opts_warn_list[warntype].name, warn_name+2, sizeof(warn_name)-2);
++compile_warnings;
if (OPTS_WERROR(warntype)) {
if (!compile_Werrors)
first_werror = ctx;
++compile_Werrors;
msgtype = "Werror";
if (OPTS_FLAG(BAIL_ON_WERROR)) {
msgtype = "error";
++compile_errors;
}
lvl = LVL_ERROR;
}
con_vprintmsg_c(lvl, ctx.file, ctx.line, msgtype, fmt, ap, warn_name);
return OPTS_WERROR(warntype) && OPTS_FLAG(BAIL_ON_WERROR);
}
bool GMQCC_WARN compile_warning(lex_ctx ctx, int warntype, const char *fmt, ...)
{
bool r;
va_list ap;
va_start(ap, fmt);
r = vcompile_warning(ctx, warntype, fmt, ap);
va_end(ap);
return r;
}

226
conout.cpp Normal file
View file

@ -0,0 +1,226 @@
#include <stdio.h>
#include "gmqcc.h"
#define GMQCC_IS_STDOUT(X) ((X) == stdout)
#define GMQCC_IS_STDERR(X) ((X) == stderr)
#define GMQCC_IS_DEFINE(X) (GMQCC_IS_STDERR(X) || GMQCC_IS_STDOUT(X))
struct con_t {
FILE *handle_err;
FILE *handle_out;
int color_err;
int color_out;
};
static con_t console;
/*
* Enables color on output if supported.
* NOTE: The support for checking colors is nullptr. On windows this will
* always work, on *nix it depends if the term has colors.
*
* NOTE: This prevents colored output to piped stdout/err via isatty
* checks.
*/
static void con_enablecolor(void) {
console.color_err = util_isatty(console.handle_err);
console.color_out = util_isatty(console.handle_out);
}
/*
* Does a write to the handle with the format string and list of
* arguments. This colorizes for windows as well via translate
* step.
*/
static int con_write(FILE *handle, const char *fmt, va_list va) {
return vfprintf(handle, fmt, va);
}
/**********************************************************************
* EXPOSED INTERFACE BEGINS
*********************************************************************/
void con_close() {
if (!GMQCC_IS_DEFINE(console.handle_err))
fclose(console.handle_err);
if (!GMQCC_IS_DEFINE(console.handle_out))
fclose(console.handle_out);
}
void con_color(int state) {
if (state)
con_enablecolor();
else {
console.color_err = 0;
console.color_out = 0;
}
}
void con_init() {
console.handle_err = stderr;
console.handle_out = stdout;
con_enablecolor();
}
void con_reset() {
con_close();
con_init();
}
/*
* Defaultizer because stdio.h shouldn't be used anywhere except here
* and inside file.c To prevent mis-match of wrapper-interfaces.
*/
FILE *con_default_out() {
return console.handle_out = stdout;
}
FILE *con_default_err() {
return console.handle_err = stderr;
}
int con_verr(const char *fmt, va_list va) {
return con_write(console.handle_err, fmt, va);
}
int con_vout(const char *fmt, va_list va) {
return con_write(console.handle_out, fmt, va);
}
/*
* Standard stdout/stderr printf functions used generally where they need
* to be used.
*/
int con_err(const char *fmt, ...) {
va_list va;
int ln = 0;
va_start(va, fmt);
con_verr(fmt, va);
va_end(va);
return ln;
}
int con_out(const char *fmt, ...) {
va_list va;
int ln = 0;
va_start(va, fmt);
con_vout(fmt, va);
va_end (va);
return ln;
}
/*
* Utility console message writes for lexer contexts. These will allow
* for reporting of file:line based on lexer context, These are used
* heavily in the parser/ir/ast.
*/
static void con_vprintmsg_c(int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap, const char *condname) {
/* color selection table */
static int sel[] = {
CON_WHITE,
CON_CYAN,
CON_RED
};
int err = !!(level == LVL_ERROR);
int color = (err) ? console.color_err : console.color_out;
int (*print) (const char *, ...) = (err) ? &con_err : &con_out;
int (*vprint)(const char *, va_list) = (err) ? &con_verr : &con_vout;
if (color)
print("\033[0;%dm%s:%d:%d: \033[0;%dm%s: \033[0m", CON_CYAN, name, (int)line, (int)column, sel[level], msgtype);
else
print("%s:%d:%d: %s: ", name, (int)line, (int)column, msgtype);
vprint(msg, ap);
if (condname)
print(" [%s]\n", condname);
else
print("\n");
}
void con_vprintmsg(int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap) {
con_vprintmsg_c(level, name, line, column, msgtype, msg, ap, nullptr);
}
void con_printmsg(int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...) {
va_list va;
va_start(va, msg);
con_vprintmsg(level, name, line, column, msgtype, msg, va);
va_end (va);
}
void con_cvprintmsg(lex_ctx_t ctx, int lvl, const char *msgtype, const char *msg, va_list ap) {
con_vprintmsg(lvl, ctx.file, ctx.line, ctx.column, msgtype, msg, ap);
}
void con_cprintmsg(lex_ctx_t ctx, int lvl, const char *msgtype, const char *msg, ...) {
va_list va;
va_start(va, msg);
con_cvprintmsg(ctx, lvl, msgtype, msg, va);
va_end (va);
}
/* General error interface: TODO seperate as part of the compiler front-end */
size_t compile_errors = 0;
size_t compile_warnings = 0;
size_t compile_Werrors = 0;
static lex_ctx_t first_werror;
void compile_show_werrors()
{
con_cprintmsg(first_werror, LVL_ERROR, "first warning", "was here");
}
void vcompile_error(lex_ctx_t ctx, const char *msg, va_list ap)
{
++compile_errors;
con_cvprintmsg(ctx, LVL_ERROR, "error", msg, ap);
}
void compile_error_(lex_ctx_t ctx, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vcompile_error(ctx, msg, ap);
va_end(ap);
}
bool GMQCC_WARN vcompile_warning(lex_ctx_t ctx, int warntype, const char *fmt, va_list ap)
{
const char *msgtype = "warning";
int lvl = LVL_WARNING;
char warn_name[1024];
if (!OPTS_WARN(warntype))
return false;
warn_name[0] = '-';
warn_name[1] = 'W';
(void)util_strtononcmd(opts_warn_list[warntype].name, warn_name+2, sizeof(warn_name)-2);
++compile_warnings;
if (OPTS_WERROR(warntype)) {
if (!compile_Werrors)
first_werror = ctx;
++compile_Werrors;
msgtype = "Werror";
if (OPTS_FLAG(BAIL_ON_WERROR)) {
msgtype = "error";
++compile_errors;
}
lvl = LVL_ERROR;
}
con_vprintmsg_c(lvl, ctx.file, ctx.line, ctx.column, msgtype, fmt, ap, warn_name);
return OPTS_WERROR(warntype) && OPTS_FLAG(BAIL_ON_WERROR);
}
bool GMQCC_WARN compile_warning_(lex_ctx_t ctx, int warntype, const char *fmt, ...)
{
bool r;
va_list ap;
va_start(ap, fmt);
r = vcompile_warning(ctx, warntype, fmt, ap);
va_end(ap);
return r;
}

547
correct.c
View file

@ -1,547 +0,0 @@
/*
* Copyright (C) 2012, 2013
* Dale Weiler
* Wolfgang Bumiller
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "gmqcc.h"
/*
* This is a very clever method for correcting mistakes in QuakeC code
* most notably when invalid identifiers are used or inproper assignments;
* we can proprly lookup in multiple dictonaries (depening on the rules
* of what the task is trying to acomplish) to find the best possible
* match.
*
*
* A little about how it works, and probability theory:
*
* When given an identifier (which we will denote I), we're essentially
* just trying to choose the most likely correction for that identifier.
* (the actual "correction" can very well be the identifier itself).
* There is actually no way to know for sure that certian identifers
* such as "lates", need to be corrected to "late" or "latest" or any
* other permutations that look lexically the same. This is why we
* must advocate the usage of probabilities. This means that instead of
* just guessing, instead we're trying to find the correction for C,
* out of all possible corrections that maximizes the probability of C
* for the original identifer I.
*
* Thankfully there exists some theroies for probalistic interpretations
* of data. Since we're operating on two distictive intepretations, the
* transposition from I to C. We need something that can express how much
* degree of I should rationally change to become C. this is called the
* Bayesian interpretation. You can read more about it from here:
* http://www.celiagreen.com/charlesmccreery/statistics/bayestutorial.pdf
* (which is probably the only good online documentation for bayes theroy
* no lie. Everything else just sucks ..)
*
* Bayes' Thereom suggests something like the following:
* AC P(I|C) P(C) / P(I)
*
* However since P(I) is the same for every possibility of I, we can
* completley ignore it giving just:
* AC P(I|C) P(C)
*
* This greatly helps visualize how the parts of the expression are performed
* there is essentially three, from right to left we perform the following:
*
* 1: P(C), the probability that a proposed correction C will stand on its
* own. This is called the language model.
*
* 2: P(I|C), the probability that I would be used, when the programmer
* really meant C. This is the error model.
*
* 3: AC, the control mechanisim, an enumerator if you will, one that
* enumerates all feasible values of C, to determine the one that
* gives the greatest probability score.
*
* In reality the requirement for a more complex expression involving
* two seperate models is considerably a waste. But one must recognize
* that P(C|I) is already conflating two factors. It's just much simpler
* to seperate the two models and deal with them explicitaly. To properly
* estimate P(C|I) you have to consider both the probability of C and
* probability of the transposition from C to I. It's simply much more
* cleaner, and direct to seperate the two factors.
*
* Research tells us that 80% to 95% of all spelling errors have an edit
* distance no greater than one. Knowing this we can optimize for most
* cases of mistakes without taking a performance hit. Which is what we
* base longer edit distances off of. Opposed to the original method of
* I had concieved of checking everything.
*
* A little information on additional algorithms used:
*
* Initially when I implemented this corrector, it was very slow.
* Need I remind you this is essentially a brute force attack on strings,
* and since every transformation requires dynamic memory allocations,
* you can easily imagine where most of the runtime conflated. Yes
* It went right to malloc. More than THREE MILLION malloc calls are
* performed for an identifier about 16 bytes long. This was such a
* shock to me. A forward allocator (or as some call it a bump-point
* allocator, or just a memory pool) was implemented. To combat this.
*
* But of course even other factors were making it slow. Initially
* this used a hashtable. And hashtables have a good constant lookup
* time complexity. But the problem wasn't in the hashtable, it was
* in the hashing (despite having one of the fastest hash functions
* known). Remember those 3 million mallocs? Well for every malloc
* there is also a hash. After 3 million hashes .. you start to get
* very slow. To combat this I had suggested burst tries to Blub.
* The next day he had implemented them. Sure enough this brought
* down the runtime by a factor > 100%
*
* The trie initially was designed to work on all strings, but later it
* became aparent that not only was this not a requirement. It was also
* slowing down get/sets' for the trie. To fully understand, only
* correct_alpha needs to be understood by the trie system, knowing this
* We can combat the slowness using a very clever but evil optimization.
* By Setting a fixed sized amount of branches for the trie using a
* char-to-index map into the branches. We've complelty made the trie
* accesses entierly constant in lookup time. No really, a lookup is
* literally trie[str[0]] [str[1]] [2] .... .value.
*
*
* Future Work (If we really need it)
*
* Currently we can only distinguish one source of error in the
* language model we use. This could become an issue for identifiers
* that have close colliding rates, e.g colate->coat yields collate.
*
* Currently the error model has been fairly trivial, the smaller the
* edit distance the smaller the error. This usually causes some un-
* expected problems. e.g reciet->recite yields recipt. For QuakeC
* this could become a problem when lots of identifiers are involved.
*/
#define CORRECT_POOL_SIZE (128*1024*1024)
/*
* A forward allcator for the corrector. This corrector requires a lot
* of allocations. This forward allocator combats all those allocations
* and speeds us up a little. It also saves us space in a way since each
* allocation isn't wasting a little header space for when NOTRACK isn't
* defined.
*/
static unsigned char **correct_pool_data = NULL;
static unsigned char *correct_pool_this = NULL;
static size_t correct_pool_addr = 0;
static GMQCC_INLINE void correct_pool_new(void) {
correct_pool_addr = 0;
correct_pool_this = (unsigned char *)mem_a(CORRECT_POOL_SIZE);
vec_push(correct_pool_data, correct_pool_this);
}
static GMQCC_INLINE void *correct_pool_alloc(size_t bytes) {
void *data;
if (correct_pool_addr + bytes>= CORRECT_POOL_SIZE)
correct_pool_new();
data = (void*)correct_pool_this;
correct_pool_this += bytes;
correct_pool_addr += bytes;
return data;
}
static GMQCC_INLINE void correct_pool_delete(void) {
size_t i;
for (i = 0; i < vec_size(correct_pool_data); ++i)
mem_d(correct_pool_data[i]);
correct_pool_data = NULL;
correct_pool_this = NULL;
correct_pool_addr = 0;
}
static GMQCC_INLINE char *correct_pool_claim(const char *data) {
char *claim = util_strdup(data);
return claim;
}
/*
* _ is valid in identifiers. I've yet to implement numerics however
* because they're only valid after the first character is of a _, or
* alpha character.
*/
static const char correct_alpha[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"_"; /* TODO: Numbers ... */
static const size_t correct_alpha_index[0x80] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 52,
0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0
};
/*
* A fast space efficent trie for a dictionary of identifiers. This is
* faster than a hashtable for one reason. A hashtable itself may have
* fast constant lookup time, but the hash itself must be very fast. We
* have one of the fastest hash functions for strings, but if you do a
* lost of hashing (which we do, almost 3 million hashes per identifier)
* a hashtable becomes slow.
*/
correct_trie_t* correct_trie_new() {
correct_trie_t *t = (correct_trie_t*)mem_a(sizeof(correct_trie_t));
t->value = NULL;
t->entries = NULL;
return t;
}
static GMQCC_INLINE void correct_trie_del_sub(correct_trie_t *t) {
size_t i;
if (!t->entries)
return;
for (i = 0; i < sizeof(correct_alpha)-1; ++i) {
correct_trie_del_sub(&t->entries[i]);
}
mem_d(t->entries);
}
static GMQCC_INLINE void correct_trie_del(correct_trie_t *t) {
size_t i;
if (t->entries) {
for (i = 0; i < sizeof(correct_alpha)-1; ++i)
correct_trie_del_sub(&t->entries[i]);
mem_d(t->entries);
}
mem_d(t);
}
static GMQCC_INLINE void* correct_trie_get(const correct_trie_t *t, const char *key) {
const unsigned char *data = (const unsigned char*)key;
while (*data) {
if (!t->entries)
return NULL;
t = t->entries + correct_alpha_index[*data];
++data;
}
return t->value;
}
static GMQCC_INLINE void correct_trie_set(correct_trie_t *t, const char *key, void * const value) {
const unsigned char *data = (const unsigned char*)key;
while (*data) {
if (!t->entries) {
t->entries = (correct_trie_t*)mem_a(sizeof(correct_trie_t)*(sizeof(correct_alpha)-1));
memset(t->entries, 0, sizeof(correct_trie_t)*(sizeof(correct_alpha)-1));
}
t = t->entries + correct_alpha_index[*data];
++data;
}
t->value = value;
}
/*
* Implementation of the corrector algorithm commences. A very efficent
* brute-force attack (thanks to tries and mempool :-)).
*/
static GMQCC_INLINE size_t *correct_find(correct_trie_t *table, const char *word) {
return (size_t*)correct_trie_get(table, word);
}
static GMQCC_INLINE bool correct_update(correct_trie_t* *table, const char *word) {
size_t *data = correct_find(*table, word);
if (!data)
return false;
(*data)++;
return true;
}
void correct_add(correct_trie_t* table, size_t ***size, const char *ident) {
size_t *data = NULL;
const char *add = ident;
if (!correct_update(&table, add)) {
data = (size_t*)mem_a(sizeof(size_t));
*data = 1;
vec_push((*size), data);
correct_trie_set(table, add, data);
}
}
void correct_del(correct_trie_t* dictonary, size_t **data) {
size_t i;
const size_t vs = vec_size(data);
for (i = 0; i < vs; i++)
mem_d(data[i]);
vec_free(data);
correct_trie_del(dictonary);
}
/*
* correcting logic for the following forms of transformations:
* 1) deletion
* 2) transposition
* 3) alteration
* 4) insertion
*
* These functions could take an additional size_t **size paramater
* and store back the results of their new length in an array that
* is the same as **array for the memcmp in correct_exists. I'm just
* not able to figure out how to do that just yet. As my brain is
* not in the mood to figure out that logic. This is a reminder to
* do it, or for someone else to :-) correct_edit however would also
* need to take a size_t ** to carry it along (would all the argument
* overhead be worth it?)
*/
static GMQCC_INLINE size_t correct_deletion(const char *ident, char **array) {
size_t itr = 0;
const size_t len = strlen(ident);
for (; itr < len; itr++) {
char *a = (char*)correct_pool_alloc(len+1);
memcpy(a, ident, itr);
memcpy(a + itr, ident + itr + 1, len - itr);
array[itr] = a;
}
return itr;
}
static GMQCC_INLINE size_t correct_transposition(const char *ident, char **array) {
size_t itr = 0;
const size_t len = strlen(ident);
for (; itr < len - 1; itr++) {
char tmp;
char *a = (char*)correct_pool_alloc(len+1);
memcpy(a, ident, len+1);
tmp = a[itr];
a[itr ] = a[itr+1];
a[itr+1] = tmp;
array[itr] = a;
}
return itr;
}
static GMQCC_INLINE size_t correct_alteration(const char *ident, char **array) {
size_t itr = 0;
size_t jtr = 0;
size_t ktr = 0;
const size_t len = strlen(ident);
for (; itr < len; itr++) {
for (jtr = 0; jtr < sizeof(correct_alpha)-1; jtr++, ktr++) {
char *a = (char*)correct_pool_alloc(len+1);
memcpy(a, ident, len+1);
a[itr] = correct_alpha[jtr];
array[ktr] = a;
}
}
return ktr;
}
static GMQCC_INLINE size_t correct_insertion(const char *ident, char **array) {
size_t itr = 0;
size_t jtr = 0;
const size_t len = strlen(ident);
for (; itr <= len; itr++) {
for (jtr = 0; jtr < sizeof(correct_alpha)-1; jtr++) {
char *a = (char*)correct_pool_alloc(len+2);
memcpy(a, ident, itr);
memcpy(a + itr + 1, ident + itr, len - itr + 1);
a[itr] = correct_alpha[jtr];
array[itr * (sizeof(correct_alpha)-1) + jtr] = a;
}
}
return (len+1)*(sizeof(correct_alpha)-1);
}
static GMQCC_INLINE size_t correct_size(const char *ident) {
/*
* deletion = len
* transposition = len - 1
* alteration = len * sizeof(correct_alpha)
* insertion = (len + 1) * sizeof(correct_alpha)
*/
register size_t len = strlen(ident);
return (len) + (len - 1) + (len * (sizeof(correct_alpha)-1)) + ((len + 1) * (sizeof(correct_alpha)-1));
}
static GMQCC_INLINE char **correct_edit(const char *ident, size_t **lens) {
size_t next;
size_t size = correct_size(ident);
char **find = (char**)correct_pool_alloc(size * sizeof(char*));
if (!find || !(*lens = (size_t*)correct_pool_alloc(size * sizeof(size_t))))
return NULL;
next = correct_deletion (ident, find);
next += correct_transposition(ident, find+next);
next += correct_alteration (ident, find+next);
/*****/ correct_insertion (ident, find+next);
/* precompute lengths */
for (next = 0; next < size; next++)
(*lens)[next] = strlen(find[next]);
return find;
}
static GMQCC_INLINE int correct_exist(char **array, register size_t *sizes, size_t rows, char *ident, register size_t len) {
size_t itr;
for (itr = 0; itr < rows; itr++) {
/*
* We can save tons of calls to memcmp if we simply ignore comparisions
* that we know cannot contain the same length.
*/
if (sizes[itr] == len && !memcmp(array[itr], ident, len))
return 1;
}
return 0;
}
static GMQCC_INLINE char **correct_known_resize(char **res, size_t *allocated, size_t size) {
size_t oldallocated = *allocated;
char **out;
if (size < oldallocated)
return res;
out = (char**)correct_pool_alloc(sizeof(*res) * oldallocated + 32);
memcpy(out, res, sizeof(*res) * oldallocated);
*allocated += 32;
return out;
}
static char **correct_known(correction_t *corr, correct_trie_t* table, char **array, size_t rows, size_t *next) {
size_t itr = 0;
size_t jtr = 0;
size_t len = 0;
size_t row = 0;
size_t nxt = 8;
char **res = (char**)correct_pool_alloc(sizeof(char *) * nxt);
char **end = NULL;
size_t *bit = NULL;
for (; itr < rows; itr++) {
if (!array[itr][0])
continue;
if (vec_size(corr->edits) > itr+1) {
end = corr->edits[itr+1];
bit = corr->lens [itr+1];
} else {
end = correct_edit(array[itr], &bit);
vec_push(corr->edits, end);
vec_push(corr->lens, bit);
}
row = correct_size(array[itr]);
for (jtr = 0; jtr < row; jtr++) {
if (correct_find(table, end[jtr]) && !correct_exist(res, bit, len, end[jtr], bit[jtr])) {
res = correct_known_resize(res, &nxt, len+1);
res[len++] = end[jtr];
}
}
}
*next = len;
return res;
}
static GMQCC_INLINE char *correct_maximum(correct_trie_t* table, char **array, size_t rows) {
char *str = NULL;
size_t *itm = NULL;
size_t itr = 0;
size_t top = 0;
for (; itr < rows; itr++) {
if ((itm = correct_find(table, array[itr])) && (*itm > top)) {
top = *itm;
str = array[itr];
}
}
return str;
}
/*
* This is the exposed interface:
* takes a table for the dictonary a vector of sizes (used for internal
* probability calculation), and an identifier to "correct".
*/
void correct_init(correction_t *c)
{
correct_pool_new();
c->edits = NULL;
c->lens = NULL;
}
void correct_free(correction_t *c)
{
vec_free(c->edits);
vec_free(c->lens);
correct_pool_delete();
}
char *correct_str(correction_t *corr, correct_trie_t* table, const char *ident) {
char **e1 = NULL;
char **e2 = NULL;
char *e1ident = NULL;
char *e2ident = NULL;
size_t e1rows = 0;
size_t e2rows = 0;
size_t *bits = NULL;
/* needs to be allocated for free later */
if (correct_find(table, ident))
return correct_pool_claim(ident);
if ((e1rows = correct_size(ident))) {
if (vec_size(corr->edits) > 0)
e1 = corr->edits[0];
else {
e1 = correct_edit(ident, &bits);
vec_push(corr->edits, e1);
vec_push(corr->lens, bits);
}
if ((e1ident = correct_maximum(table, e1, e1rows)))
return correct_pool_claim(e1ident);
}
e2 = correct_known(corr, table, e1, e1rows, &e2rows);
if (e2rows && ((e2ident = correct_maximum(table, e2, e2rows))))
return correct_pool_claim(e2ident);
return util_strdup(ident);
}

View file

@ -1,53 +0,0 @@
DROPBOX := dropbox_uploader.sh
UNAME := $(shell uname -m)
DOWNLOAD:= ../doc/html/download.c
BRANCH := $(shell git branch | sed -n -e 's/^\* \(.*\)/\1/p')
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
$(MAKE) -C win32/
@mv deb/*.deb ./
@mv archlinux/this/*pkg.tar.xz ./
@mv win32/*.zip ./
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\|zip\)" -exec ./$$(basename $(DROPBOX)) upload {} \;
@rm dropbox_config dropbox_uploader.sh
website:
$(CC) $(DOWNLOAD) -o html.gen
@./html.gen ../
@rm html.gen
@git stash
@git checkout gh-pages
@rm -f ../download.html
@mv -f download.html ../download.html
@cd ..; git add download.html; git commit -m 'update download page'; git push origin gh-pages;
@git checkout $(BRANCH)
@git stash apply
clean:
@rm -f *.deb
@rm -f *.pkg.tar.xz
@rm -f *.zip
@rm -f *.gen
@rm -f *.html
all: base upload

View file

@ -1,55 +0,0 @@
# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
# Contributor: Wolfgang Bumiller <blub@speed.at>
pkgname=gmqcc-git
pkgver=20130127
pkgrel=1
pkgdesc="An Improved Quake C Compiler"
arch=('i686' 'x86_64')
depends=()
conflicts=('gmqcc')
provides=('gmqcc=0.2.4')
makedepends=('git')
url="https://github.com/graphitemaster/gmqcc.git"
license=('MIT')
_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"
msg "Compiling..."
gmake
}
check() {
cd "$srcdir"/"$_gitname"
gmake check
}
package() {
cd "$srcdir"/"$_gitname"
msg "Compiling and installing to pkgdir this time..."
gmake install DESTDIR=$pkgdir PREFIX=/usr
msg "Compiling done."
install -dm755 ${pkgdir}/usr/share/licenses/gmqcc
install -m644 LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
}

View file

@ -1,38 +0,0 @@
# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
# Contributor: Wolfgang Bumiller <blub@speed.at>
pkgname=gmqcc
pkgver=0.2.2
pkgrel=1
pkgdesc="An Improved Quake C Compiler"
arch=('i686' 'x86_64')
depends=()
url="https://github.com/graphitemaster/gmqcc.git"
license=('MIT')
source=(gmqcc-$pkgver.zip::https://github.com/graphitemaster/gmqcc/zipball/$pkgver)
sha1sums=('8cd91dc13f70cd9d3767602bf3eb47a1906d9353')
_gitname=graphitemaster-gmqcc-de24486/
build() {
msg "Starting compilation..."
cd "$srcdir"/"$_gitname"
msg "Compiling..."
gmake
}
check() {
cd "$srcdir"/"$_gitname"
gmake check
}
package() {
cd "$srcdir"/"$_gitname"
msg "Compiling and installing to pkgdir this time..."
gmake install DESTDIR=$pkgdir PREFIX=/usr
msg "Compiling done."
install -dm755 ${pkgdir}/usr/share/licenses/gmqcc
install -m644 LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
}

View file

@ -1,48 +0,0 @@
# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
pkgname=gmqcc-git
pkgver=0.2.612.g160e7cf
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')
depends=('glibc')
conflicts=('gmqcc')
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')
build() {
msg "Starting compilation..."
cd "$srcdir"/"gmqcc"
msg "Compiling..."
make
}
check() {
cd "$srcdir"/"gmqcc"
make check
}
package() {
cd "$srcdir"/"gmqcc"
msg "Compiling and installing to pkgdir this time..."
make install DESTDIR=$pkgdir PREFIX=/usr
msg "Compiling done."
install -Dm644 syntax/geany/filetypes.qc ${pkgdir}/usr/share/geany/filetypes.qc
install -Dm644 syntax/gtksourceview/qc.lang ${pkgdir}/usr/share/gtksourceview-3.0/language-specs/qc.lang
# jedit
install -Dm644 syntax/kate/qc.xml ${pkgdir}/usr/share/apps/katepart/syntax/qc.xml
install -Dm644 syntax/nano/qc.nanorc ${pkgdir}/usr/share/nano/qc.nanorc
install -Dm644 LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
}

View file

@ -1,36 +0,0 @@
# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
pkgname=gmqcc
pkgver=0.2.2
pkgrel=1
pkgdesc="An Improved Quake C Compiler"
arch=('i686' 'x86_64')
depends=('glibc')
url="https://github.com/graphitemaster/gmqcc.git"
license=('MIT')
source=(gmqcc-$pkgver.zip::https://github.com/graphitemaster/gmqcc/zipball/$pkgver)
sha1sums=('e0fe99af9a55d36cd9e0909a96d1b14f2db8b757')
_gitname=graphitemaster-gmqcc-de24486/
build() {
msg "Starting compilation..."
cd "$srcdir"/"$_gitname"
msg "Compiling..."
make
}
check() {
cd "$srcdir"/"$_gitname"
make check
}
package() {
cd "$srcdir"/"$_gitname"
msg "Compiling and installing to pkgdir this time..."
make install DESTDIR=$pkgdir PREFIX=/usr
msg "Compiling done."
install -D LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
}

View file

@ -1,48 +0,0 @@
BASEDIR := ../../../
PREFIX := /usr
HEADER := $(BASEDIR)/gmqcc.h
MAJOR := $(shell sed -n -e '/GMQCC_VERSION_MAJOR/{s/.* .* //;p;q;}' $(HEADER))
MINOR := $(shell sed -n -e '/GMQCC_VERSION_MINOR/{s/.* .* //;p;q;}' $(HEADER))
PATCH := $(shell sed -n -e '/GMQCC_VERSION_PATCH/{s/.* .* //;p;q;}' $(HEADER))
PKGREL := 1
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 :=
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)
@echo "url = https://github.com/graphitemaster/gmqcc.git" >> $(PKGINFO)
@echo "builddate = `date -u \"+%s\"`" >> $(PKGINFO)
@echo "packager = Unknown Packager" >> $(PKGINFO)
@echo "size = `du -sk $(PKGDIR) | awk '{print $$1 * 1024}'`" >> $(PKGINFO)
@echo "arch = $(CARCH)" >> $(PKGINFO)
@echo "license = MIT" >> $(PKGINFO)
@echo "conflict = gmqcc" >> $(PKGINFO)
@echo "depend = glibc" >> $(PKGINFO)
@echo "makepkgopt = strip" >> $(PKGINFO)
@echo "makepkgopt = docs" >> $(PKGINFO)
@echo "makepkgopt = libtool" >> $(PKGINFO)
@echo "makepkgopt = emptydirs" >> $(PKGINFO)
@echo "makepkgopt = zipman" >> $(PKGINFO)
@echo "makepkgopt = purge" >> $(PKGINFO)
@echo "makepkgopt = !upx" >> $(PKGINFO)
@tar -cJvf $(PKG) -C $(PKGDIR)/ .PKGINFO usr/
@rm -rf $(PKGDIR)
clean:
$(MAKE) -C $(BASEDIR) clean
@rm -f *.pkg.tar.xz
all: base

View file

@ -1,43 +0,0 @@
BASEDIR := ../..
PREFIX := /usr
HEADER := $(BASEDIR)/gmqcc.h
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)
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
@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:
$(MAKE) -C $(BASEDIR) clean
@rm -f *.deb
all: base

View file

@ -1,17 +0,0 @@
BASEDIR := ../..
HEADER := $(BASEDIR)/gmqcc.h
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)`
BINDIR := gmqcc-$(MAJOR).$(MINOR).$(PATCH)
base:
$(MAKE) CC=i486-mingw32-gcc UNAME=MINGW32 -C $(BASEDIR) clean
$(MAKE) CC=i486-mingw32-gcc UNAME=MINGW32 -C $(BASEDIR) DESTDIR=distro/win32/$(BINDIR) PREFIX=/ install
@zip -r $(BINDIR)-win32.zip $(BINDIR)
@rm -rf $(BINDIR)
clean:
$(MAKE) -C $(BASEDIR) clean
@rm -f *.zip
all: base

View file

@ -153,7 +153,7 @@ Adds compiler information to the generated binary file. Currently
this includes the following globals:
.Bl -tag -width indent -compact
.It Li reserved:version
String containing the compiler version as printed by the --version
String containing the compiler version as printed by the \-\-version
parameter.
.El
.It Fl -correct , Fl -no-correct
@ -168,6 +168,11 @@ DEBUG OPTION. Print the code's intermediate representation after the
optimization and finalization passes to stdout before generating the
binary. The instructions will be enumerated, and values will contain a
list of liferanges.
.It Fl force-crc= Ns Ar CRC
Force the produced progs file to use the specified CRC.
.It Fl state-fps= Ns Ar NUM
Activate \-femulate-state and set the emulated FPS to
.Ar NUM Ns .
.El
.Sh COMPILE WARNINGS
.Bl -tag -width Ds
@ -181,6 +186,9 @@ variables can be opened using
.Ql #pragma noref 1
and closed via
.Ql #pragma noref 0 Ns .
.It Fl W Ns Cm unused-component
Generate a warning about vector variables which are declared but not all their
components are used.
.It Fl W Ns Cm used-uninitialized
Generate a warning if it is possible that a variable can be used
without prior initialization. Note that this warning is not
@ -320,6 +328,34 @@ marked as such.
Warn about possible mistakes caused by missing or wrong parenthesis,
like an assignment in an 'if' condition when there's no additional set
of parens around the assignment.
.It Fl W Ns Cm unsafe-types
When passing variadic parameters via
.Li ...(N)
it can happen that incompatible types are passed to functions. This
enables several warnings when static typechecking cannot guarantee
consistent behavior.
.It Fl W Ns Cm breakdef
When compiling original id1 QC there is a definition for `break`
which conflicts with the 'break' keyword in GMQCC. Enabling this
will print a warning when the definition occurs. The definition is
ignored for both cases.
.It Fl W Ns Cm const-overwrite
When compiling original QuakeWorld QC there are instances where
code overwrites constants. This is considered an error, however
for QuakeWorld to compile it needs to be treated as a warning
instead, as such this warning only works when \-std=qcc.
.It Fl W Ns Cm directive-inmacro
Warn about the use of preprocessor directives inside macros.
.It Fl W Ns Cm builtins
When using a function that is not explicitly defined, the compiler
will search its intrinsics table for something that matches that
function name by appending "__builtin_" to it. This behaviour may
be unexpected, so enabling this will produce a diagnostic when
such a function is resolved to a builtin.
.It Fl W Ns Cm inexact-compares
When comparing an inexact value such as `1.0/3.0' the result is
pathologically wrong. Enabling this will trigger a compiler warning
on such expressions.
.El
.Sh COMPILE FLAGS
.Bl -tag -width Ds
@ -340,7 +376,7 @@ features used in the Xonotic codebase. If you need more, write a
ticket.
.It Fl f Ns Cm ftepp-predefs
Enable some predefined macros. This only works in combination with
\'-fftepp' and is currently not included by '-std=fteqcc'. The
\'\-fftepp' and is currently not included by '\-std=fteqcc'. The
following macros will be added:
.Bd -literal -offset indent
__LINE__
@ -373,6 +409,45 @@ only the first component will be 0, while the other two will become
the first to of the global return value. This behavior is odd and
relying on it should be discouraged, and thus is not supported by
gmqcc.
.It Fl f Ns Cm ftepp-mathdefs
Enable math constant definitions. This only works in combination
with \'\-fftepp' and is currently not included by '\-std=fteqcc'.
The following macros will be added:
.Bd -literal -offset indent
M_E
M_LOG2E
M_LOG10E
M_LN2
M_LN10
M_PI
M_PI_2
M_PI_4
M_1_PI
M_2_PI
M_2_SQRTPI
M_SQRT2
M_SQRT1_2
M_TAU
.Ed
.It Fl f Ns Cm ftepp-indirect-expansion
Enable indirect macro expansion. This only works in combination
with '-fftepp' and is currently not included by '-std=fteqcc'.
Enabling this behavior will allow the preprocessor to operate more
like the standard C preprocessor in that it will allow arguments
of macros which are macro-expanded to be substituted into the
definition of the macro.
.Pp
As an example:
.Bd -literal -offset indent
#define STR1(x) #x
#define STR2(x) STR1(x)
#define THE_ANSWER 42
#define THE_ANSWER_STR STR2(THE_ANSWER) /* "42" */
.Ed
With this enabled, an expansion of THE_ANSWER_STR will yield
the string "42". With this disabled an expansion of THE_ANSWER_STR
will yield "THE_ANSWER"
.It Fl f Ns Cm relaxed-switch
Allow switch cases to use non constant variables.
.It Fl f Ns Cm short-logic
@ -497,6 +572,69 @@ void vafunc(string...count) {
Most Quake VMs, including the one from FTEQW or up till recently
Darkplaces, do not cope well with vector instructions with overlapping
input and output. This option will avoid producing such code.
.It Fl f Ns Cm expressions-for-builtins
Usually builtin-numbers are just immediate constants. With this flag
expressions can be used, as long as they are compile-time constant.
.Pp
Example:
.Bd -literal -offset indent
void printA() = #1; // the usual way
void printB() = #2-1; // with a constant expression
.Ed
.It Fl f Ns Cm return-assignments
Enabiling this option will allow assigning values or expressions to the
return keyword as if it were a local variable of the same type as the
function's signature's return type.
.Pp
Example:
.Bd -literal -offset indent
float bar() { return 1024; }
float fun() {
return = bar();
return; // returns value of bar
}
.Ed
.It Fl f Ns Cm unsafe-varargs
When passing on varargs to a different functions, this turns some
static error cases into warnings. Like when the caller's varargs are
restricted to a different type than the callee's parameter. Or a list
of unrestricted varargs is passed into restricted varargs.
.It Fl f Ns Cm typeless-stores
Always use STORE_F, LOAD_F, STOREP_F when accessing scalar variables.
This is somewhat incorrect assembly instruction use, but in all engines
they do exactly the same. This makes disassembly output harder to read,
breaks decompilers, but causes the output file to be better compressible.
.It Fl f Ns Cm sort-operands
In commutative instructions, always put the lower-numbered operand first.
This shaves off 1 byte of entropy from all these instructions, reducing
compressed size of the output file.
.It Fl f Ns Cm emulate-state
Emulate OP_STATE operations in code rather than using the instruction.
The desired fps can be set via -state-fps=NUM, defaults to 10.
Specifying \-state-fps implicitly sets this flag. Defaults to off in all
standards.
.It Fl f Ns Cm arithmetic-exceptions
Turn on arithmetic exception tests in the compiler. In constant expressions
which trigger exceptions like division by zero, overflow, underflow, etc,
the following flag will produce diagnostics for what triggered that
exception.
.It Fl f Ns Cm split-vector-parameters
With this flag immediate vector literals which only ever appear as function
parameters won't be stored as vector immediates. Instead, the 3 floats making
up the vector will be copied separately. Essentially this turns a vector-store
instruction into 3 float-store instructions for such cases. This increases
code size but can dramatically reduce the amount of vector globals, which is
after all limited to 64k. There's at least one known codebase where this
lowers the number of globals from over 80k down to around 3k. In other code
bases it doesn't reduce the globals at all but only increases code size.
Just try it and see whether it helps you.
.It Fl f Ns Cm default-eraseable
Force all expressions to be "eraseable" which permits the compiler to
remove unused functions, variables and statements. This is equivlant to
putting [[eraseable]] on all definitions. This is dangerous as it breaks
auto cvars, definitions for functions the engine may be looking for and
translatable strings. Instead, you can mark a definition with [[noerase]]
to prevent this from happening.
.El
.Sh OPTIMIZATIONS
.Bl -tag -width Ds
@ -541,7 +679,7 @@ string being added.
.Pp
For example the following code will only generate 1 string:
.Bd -literal -offset indent
print("Hell you!\\n");
print("Hello you!\\n");
print("you!\\n"); // trailing substring of "Hello you!\\n"
.Ed
.Pp
@ -573,6 +711,10 @@ in this case, the y component of a vector. This optimization will turn
such a multiplication into a direct component access. If the factor is
anything other than 1, a float-multiplication will be added, which is
still faster than a vector multiplication.
.It Fl O Ns Cm const-fold-dce
For constant expressions that result in dead code (such as a branch whos
condition can be evaluated at compile-time), this will eliminate the branch
and else body (if present) to produce more optimal code.
.El
.Sh CONFIG
The configuration file is similar to regular .ini files. Comments
@ -622,7 +764,7 @@ A documented example for a gmqcc.ini file.
.Sh AUTHOR
See <http://graphitemaster.github.com/gmqcc>.
.Sh BUGS
Currently the '-fftepp-predefs' flag is not included by '-std=fteqcc',
Currently the '\-fftepp-predefs' flag is not included by '\-std=fteqcc',
partially because it is not entirely conformant to fteqcc.
.Pp
Please report bugs on <http://github.com/graphitemaster/gmqcc/issues>,

View file

@ -1,284 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/*
* protect some information, not that I care, but this is just to stay
* safer.
*/
#define SECURITY_BASE "\
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
#define SECURITY_TOKEN "\
P29hdXRoX2NvbnN1bWVyX2tleT03NnZoM3E0Mmhudm16bTMmb2F1dGhfdG9rZW49\
dzBieHpmMGRmdDhlZGZxJm9hdXRoX3NpZ25hdHVyZV9tZXRob2Q9UExBSU5URVhU\
Jm9hdXRoX3NpZ25hdHVyZT10bWVlY2h0MmNtaDcyeGElMjY5dm9zeDd4OGd5NGtn\
amsmb2F1dGhfdGltZXN0YW1wPSZvYXV0aF9ub25jZT0xMjE2NQo="
int isbase64(char c) {
return !!(c && strchr(SECURITY_BASE, c) != NULL);
}
char value(char c) {
const char *load = SECURITY_BASE;
const char *find = strchr(load, c);
return (find) ? find - load : 0;
}
int security_decode(unsigned char *dest, const unsigned char *src, int srclen) {
unsigned char *p;
if(!*src)
return 0;
*dest = 0;
p = dest;
do {
*p++ = (value(src[0]) << 2) | (value(src[1]) >> 4);
*p++ = (value(src[1]) << 4) | (value(src[2]) >> 2);
*p++ = (value(src[2]) << 6) | (value(src[3]) >> 0);
if(!isbase64(src[1])) {
p -= 2;
break;
}
else if(!isbase64(src[2])) {
p -= 2;
break;
}
else if(!isbase64(src[3])) {
p--;
break;
}
src += 4;
while(*src && (*src == 13 || *src == 10))
src++;
} while(srclen-= 4);
*p = 0;
return p-dest;
}
#define BASEURL " https://api-content.dropbox.com/1/files/sandbox/"
/*
* If more platforms are supported add the entries between the start
* tag here, and the end tag below. Nothing else needs to be done
* <tag> (the table needs to match the HTML too)
*/
#define ARCHLINUX_32_REF "%sgmqcc-%c.%c.%c-1-i686.pkg.tar.xz%s"
#define ARCHLINUX_64_REF "%sgmqcc-%c.%c.%c-1-x86_64.pkg.tar.xz%s"
#define DEBIAN_32_REF "%sgmqcc-%c.%c.%c-i686.deb%s"
#define DEBIAN_64_REF "%sgmqcc-%c.%c.%c-x86_64.deb%s"
#define WINDOWS_32_REF "%sgmqcc-%c.%c.%c-win32.zip%s"
#define WINDOWS_64_REF "%sgmqcc-%c.%c.%c-win64.zip%s"
#define HTML "\
<!doctype html>\
<html>\
<head>\
<meta charset=\"utf-8\">\
<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\">\
<title>GMQCC</title>\
<link rel=\"stylesheet\" href=\"stylesheets/styles.css\">\
<link rel=\"stylesheet\" href=\"stylesheets/pygment_trac.css\">\
<script src=\"javascripts/scale.fix.js\"></script>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\
<!--[if lt IE 9]>\
<script src=\"//html5shiv.googlecode.com/svn/trunk/html5.js\"></script>\
<![endif]-->\
</head>\
<body>\
<a href=\"https://github.com/graphitemaster/gmqcc\"><div class=\"fork\"></div></a>\
<div class=\"wrapper\">\
<header>\
<h1 class=\"header\">GMQCC</h1>\
<p class=\"header\">An Improved Quake C Compiler</p>\
<ul>\
<li class=\"buttons\"><a href=index.html>Index</a></li>\
<li class=\"download\"><a href=\"download.html\">Download</a></li>\
<li class=\"buttons\"><a href=\"https://github.com/graphitemaster/gmqcc/issues\">Issues</a></li>\
<li class=\"buttons\"><a href=\"doc.html\">Documentation</a></li>\
<li class=\"buttons\"><a href=\"https://github.com/graphitemaster/gmqcc\">View On GitHub</a></li>\
</ul>\
</header>\
<section>\
<table>\
<tr>\
<th>Operating System / Distribution</th>\
<th>x86 Architecture</th>\
<th>x86_64 Architecture</th>\
</tr>\
<tr>\
<td>Archlinux</td>\
<td><a href=\"%s\">Download</a></td>\
<td><a href=\"%s\">Download</a></td>\
</tr>\
<tr>\
<td>Debian</td>\
<td><a href=\"%s\">Download</a></td>\
<td><a href=\"%s\">Download</a></td>\
</tr>\
<tr>\
<td>Windows</td>\
<td><a href=\"%s\">Download</a></td>\
<td><a href=\"%s\">Download</a></td>\
</tr>\
</table>\
</section>\
<footer>\
<script type=\"text/javascript\" src=\"http://www.ohloh.net/p/602517/widgets/project_partner_badge.js\"></script>\
</footer>\
</div>\
<!--[if !IE]><script>fixScale(document);</script><![endif]-->\
</body>\
</html>\
"
static char build_table[][4096] = {
ARCHLINUX_32_REF, ARCHLINUX_64_REF,
DEBIAN_32_REF, DEBIAN_64_REF,
WINDOWS_32_REF, WINDOWS_64_REF
};
/* </tag> */
#define ISXDIGIT(c) ((c >= 48 && c <= 57) || ((c & ~0x20) >= 65 && (c & ~0x20) <= 70))
typedef struct {
char *data;
unsigned int len;
unsigned int size;
} url_t;
void escape(url_t *str) {
char *p, *ptr;
char hexstr[3];
unsigned int i=0;
unsigned long l=0;
p = str->data;
for(i=0; i < str->len; i++) {
if((p - str->data) >= str->len)
break;
if(*p == '%' &&
((p - str->data)+2) < str->len &&
ISXDIGIT(*(p+1)) &&
ISXDIGIT(*(p+2))
) {
p++;
hexstr[0] = *p++;
hexstr[1] = *p++;
hexstr[2] = 0;
l = strtoul(hexstr, &ptr, 16);
str->data[i] = (char)(l & 0x7f);
continue;
}
if(*p == '+') {
*p = ' ';
}
str->data[i] = *p++;
}
str->data[i] = 0;
str->len = i;
}
void version(const char *directory, char *major, char *minor, char *patch) {
FILE *handle;
char file[4096];
size_t size = 0;
char *data = NULL;
snprintf(file, sizeof(file), "%s/gmqcc.h", directory);
handle = fopen(file, "r");
if (!handle) {
fprintf(stderr, "failed to open %s for reading version (%s)\n",
file, strerror(errno)
);
abort();
}
while (getline(&data, &size, handle) != EOF) {
#define TEST(TYPE, STORE) \
if (strstr(data, "#define GMQCC_VERSION_" TYPE )) { \
char *get = data; \
while (!isdigit(*get)) \
get++; \
*STORE = *get; \
}
TEST("MAJOR", major)
TEST("MINOR", minor)
TEST("PATCH", patch)
#undef TEST
}
free(data);
}
void genhtml() {
FILE *fp = fopen("download.html", "w");
if (!fp) {
fprintf(stderr, "failed to generate HTML: %s\n", strerror(errno));
abort();
}
fprintf(fp, HTML,
build_table[0], build_table[1],
build_table[2], build_table[3],
build_table[4], build_table[5]
);
fclose (fp);
}
/*
* Builds a list of download links with the right version and handles the
* rest of the magic.
*/
void build(const char *directory) {
/* Figure out version number */
char find[3];
char decode[4096];
size_t size;
version(directory, &find[0], &find[1], &find[2]);
/*
* decode the secuity stuff for preparing the URLs which will be used
* as links.
*/
memset(decode, 0, sizeof(decode));
security_decode(decode, SECURITY_TOKEN, strlen(SECURITY_TOKEN));
for (size = 0; size < sizeof(build_table) / sizeof(*build_table); size++) {
char *load = strdup(build_table[size]);
url_t esc = { NULL, 0 };
snprintf(build_table[size], 4096, load, BASEURL, find[0], find[1], find[2], decode);
esc.data = strdup(build_table[size]);
esc.size = strlen(build_table[size]);
esc.len = esc.size;
/* Yes we also need to escape URLs just incase */
escape(&esc);
free(load);
}
/*
* Now generate the HTML file for those download links by asking tinyurl to
*/
genhtml();
}
int main(int argc, char **argv) {
size_t itr;
argc--;
argv++;
if (!argc) {
printf("usage: %s [gmqcc.h location]\n", argv[-1]);
return 0;
}
build(*argv);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -1,92 +0,0 @@
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font: inherit;
vertical-align: baseline;
}
body {
font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0;
line-height: 1.8em;
-webkit-font-smoothing: antialiased;
background: #CDC9C9;
}
h1, h2, h3, h4, h5, h6 {
color:#232323;
margin:36px 0 10px;
}
.head-ltitle, .head-rtitle, .head-vol {
font: bold 0.8em Arial, Helvectia, sans-serif;
}
.head-vol {
visibility: hidden;
}
.name {
font: bold 0.8em Monospace, serif;
}
.ftype {
font: normal 1em Monospace, serif;
}
h1 {
color: #c30000;
margin-top: 0.3em;
margin-bottom: 0.3em;
line-height: 1.3;
font: normal 1.4em Arvo, Monaco, sans-serif;
/*font: bold 1.4em Arial, Helvetica, sans-serif*/
}
.section {
margin-bottom: 1em;
margin-top: 1em;
padding-left: 1em;
border-top: 1px #cccccc solid;
font: normal 0.9em Arial, Helvetica, sans-serif;
text-align: justify;
border: 0;
padding-bottom: 1em;
border-bottom: 1px solid #f0e0e0;
}
.list-tag {
padding-left: 1em;
}
pre {
border: 1px dashed #ffffff;
background: #ddd8d8;
}
.flag {
font: normal 1em Monospace, serif;
}
a {
color:#C30000;
font-weight:200;
text-decoration:none;
}
a:hover {
text-decoration: underline;
}

View file

@ -69,7 +69,9 @@ Append a string parameter to be passed to
The following builtin functions are available:
.Bl -ohang
.It Li 1) void print(string...) = #1;
.D1 Print the passed strings to stdout. At most 8 strings are allowed.
.Bd -unfilled -offset indent -compact
Print the passed strings to stdout. At most 8 strings are allowed.
.Ed
.It Li 2) string ftos(float) = #2;
.D1 Convert a float to a string.
.It Li 3) entity spawn() = #3;
@ -79,7 +81,7 @@ The following builtin functions are available:
.It Li 5) string vtos(vector) = #5;
.D1 Convert a vector to a string.
.It Li 6) void error(string...) = #6;
.D1 Print at most 8 strings to stdout and then exit with an error.
.D1 Print strings to stdout and then exit with an error (limited to 8 arguments)
.It Li 7) float vlen(vector) = #7;
.D1 Get the length of a vector.
.It Li 8) string etos(entity) = #8;

View file

@ -1,759 +0,0 @@
\documentclass{article}
%%% PACKAGES
\usepackage{geometry}
\usepackage[utf8]{inputenc}
\usepackage[parfill]{parskip}
\usepackage{subfig}
\usepackage{listings}
\usepackage{color}
\usepackage{sectsty}
%%% GEOMETRY FOR DOCUMENT
\geometry{a4paper}
%%% HEADERS/FOOTERS APPEARANCE
\usepackage{fancyhdr} % This should be set AFTER setting up the page geometry
\pagestyle{fancy} % options: empty , plain , fancy
\renewcommand{\headrulewidth}{0pt} % customise the layout...
\lhead{}\chead{}\rhead{}
\lfoot{}\cfoot{\thepage}\rfoot{}
%%% SECTION TITLE APPEARANCE
\allsectionsfont{\sffamily\mdseries\upshape} % (See the fntguide.pdf for font help)
%%% ToC APPEARANCE
\usepackage[nottoc,notlof,notlot]{tocbibind} % Put the bibliography in the ToC
\usepackage[titles,subfigure]{tocloft} % Alter the style of the Table of Contents
\renewcommand{\cftsecfont}{\rmfamily\mdseries\upshape}
\renewcommand{\cftsecpagefont}{\rmfamily\mdseries\upshape} % No bold!
%%% listing language definitions
%%% BNF for now, QuakeC will be later
\definecolor{keyword1}{RGB}{0,102,153}
\definecolor{keyword2}{RGB}{0,153,102}
\definecolor{keyword3}{RGB}{0,153,255}
\definecolor{comment}{RGB}{204,0,0}
\definecolor{function}{RGB}{153,102,255}
\definecolor{digit}{RGB}{255,0,0}
\definecolor{string}{RGB}{255,0,204}
\definecolor{rule}{RGB}{192,192,192}
\definecolor{back}{RGB}{250,250,250}
\lstdefinelanguage{bnf}{
keywordstyle={\color{keyword2}\bfseries},
keywords={},
otherkeywords={::=,|},
morecomment=[s][\color{comment}]{(*}{*)},
stringstyle=\color{string},
showstringspaces=false,
frame=none,
rulecolor=\color{rule},
backgroundcolor=\color{back}
}
%% Title Information %%
\title{The GMQCC QuakeC Programming Language}
\author{Dale Weiler}
\date{\today}
\begin{document}
%% Title Page %%
\maketitle
\thispagestyle{empty}
\raggedright
\abstract
This document specifies the form and establishes the interpretation of programs written in
the GMQCC QuakeC programming language variant (refereed simply as QuakeC throughout this
document). It specifies:
\begin{itemize}
\item the representation of QuakeC programs;
\item the syntax and constraints of the QuakeC language;
\item the semantic rules for interpreting QuakeC programs;
\item the representation of input data to be processed by QuakeC programs;
\item the representation of output data produced by QuakeC programs;
\item the restrictions and limits imposed by a conforming implementation of QuakeC.
\end{itemize}
This document does not specify
\begin{itemize}
\item the mechanism by which QuakeC programs are transformed for use by a data-
processing system;
\item the mechanism by which QuakeC programs are invoked for use by a data-processing
system;
\item the mechanism by which input data are transformed for use by a QuakeC program;
\item the size or complexity of a program and its data that will exceed the capacity
of any specific data-processing system or the capacity of a particular
execution environment;
\item all minimal requirements of a data-processing system that is capable of
supporting a conforming implementation.
\end{itemize}
%% Table Of Contents %%
\newpage
\thispagestyle{empty}
\tableofcontents
\newpage
%% Begin Contents %%
\raggedright % No weird TEX spacing on lines to fill page
%% -> Terms, definitions, and symbols %%
\section{Terms, definitions, and symbols}
\subsection*{argument}
Expression in the comma-separated list bounded by the parentheses in a function call
expression, or a sequence of preprocessing tokens in the comma-separated list bounded
by the parentheses in a function-like macro invocation.
\subsection*{behavior}
External appearance or action
\subsection*{implementation-defined behavior}
Unspecified behavior where each implementation documents how the choice is made.
\subsection*{undefined behavior}
Behavior, upon use of a non-portable or erroneous program construct or of erroneous data,
for which this document imposes no actual requirements.
\subsection*{unspecified behavior}
Use of an unspecified value, or other behavior where this document provides two or more
possibilities and imposes no further requirements on which is chosen in any instance.
\subsection*{constraint}
Restriction, either syntactic or semantic, by which the exposition of language elements
is to be interpreted.
\subsection*{diagnostic message}
Message belonging to an implementation-defined subset of the implementation's message
output.
\subsection*{object}
Region of data storage in the execution environment, the contents of which can represent
values.
\subsection*{parameter}
Object declared as part of a function declaration or definition that acquires a value on
entry to the function, or an identifier from the comma-separated list bounded by the
parentheses immediately following the macro name in a function-like macro definition.
\subsection*{recommended practice}
Specification that is strongly recommended as being in keeping with the intent of this
document, but that may be impractical for some implementations.
\subsection*{value}
Precise meaning of the contents of an object when interpreted as having a specific type.
\subsection*{implementation}
Particular set of software, running in a particular translation environment under
particular control options, that performs translation of programs for, and supports
execution of functions in, a particular execution environment.
\subsection*{implementation-defined value}
Unspecified value where each implementation documents how the choice is made.
\subsection*{unspecified value}
Valid value of the relevant type where this document imposes no requirements on which
value is chosen in any instance.
%% -> Conformance %%
\section{Conformance}
In this document, "shall" is to be interpreted as a requirement on an implementation
or on a program; conversely, "shall not" is to be interpreted as a prohibition. \\
If a "shall" or "shall not" requirement that appears outside of a constraint is violated,
the behavior is undefined. Undefined behavior is otherwise indicated in this document by
the words "undefined behavior" or by the omission of any explicit definition of behavior.
There is no difference in emphasis among these three; they all describe "behavior that is
undefined".
%% -> Enviroment %%
\section{Environment}
An implementation that translates QuakeC source files and executes QuakeC programs in two
data processing-system environments, which will be called the translation environment and
the execution environment in this document. Their characteristics define and constrain the
results of executing QuakeC programs constructed according to the syntactic and semantic
rules for conforming implementations.
\subsection{Conceptual models}
\subsubsection{Translation environment}
\paragraph*{Translation steps}
The precedence among the syntax rules of translation is specified by the following steps
\begin{enumerate}
\item Physical source file characters are mapped, in an implementation-defined manner,
to the source character set (introducing new-line characters for end-of-line
indicators) if necessary. Trigraph and digraph sequences are replaced by their
corresponding single-character internal representations.
\item The source file is decomposed into preprocessing tokens and sequences of white-
space characters (including comments). A source file shall not end in a partial
preprocessing token or in a partial comment. Each comment is replaced by one
space character. New-line characters are retained. Whether each nonempty
sequences of white-space characters other than new-line is retained or replaced
by one space character is implementation-defined.
\item Preprocessing directives are executed, macro invocations are expanded
recursively. A \#include preprocessing directive causes the named header or
source file to be processed from step one through step three, recursively. All
preprocessing directives are then deleted.
\item Each source character set member and escape sequence in character constants and
string literals is converted to the corresponding member of the execution
character set; if there is no corresponding member, it is converted to an
implementation-defined member other than the null character.
\item Adjacent string literal tokens are concatenated.
\item White-space characters seperating tokens are no longer significant. Each
preprocessing token is converted into a token. The resulting tokens are then
syntactically and semantically analyzed and translated.
\end{enumerate}
\subparagraph*{Footnotes}
Implementations shall behave as if these steps occur separately, even though many are likely
to be folded together in practice. Source files need not be stored as file, nor need there
be any one-to-one correspondence between these items and any external representation. The
description is conceptual only, and does not specify any particular implementation.
\paragraph*{Diagnostics}
A conforming implementation shall produce at least on diagnostic message(identified in an
implementation-defined manner) if a source file contains a violation of any syntax rule or
constraint, even if the behavior is also explicitly specified as undefined or
implementation-defined. Diagnostic messages need not be produced in other circumstances.
%% ->-> Execution environments %%
\subsubsection{Execution environment}
A conforming execution environment shall provide at minimal the following 15 definitions
for built in functions, with an accompanying header or source file that defines them.
\begin{enumerate}
\item entity () spawn
\item void (entity) remove
\item string (float) ftos
\item string (vector) vtos
\item string (entity) etos
\item float (string) stof
\item void (string, ...) dprint
\item void (entity) eprint
\item float (float) rint
\item float (float) floor
\item float (float) ceil
\item float (float) fabs
\item float (float) sin
\item float (float) cos
\item float (float) sqrt
\end{enumerate}
The numbers of which these built-ins are assigned is implementation-defined;
an implementation is allowed to use these built-ins however it sees fit.
\pagebreak
%% -> Language %%
\section{Language}
\subsection{Notation}
The syntax notation used in this document is that of a BNF specification. A set of
derivation rules, often written as:
\begin{lstlisting}[language=bnf]
symbol ::= expression
\end{lstlisting}
Where symbol is a nonterminal, and the expression consists of one or more sequences of
symbols; more sequences are separated by a vertical bar \textbar, indicating a choice,
the whole being a possible substitution for the symbol on the left. Symbols that never
appear on the left side are terminals.
\linebreak
This document defines language syntax throughout it's way at defining language
constructs If you're interested in a summary of the language syntax, one is given in
annex A.
%% -> Concepts %%
\subsection{Concepts}
%% ->-> Scopes of identifiers %%
\subsubsection{Scopes of identifiers}
An identifier can denote an object; a function, or enumeration; a label name; a macro
name; or a macro parameter. The same identifier can denote different items at different
points in the program. A member of an enumeration is called an enumeration constant.
Macro names and macro parameters are not considered further here, because prior to the
semantic phase of program translation any occurrences of macro names in the source file
are replaced by the preprocessing token sequences that constitute their macro definitions.
\linebreak
For each different item that an identifier designates, the identifier is visible (i.e,
can be used) only within a region of program text called its scope. Different items
designated by the same identifier either have different scopes, or are in different name
spaces. There are four kinds of scopes: function, file, block and function prototype.
(A function prototype is a declaration of a function that declares the types of its
parameters.)
\linebreak
A label name is the only kind of identifier that has function scope. It can be used (in
a goto statement) anywhere in the function in which it appears, and is declared
implicitly by its syntactic appearance (prefixed by a colon :, and suffixed with a
statement).
\linebreak
Every other identifier has scope determined by the placement of its declaration (in a
declarator or type specifier). If the declarator or type specifier that declares the
identifier appears outside any block or list of parameters, the identifier has file
scope, which terminates at the end of the file. If the declartor or type specifier that
declares the identifier appears inside a block or within the list of parameter
declarations in a function definition, the identifier has block scope, which terminates
at the end of the associated block. If the declarator or type specifier that declares
the identifier appears within the list of parameter declarations in a function prototype
(not part of a function definition), the identifier has function prototype scope, which
terminates at the end of the function declarator. If an identifier designates two
different items in the same name space, the scopes might overlap. If so, the scope of
one item (the inner scope) will be a strict subset of the scope of the other item (the
outer scope). Within the inner scope, the identifier designates the item declared in the
inner scope; the item declared in the outer scope is hidden (and not visible) within
the inner scope.
\linebreak
Unless explicitly stated otherwise, where this document uses the term "identifier" to
refer to some item (as opposed to the syntactic construct), it refers to the item in the
relevant name space whose declaration is visible at the point the identifier occurs.
\linebreak
Two identifiers have the same scope if and only if their scopes terminate at the same
point.
\linebreak
Each enumeration constant has scope that begins just after the appearance of its defining
enumerator in an enumerator list. Any other identifier has scope that begins just after
the completion of its declarator.
%% ->-> Name spaces of identifiers %%
\subsubsection{Name spaces of identifiers}
If more than one declaration of a particular identifier is visible at any point in a
source file, the syntactic context disambiguates uses that refer to different items.
Thus, there are separate name spaces for various categories of identifiers, as follows:
\linebreak
\begin{itemize}
\item Label names (disambiguated by the syntax of the label declaration and use);
\item Enumerations (disambiguated by following the keyword enum);
\item All other identifiers, called ordinary identifiers (declared in ordinary
declarators or as enumeration constants).
\end{itemize}
%% ->-> Types %%
\subsubsection{Types}
The meaning of a value stored in an object returned by a function is determined by the
type of the expression used to access it. (An identifier declared to be an object is the simplest
such expression; the type is specified in the declaration of the identifier.) Types are
partitioned into object types (types that fully describe objects), function types(types
that describe functions), and incomplete types(types that describe objects but lack
information).
\linebreak
An object declared type bool is large enough to store the values 0 and 1.
\linebreak
An object declared type float is a real type; An object declared type vector is a
comprised set of three floats that respectively represent the \underline{x,y,z}
components of a three-dimensional vector.
\linebreak
An enumeration comprises a set of named integer constant values. Each distinct
enumeration constitutes a different enumerated type.
\linebreak
Enumeration types and float are collectively called arithmetic types. Each arithmetic
type belongs to one type domain.
\linebreak
The void type comprises an empty set of values; it is an incomplete type that cannot be
completed.
\linebreak
A number of derived types can be constructed from the object, function and incomplete
types, as follows:
\linebreak
\begin{itemize}
\item An array type describes a contiguously allocated nonempty set of objects with a
particular object type, called the element type. Array types are characterized
by their element type and by the number of elements in the array. An array type
is said to be derived from its element type, and if its element is type T, the
array type is sometimes called "array of T". The construction of an array type
from an element type is called "array type derivation".
\item A function type describes a function with a specified return type. A function
type is characterized by its return type and the number and types of its
parameters. A function type is said to be derived from its return type, and if
its return type is T, the function type is sometimes called "function returning
T". The construction of a function type from a return type is called "function
type derivation".
\end{itemize}
Arithmetic types are collectively called scalar types. Arrays and vectors are
collectively called aggregate types.
\linebreak
An array of unknown size is an incomplete type. It is completed, for an identifier of
that type, by specifying the size in a later declaration. Arrays are required to have
known constant size.
\linebreak
A type is characterized by its type category, which is either the outermost derivation
of a derived type (as noted above in the construction of derived types), or the type
itself if the type consists of no derived types.
\linebreak
Any type so far mentioned is an unqualified type. Each unqualified type has several
qualified versions of its type, corresponding to the combinations of one, two, or all
two of const and volatile qualifiers. The qualified or unqualified versions of a type
are distinct types that belong to the same type category and have the same representation.
A derived type is not qualified by the qualifiers (if any) of the type from which it
is derived.
\linebreak
%% ->-> Compatible types and composite type %%
\subsubsection{Compatible types and composite type}
Two types have compatible type if their types are the same.
\linebreak
All declarations that refer to the same object or function shall have compatible type;
otherwise the behavior is undefined.
\linebreak
A composite type can be constructed from two types that are compatible; it is a type that
is compatible with both of the two types and satisfies the following conditions:
\begin{itemize}
\item If one type is an array, the composite type is an array of that size.
\item If only one type is a function type with a parameter type list(a function
prototype), the composite type is a function prototype with the parameter type
list.
\item If both types are function types with parameter type lists, the type of each
parameter in the composite parameter type list is the composite type of the
corresponding parameters.
\end{itemize}
These rules apply recursively to types from which the two types are derived.
\linebreak
%% ->Conversions %%
\subsection{Conversions}
Several operators convert operand values from one type to another automatically. This
sub-clause specifies the result required from such an implicit conversion.
\linebreak
Conversion from an operand value to a compatible type causes no change to the value or
the representation.
\linebreak
TODO: Specify all implicit conversions.
%% ->->Aritmetic operands %%
\subsubsection{Arithmetic operands}
\paragraph*{Boolean type}
When any scalar value is converted to bool, the result is 0 if the value compares equal
to 0; otherwise the result is 1.
%% ->->Other operands %%
\subsubsection{Other operands}
\paragraph{Lvalues, arrays and function designators}
An lvalue is an expression with an object type or an incomplete type other than void;
if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
When an object is said to have a particular type, the type is specified by the lvalue
used to designate the object. A modifiable lvalue is an lvalue that does not have an
array type, does not have an incomplete type, and does not have a const-qualified type.
\linebreak
Except when it is the operand of the unary \& operator, the ++ operator, the -- operator,
or the left operand of the . operator or an assignment operator, an lvalue that does not
have array type is converted to the value stored in the designated object (and is no
longer an lvalue). If the lvalue has qualified type, the value has the unqualified
version of the type of the lvalue; otherwise, the value has the type of the lvalue. If
the lvalue has an incomplete type and does not have array type, the behavior is undefined.
\linebreak
A function designator is an expression that has function type.
\paragraph*{void}
The (nonexistent) value of a void expression (an expression that has type void) shall not
be used in any way, and implicit conversions (except to void) shall not be applied to
such an expression. If an expression of any other type is evaluated as a void expression,
its value or designator is discarded. (A void expression is only evaluated for its
side effects.)
\pagebreak
\subsection{Lexical elements}
\paragraph*{Syntax}
\begin{lstlisting}[language=bnf]
token ::= keyword
| identifier
| constant
| string-literal
| punctuator
preprocessing-token ::= header-name
| identifier
| pp-number
| string-literal
| punctuator
\end{lstlisting}
\paragraph*{Constraints}
Each preprocessing token that is converted to a token shall have the lexical form of a
keyword, an identifier, a constant, a string literal, or a punctuator.
\paragraph*{Semantics}
A token is the minimal lexical element of the language in translation steps six and seven.
The categories of tokens are: keywords, identifiers, constants, string literals, and
punctuators. A preprocessing token is the minimal lexical element of the language in
translation steps three through five. The categories of preprocessing tokens are: header
names, identifiers, preprocessing numbers, string literals, punctuators and other single
non-white-space characters that do not lexically match the other preprocessing token
categories. If a ' or a " character matches the last category, the behavior is undefined.
Preprocessing tokens can be separated by white space; this consists of comments (described
later), or white-space characters (space, horizontal tab, new-line, vertical tab, and form
-feed), or both. In certain circumstances during translation step four, white space (or
the absence thereof) serves as more than preprocessing token separation. White space may
appear within a preprocessing token only as part of a header name or between the quotation
characters in a string literal.
\linebreak
If the input stream has been parsed into preprocessing tokens up to a given character, the
next preprocessing token is the longest sequence of characters that could constitute a
preprocessing token. There is one exception to this rule: header name preprocessing tokens
are recognized only within \#include preprocessing directives and in implementation-defined
locations within \#pragma directives. In such contexts, a sequence of characters that
could be either a header name or string literal is recognized as the former.
%% ->-> Keywords %%
\subsubsection{Keywords}
\paragraph*{Syntax}
\begin{lstlisting}[language=bnf]
keyword ::= enum | break | return | void
| case | float | volatile | for
| while | const | goto | bool
| continue | if | static | default
| inline | do | switch | else
| vector | entity
\end{lstlisting}
\paragraph*{Semantics}
The above tokens (case sensitive) are reserved (in translation step seven and eight) for
use as keywords, and shall not be used otherwise.
%% ->->Identifiers %%
\subsubsection{Identifiers}
\begin{lstlisting}[language=bnf]
identifier ::= nondigit
| identifier nondigit
| identifier digit
nondigit ::= _ | a | b | c | d | e | f | g | h | i
| j | k | l | m | n | o | p | q | r | s
| t | u | v | w | x | y | z | A | B | C
| D | E | F | G | H | I | J | K | L | M
| N | P | Q | R | S | T | U | V | W | X
| Y | Z
digit ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
\end{lstlisting}
\paragraph*{Semantics}
An identifier is a sequence of nondigit characters (including the underscore \_, the lower
case and upper case Latin letters, and other characters) and digits, which designates one
or more items. Lowercase and uppercase letters are distinct. There is a specific limit of
65535 characters for an identifier.
\linebreak
When preprocessing tokens are converted to tokens during translation step six, if a
preprocessing token could not be converted to either a keyword or an identifier, it is
converted to a keyword.
\paragraph*{Predefined identifiers}
Any identifiers that begin with the prefix \_\_builtin, or are within the reserved name
space are reserved by the implementation.
%% ->->Constants %%
\subsubsection{Constants}
\begin{lstlisting}[language=bnf]
constant ::= integer-constant
| floating-constant
| enumeration-constant
| character-constant
| vector-constant
integer-constant ::= decimal-constant
| octal-constant
| hexadecimal-constant
decimal-constant ::= nonzero-digit
| decimal-constant digit
octal-constant ::= 0
| octal-constant octal-digit
hexadecimal-constant ::= hexdecimal-prefix
hexadecimal-digit
| hexadecimal-digit
hexadecimal-constant
hexadecimal-prefix: ::= 0x | 0X
nonzero-digit ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
| 9
octal-digit ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
hexadecimal-digit ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
| 8 | 9 | a | b | c | d | e | f
| A | B | C | D | E | F
\end{lstlisting}
%% ->-> String literals %%
\subsubsection{String literals}
\begin{lstlisting}[language=bnf]
string-literal := " s-char-sequence "
s-char-sequence := s-char
| s-char-sequence s-char
s-char := ` | ! | @ | # | $ | % | ^ | & | *
| ( | ) | _ | - | + | = | { | } | [
| ] | | | : | ; | ' | < | , | > | .
| ? | / | 1 | 2 | 3 | 4 | 5 | 6 | 7
| 8 | 9 | 0 | q | w | e | r | t | y
| u | i | o | p | a | s | d | f | g
| h | j | k | l | z | x | c | v | b
| n | m | Q | W | E | R | T | Y | U
| I | O | P | A | S | D | F | G | |
| H | J | K | L | Z | X | C | V | B
| N | M
\end{lstlisting}
\paragraph*{Description}
A character string literal is a sequence of zero or more characters enclosed in
double-quotes, as in "xyz".
\linebreak
The same considerations apply to each element of the sequence in a character string
literal as if it where an integer character constant, except that the single-quote
' is representable either by itself or by the escape sequence \textbackslash', but
the double-quote " shall be represented by the escape sequence \textbackslash".
\paragraph*{Semantics}
In translation stage six, the character sequences specified by any sequence of adjacent
character string literal tokens are concatenated into a single character sequence.
%% ->-> Punctuators %%
\subsubsection{Punctuators}
TODO: BNF
A punctuator is a symbol that has independent syntactic and semantic significance.
Depending on context, it may specify an operation to be performed (which in turn
may yield a value or a function designator, produce a side effect, or some combination
thereof) in which case it is known as an operator (other forms of operator also exist
in some contexts). An operand is an item on which an operator acts.
\linebreak
TODO: Trigraphs \& Digraphs
\subsubsection{Header names}
TODO
\subsubsection{Preprocessing numbers}
TODO
\subsubsection{Comments}
Except within a character constant, a string literal, or a comment, the characters /*
introduce a comment. The contents of such a comment are examined only to identify
characters and to find the characters */ that terminate it.
\linebreak
Except within a character constant, a string literal, or a comment, the characters //
introduce a comment that includes all characters up to, but not including, the next
new-line character. The contents of such a comment are examined only to identify
characters and to find the terminating new-line character.
\linebreak
%% -> Expressions %%
\subsection{Expressions}
An expression is a sequence of operators and operands that specifies computation of a
value, or that designates an object or function, or that generates side effects, or that
performs a combination thereof.
\linebreak
Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression. Furthermore, the prior value
shall be read only to determine the value to be stored.
\linebreak
The grouping of operators and operands is indicated by the syntax. Except as specified
later (for the function call (), \&\&, \textbar\textbar ?:, and comma operators), the
order of evaluation of sub-expressions and the order in which side effects take place
are both unspecified.
\linebreak
Some operators (the unary \textasciitilde operator, and the binary operators \textless
\textless, \textgreater\textgreater, \&, \^, and \textbar, collectively describe bitwise
operators) are required to have operands that are either integer, or floating point with
zero points of decimal precision.
\linebreak
If an exceptional condition occurs during the evaluation of an expression (that is, if
the result is not mathematically defined or not in the range or representable values for
its type), the behavior is undefined.
%% ->-> Primary expressions %%
\subsubsection{Primary expressions}
\paragraph*{Syntax}
\begin{lstlisting}[language=bnf]
primary-expression ::= identifier
| constant
| string-literal
( expression )
\end{lstlisting}
\paragraph*{Semantics}
An identifier is a primary expression, provided it has been declared as designating an
object(in which case it is an lvalue) or a function(in which case it is a function
designator).
\linebreak
A constant is a primary expression. Its type depends on its form and value.
\linebreak
A string literal is a primary expression. It is an lvalue.
\linebreak
A parenthesized expression is a primary expression. Its type and value identical to
those of the unparenthesized expression. It is an lvalue, a function designator, or a
void expression if the unparenthesized expression is, respectively, an lvalue, a
function designator, or a void expression.
%% ->-> Constant expressions %%
\subsubsection{Constant expressions}
\paragraph*{Syntax}
\begin{lstlisting}[language=bnf]
constant-expression ::= conditional-expression
\end{lstlisting}
\paragraph*{Description}
A constant expression can be evaluated during translation rather than runtime, and
accordingly may be used in any place that a constant may be.
\paragraph*{Constraints}
\begin{itemize}
\item Constant expressions shall not contain assignment, increment, decrement,
function-call, or comma operators, except when contained within a subexpression
that is not evaluated.
\item Each constant expression shall evaluate to a constant that is in range of
representable values for its type.
\end{itemize}
\paragraph*{Semantics}
An expression that evaluates to a constant is required in several contexts. If a floating
point expression is evaluated in the translation environment, the arithmetic precision range
shall be as great is if the expression were being evaluated in the execution environment.
\linebreak
An integer constant expression shall have integer type and shall only have operands that
are integer constants, enumeration constants, character constants, and floating constants
that are the immediate operand of casts. Cast operators in an integer constant expression
shall only convert arithmetic types to integer types.
\linebreak
More latitude is permitted for constant expressions in initializers. Such a constant expression
shall be, or evaluate to an arithmetic constant expression.
\linebreak
An arithmetic constant expression shall have arithmetic type and shall only have operands that
are integer constants, floating constants, enumeration constants, and character constants. Cast
operators in an arithmetic constant expression shall only convert arithmetic types to arithmetic
types.
\linebreak
An implementation may accept other forms of constant expressions.
\linebreak
The semantic rules for the evaluation of a constant expression are the same as for nonconstant
expressions.
\bibliographystyle{abbrv}
\bibliography{main}
\end{document}

File diff suppressed because it is too large Load diff

1679
fold.cpp Normal file

File diff suppressed because it is too large Load diff

121
fold.h Normal file
View file

@ -0,0 +1,121 @@
#ifndef GMQCC_FOLD_HDR
#define GMQCC_FOLD_HDR
#include "lexer.h"
#include "gmqcc.h"
struct ir_builder;
struct ir_value;
struct ast_function;
struct ast_ifthen;
struct ast_ternary;
struct ast_expression;
struct ast_value;
struct parser_t;
struct fold {
fold();
fold(parser_t *parser);
~fold();
// Bitmask describing which branches of a conditional to take after folding.
// Zero indicates all the branches can be removed.
// ON_TRUE means ON_FALSE can be removed.
// ON_FALSE means ON_TRUE can be removed.
// ON_TRUE | ON_FALSE means nothing can be removed.
enum {
ON_TRUE = 1 << 0,
ON_FALSE = 1 << 1,
};
bool generate(ir_builder *ir);
ast_expression *op(const oper_info *info, ast_expression **opexprs);
ast_expression *intrinsic(const char *intrinsic, size_t n_args, ast_expression **args);
static uint32_t cond_ternary(ast_value *condval, ast_ternary *branch);
static uint32_t cond_ifthen(ast_value *condval, ast_ifthen *branch);
static ast_expression *superfluous(ast_expression *left, ast_expression *right, int op);
static ast_expression *binary(lex_ctx_t ctx, int op, ast_expression *left, ast_expression *right);
ast_expression *constgen_float(qcfloat_t value, bool inexact);
ast_expression *constgen_vector(vec3_t value);
ast_expression *constgen_string(const char *str, bool translate);
ast_expression *constgen_string(const std::string &str, bool translate);
ast_value *imm_float(size_t index) const { return m_imm_float[index]; }
ast_value *imm_vector(size_t index) const { return m_imm_vector[index]; }
protected:
static qcfloat_t immvalue_float(ast_value *value);
static vec3_t immvalue_vector(ast_value *value);
static const char *immvalue_string(ast_value *value);
lex_ctx_t ctx();
bool immediate_true(ast_value *v);
bool check_except_float_impl(void (*callback)(void), ast_value *a, ast_value *b);
bool check_inexact_float(ast_value *a, ast_value *b);
ast_expression *op_mul_vec(vec3_t vec, ast_value *sel, const char *set);
ast_expression *op_neg(ast_value *a);
ast_expression *op_not(ast_value *a);
ast_expression *op_add(ast_value *a, ast_value *b);
ast_expression *op_sub(ast_value *a, ast_value *b);
ast_expression *op_mul(ast_value *a, ast_value *b);
ast_expression *op_div(ast_value *a, ast_value *b);
ast_expression *op_mod(ast_value *a, ast_value *b);
ast_expression *op_bor(ast_value *a, ast_value *b);
ast_expression *op_band(ast_value *a, ast_value *b);
ast_expression *op_xor(ast_value *a, ast_value *b);
ast_expression *op_lshift(ast_value *a, ast_value *b);
ast_expression *op_rshift(ast_value *a, ast_value *b);
ast_expression *op_andor(ast_value *a, ast_value *b, float expr);
ast_expression *op_tern(ast_value *a, ast_value *b, ast_value *c);
ast_expression *op_exp(ast_value *a, ast_value *b);
ast_expression *op_lteqgt(ast_value *a, ast_value *b);
ast_expression *op_ltgt(ast_value *a, ast_value *b, bool lt);
ast_expression *op_cmp(ast_value *a, ast_value *b, bool ne);
ast_expression *op_bnot(ast_value *a);
ast_expression *op_cross(ast_value *a, ast_value *b);
ast_expression *op_length(ast_value *a);
ast_expression *intrinsic_isfinite(ast_value *a);
ast_expression *intrinsic_isinf(ast_value *a);
ast_expression *intrinsic_isnan(ast_value *a);
ast_expression *intrinsic_isnormal(ast_value *a);
ast_expression *intrinsic_signbit(ast_value *a);
ast_expression *intrinsic_acosh(ast_value *a);
ast_expression *intrinsic_asinh(ast_value *a);
ast_expression *intrinsic_atanh(ast_value *a);
ast_expression *intrinsic_exp(ast_value *a);
ast_expression *intrinsic_exp2(ast_value *a);
ast_expression *intrinsic_expm1(ast_value *a);
ast_expression *intrinsic_pow(ast_value *lhs, ast_value *rhs);
ast_expression *intrinsic_mod(ast_value *lhs, ast_value *rhs);
ast_expression *intrinsic_fabs(ast_value *a);
ast_expression* intrinsic_nan(void);
ast_expression* intrinsic_epsilon(void);
ast_expression* intrinsic_inf(void);
static qcfloat_t immvalue_float(ir_value *value);
static vec3_t immvalue_vector(ir_value *value);
static uint32_t cond(ast_value *condval, ast_ifthen *branch);
private:
friend struct intrin;
std::vector<ast_value*> m_imm_float;
std::vector<ast_value*> m_imm_vector;
std::vector<ast_value*> m_imm_string;
hash_table_t *m_imm_string_untranslate; /* map<string, ast_value*> */
hash_table_t *m_imm_string_dotranslate; /* map<string, ast_value*> */
parser_t *m_parser;
bool m_initialized;
};
#endif

312
fs.c
View file

@ -1,312 +0,0 @@
/*
* 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.
*/
#include "gmqcc.h"
/*
* This is essentially a "wrapper" interface around standard C's IO
* library. There is two reason we implement this, 1) visual studio
* hearts for "secure" varations, as part of it's "Security Enhancements
* in the CRT" (http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx).
* 2) But one of the greater reasons is for the possibility of large file
* support in the future. I don't expect to reach the 2GB limit any
* time soon (mainly because that would be insane). But when it comes
* to adding support for some other larger IO tasks (in the test-suite,
* or even the QCVM we'll need it). There is also a third possibility of
* building .dat files directly from zip files (which would be very cool
* at least I think so).
*/
#ifdef _MSC_VER
#include <crtdbg.h> /* _CrtSetReportMode, _CRT_ASSERT */
/* {{{ */
/*
* Visual Studio has security CRT features which I actually want to support
* if we ever port to Windows 8, and want GMQCC to be API safe.
*
* We handle them here, for all file-operations.
*/
static void file_exception (
const wchar_t *expression,
const wchar_t *function,
const wchar_t *file,
unsigned int line,
uintptr_t reserved
) {
wprintf(L"Invalid parameter dectected %s:%d %s [%s]\n", file, line, function, expression);
wprintf(L"Aborting ...\n");
exit(EXIT_FAILURE);
}
static void file_init() {
static bool init = false;
if (init)
return;
_set_invalid_parameter_handler(&file_exception);
/*
* Turnoff the message box for CRT asserations otherwise
* we don't get the error reported to the console as we should
* otherwise get.
*/
_CrtSetReportMode(_CRT_ASSERT, 0);
init = !init;
}
FILE *fs_file_open(const char *filename, const char *mode) {
FILE *handle = NULL;
file_init();
return (fopen_s(&handle, filename, mode) != 0) ? NULL : handle;
}
size_t fs_file_read(void *buffer, size_t size, size_t count, FILE *fp) {
file_init();
return fread_s(buffer, size*count, size, count, fp);
}
int fs_file_printf(FILE *fp, const char *format, ...) {
int rt;
va_list va;
va_start(va, format);
file_init();
rt = vfprintf_s(fp, format, va);
va_end (va);
return rt;
}
/* }}} */
#else
/* {{{ */
/*
* All other compilers/platforms that don't restrict insane policies on
* IO for no aparent reason.
*/
FILE *fs_file_open(const char *filename, const char *mode) {
return fopen(filename, mode);
}
size_t fs_file_read(void *buffer, size_t size, size_t count, FILE *fp) {
return fread(buffer, size, count, fp);
}
int fs_file_printf(FILE *fp, const char *format, ...) {
int rt;
va_list va;
va_start(va, format);
rt = vfprintf(fp, format, va);
va_end (va);
return rt;
}
/* }}} */
#endif
/*
* These are implemented as just generic wrappers to keep consistency in
* the API. Not as macros though
*/
void fs_file_close(FILE *fp) {
/* Invokes file_exception on windows if fp is null */
fclose (fp);
}
size_t fs_file_write (
const void *buffer,
size_t size,
size_t count,
FILE *fp
) {
/* Invokes file_exception on windows if fp is null */
return fwrite(buffer, size, count, fp);
}
int fs_file_error(FILE *fp) {
/* Invokes file_exception on windows if fp is null */
return ferror(fp);
}
int fs_file_getc(FILE *fp) {
/* Invokes file_exception on windows if fp is null */
return fgetc(fp);
}
int fs_file_puts(FILE *fp, const char *str) {
/* Invokes file_exception on windows if fp is null */
return fputs(str, fp);
}
int fs_file_seek(FILE *fp, long int off, int whence) {
/* Invokes file_exception on windows if fp is null */
return fseek(fp, off, whence);
}
long int fs_file_tell(FILE *fp) {
/* Invokes file_exception on windows if fp is null */
return ftell(fp);
}
/*
* Implements libc getline for systems that don't have it, which is
* assmed all. This works the same as getline().
*/
int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
int chr;
int ret;
char *pos;
if (!lineptr || !n || !stream)
return -1;
if (!*lineptr) {
if (!(*lineptr = (char*)mem_a((*n=64))))
return -1;
}
chr = *n;
pos = *lineptr;
for (;;) {
int c = fs_file_getc(stream);
if (chr < 2) {
*n += (*n > 16) ? *n : 64;
chr = *n + *lineptr - pos;
if (!(*lineptr = (char*)mem_r(*lineptr,*n)))
return -1;
pos = *n - chr + *lineptr;
}
if (ferror(stream))
return -1;
if (c == EOF) {
if (pos == *lineptr)
return -1;
else
break;
}
*pos++ = c;
chr--;
if (c == '\n')
break;
}
*pos = '\0';
return (ret = pos - *lineptr);
}
/*
* Now we implement some directory functionality. Windows lacks dirent.h
* this is such a pisss off, we implement it here.
*/
#if defined(_WIN32) && !defined(__MINGW32__)
DIR *fs_dir_open(const char *name) {
DIR *dir = (DIR*)mem_a(sizeof(DIR) + strlen(name));
if (!dir)
return NULL;
util_strncpy(dir->dd_name, name, strlen(name));
return dir;
}
int fs_dir_close(DIR *dir) {
FindClose((HANDLE)dir->dd_handle);
mem_d ((void*)dir);
return 0;
}
struct dirent *fs_dir_read(DIR *dir) {
WIN32_FIND_DATA info;
struct dirent *data;
int rets;
if (!dir->dd_handle) {
char *dirname;
if (*dir->dd_name) {
size_t n = strlen(dir->dd_name);
if ((dirname = (char*)mem_a(n + 5) /* 4 + 1 */)) {
util_strncpy(dirname, dir->dd_name, n);
util_strncpy(dirname + n, "\\*.*", 4); /* 4 + 1 */
}
} else {
if (!(dirname = util_strdup("\\*.*")))
return NULL;
}
dir->dd_handle = (long)FindFirstFile(dirname, &info);
mem_d(dirname);
rets = !(!dir->dd_handle);
} else if (dir->dd_handle != -11) {
rets = FindNextFile ((HANDLE)dir->dd_handle, &info);
} else {
rets = 0;
}
if (!rets)
return NULL;
if ((data = (struct dirent*)mem_a(sizeof(struct dirent)))) {
util_strncpy(data->d_name, info.cFileName, FILENAME_MAX - 1);
data->d_name[FILENAME_MAX - 1] = '\0'; /* terminate */
data->d_namlen = strlen(data->d_name);
}
return data;
}
int fs_dir_change(const char *path) {
return !SetCurrentDirectory(path);
}
int fs_dir_make(const char *path) {
return !CreateDirectory(path, NULL);
}
#else
# if !defined(__MINGW32__)
# include <sys/stat.h> /* mkdir */
int fs_dir_make(const char *path) {
return mkdir(path, 0700);
}
# else
int fs_dir_make(const char *path) {
return mkdir(path);
}
# endif /*! !defined(__MINGW32__) */
DIR *fs_dir_open(const char *name) {
return opendir(name);
}
int fs_dir_close(DIR *dir) {
return closedir(dir);
}
struct dirent *fs_dir_read(DIR *dir) {
return readdir(dir);
}
#endif /*! defined(_WIN32) && !defined(__MINGW32__) */

File diff suppressed because it is too large Load diff

1021
gmqcc.h

File diff suppressed because it is too large Load diff

View file

@ -1,262 +1,745 @@
# This is an example INI file that can be used to set compiler options
# without the rquirement for supplying them as arguments on the command
# line, this can be coupled with progs.src. To utilize this file there
# are two options availble, if it's named "gmqcc.ini" or "gmqcc.cfg" and
# the file exists in the directory that GMQCC is invoked from, the compiler
# will implicitally find and execute regardless. For more freedom you may
# use -config=<file> from the command line to specify a more explicit
# directory/name.ext for the configuration file.
#This configuration file is similar to a regular .ini file. Comments start
#with hashtags or semicolons, sections are written in square brackets and
#in each section there can be arbitrary many key-value pairs.
#There are 3 sections currently: flags, warnings, optimizations.
#They contain a list of boolean values of the form VARNAME = true or
#VARNAME = false. The variable names are the same as for the corre
#sponding -W, -f or -O flag written with only capital letters and dashes
#replaced by underscores.
# These are common compiler flags usually represented via the -f prefix
# from the command line.
[flags]
# Enabling this can potentially reduces code size by overlapping
# locals where possible.
OVERLAP_LOCALS = false
#Add some additional characters to the string table in order to
#compensate for a wrong boundcheck in some specific version of the
#darkplaces engine.
# in some older versions of the Darkplaces engine the string table
# size is computed wrong causing compiled progs.dat to fail to load
# Enabling this works around the bug by writing a few additional
# null bytes to the end of the string table to compensate.
DARKPLACES_STRING_TABLE_BUG = false
DARKPLACES_STRING_TABLE_BUG = true
# Enabling this corrects the assignment of vector field pointers via
# subsituting STORE_FLD with STORE_V.
ADJUST_VECTOR_FIELDS = true
# Enabling this allows the use of the FTEQ preprocessor, as well as
# additional preprocessing directives such as #error and #warning.
FTEPP = true
#When assigning to field pointers of type .vector the common be
#haviour in compilers like fteqcc is to only assign the x-compo
#nent of the pointer. This means that you can use the vector as
#such, but you cannot use its y and z components directly. This
#flag fixes this behaviour. Before using it make sure your code
#does not depend on the buggy behaviour.
# Enabling this relaxes switch statement semantics
RELAXED_SWITCH = false
ADJUST_VECTOR_FIELDS = true
# Enabling this allows short-circut evaluation and logic, opposed
# to full evaluation.
SHORT_LOGIC = false
# Enabling this allows perl-like evaluation/logic.
PERL_LOGIC = true
#Enable a partially fteqcc-compatible preprocessor. It supports
#all the features used in the Xonotic codebase. If you need more,
#write a ticket.
# Enabling this allows the use of the "translatable strings" extension
# assisted by .po files.
TRANSLATABLE_STRINGS = false
FTEPP = true
# Enabling this prevents initializations from becoming constant unless
# 'const' is specified as a type qualifier.
INITIALIZED_NONCONSTANTS = false
# Enabling this allows function types to be assignable even if their
# signatures are invariant of each other.
ASSIGN_FUNCTION_TYPES = false
#Enable some predefined macros. This only works in combination
#with '-fftepp' and is currently not included by '-std=fteqcc'.
#The following macros will be added:
#
# __LINE__
# __FILE__
# __COUNTER__
# __COUNTER_LAST__
# __RANDOM__
# __RANDOM_LAST__
# __DATE__
# __TIME__
# __FUNC__
#
#Note that __FUNC__ is not actually a preprocessor macro, but is
#recognized by the parser even with the preprocessor disabled.
#
#Note that fteqcc also defines __NULL__ which becomes the first
#global. Assigning it to a vector does not yield the same result
#as in gmqcc where __NULL__ is defined to nil (See -funtyped-nil
#), which will cause the vector to be zero in all components. With
#fteqcc only the first component will be 0, while the other two
#will become the first to of the global return value. This behav
#ior is odd and relying on it should be discouraged, and thus is
#not supported by gmqcc.
# Enabling this will allow the generation of .lno files for engine
# virtual machine backtraces (this is enabled with -g as well).
LNO = false
FTEPP_PREDEFS = false
# Enabling this corrects ternary percedence bugs present in fteqcc.
CORRECT_TERNARY = true
# Prevent the creation of _x, _y and _z progdefs for vectors
SINGLE_VECTOR_DEFS = false
#Enable math constant definitions. This only works in combination
#with '-fftepp' and is currently not included by '-std=fteqcc'.
#The following macros will be added:
#
# M_E
# M_LOG2E
# M_LOG10E
# M_LN2
# M_LN10
# M_PI
# M_PI_2
# M_PI_4
# M_1_PI
# M_2_PI
# M_2_SQRTPI
# M_SQRT2
# M_SQRT1_2
# M_TAU
# Cast vectors to real booleans when used in logic expressions.
# This is achieved by using NOT_V.
CORRECT_LOGIC = false
FTEPP_MATHDEFS = false
# Always treat empty strings as true. Usuall !"" yields true, because
# the string-NOT instruction considers empty strings to be false, while
# an empty string as condition for 'if' will be considered true, since
# only the numerical value of the global is looked at.
TRUE_EMPTY_STRINGS = false
# Opposite of the above, empty strings are always false. Similar to
# CORRECT_LOGIC this will always use NOT_S to cast a string to a real
# boolean value.
FALSE_EMPTY_STRINGS = false
#Enable indirect macro expansion. This only works in combination
#with '-fftepp' and is currently not included by '-std=fteqcc'.
#Enabling this behavior will allow the preprocessor to operate more
#like the standard C preprocessor in that it will allow arguments
#of macros which are macro-expanded to be substituted into the
#definition of the macro. As an example:
#
# #define STR1(x) #x
# #define STR2(x) STR1(x)
# #define THE_ANSWER 42
# #define THE_ANSWER_STR STR2(THE_ANSWER) /* "42" */
#
#With this enabled, an expansion of THE_ANSWER_STR will yield
#the string "42". With this disabled an expansion of THE_ANSWER_STR
#will yield "THE_ANSWER"
# Recognize utf-8 characters in character constants, and encode
# codepoint escape sequences in strings as utf-8. This essentially allows
# \{1234} escape sequences to be higher than 255.
UTF8
FTEPP_INDIRECT_EXPANSION = false
# When a warning is printed and it is set to be treated as error via
# a -Werror switch, compilation will be stopped, unless this is false.
# When this is false, the rest of the code will be compiled, and at the end
# the file and line of the first warning will be shown.
BAIL_ON_WERROR = true
# Allow loops and switches to be labeled and break and continue to take an
# optional label to target a specific loop/switch.
LOOP_LABELS = false
#Allow switch cases to use non constant variables.
# Enable the 'nil' null constant, which has no type. It can be used as the
# right hand of any assignment regardless of the required type.
UNTYPED_NIL = false
RELAXED_SWITCH = true
# Be "permissive". For instance, when -funtyped-nil is used, this allows local
# variables with the name 'nil' to be declared.
PREMISSIVE = false
# Allow vararg access from within QC of the form: ...(argnumber, type)
VARIADIC_ARGS = true
#Perform early out in logical AND and OR expressions. The final
#result will be either a 0 or a 1, see the next flag for more pos
#sibilities.
# Most Quake VMs, including the one from FTEQW or up till recently
# Darkplaces, do not cope well with vector instructions with overlapping
# input and output. This option will avoid producing such code.
LEGACY_VECTOR_MATHS = true
SHORT_LOGIC = true
#In many languages, logical expressions perform early out in a
#special way: If the left operand of an AND yeilds true, or the
#one of an OR yields false, the complete expression evaluates to
#the right side. Thus true && 5 evaluates to 5 rather than 1.
PERL_LOGIC = false
#Enable the underscore intrinsic: Using _("A string constant")
#will cause the string immediate to get a name with a "dotrans
#late_" prefix. The darkplaces engine recognizes these and trans
#lates them in a way similar to how gettext works.
TRANSLATABLE_STRINGS = true
#Don't implicitly convert initialized variables to constants. With
#this flag, the const keyword is required to make a constant.
INITIALIZED_NONCONSTANTS = false
#If this flag is not set, (and it is set by default in the qcc and
#fteqcc standards), assigning function pointers of mismatching
#signatures will result in an error rather than a warning.
ASSIGN_FUNCTION_TYPES = true
#Produce a linenumber file along with the output .dat file.
LNO = false
#Use C's operator precedence for ternary expressions. Unless your
#code depends on fteqcc-compatible behaviour, you'll want to use
#this option.
CORRECT_TERNARY = true
#Normally vectors generate 4 defs, once for the vector, and once
#for its components with _x, _y, _z suffixes. This option prevents
#components from being listed.
SINGLE_VECTOR_DEFS = true
#Most QC compilers translate if(a_vector) directly as an IF on
#the vector, which means only the x-component is checked. This
#option causes vectors to be cast to actual booleans via a NOT_V
#and, if necessary, a NOT_F chained to it.
#
# if (a_vector) // becomes
# if not(!a_vector)
# // likewise
# a = a_vector && a_float // becomes
# a = !!a_vector && a_float
CORRECT_LOGIC = true
#An empty string is considered to be true everywhere. The NOT_S
#instruction usually considers an empty string to be false, this
#option effectively causes the unary not in strings to use NOT_F
#instead.
TRUE_EMPTY_STRINGS = false
#An empty string is considered to be false everywhere. This means
#loops and if statements which depend on a string will perform a
#NOT_S instruction on the string before using it.
FALSE_EMPTY_STRINGS = true
#Enable utf8 characters. This allows utf-8 encoded character con
#stants, and escape sequence codepoints in the valid utf-8 range.
#Effectively enabling escape sequences like '\{x2211}'.
UTF8 = true
#When a warning is treated as an error, and this option is set
#(which it is by default), it is like any other error and will
#cause compilation to stop. When disabling this flag by using
#-fno-bail-on-werror, compilation will continue until the end, but
#no output is generated. Instead the first such error message's
#context is shown.
BAIL_ON_WERROR = false
#Allow loops to be labeled, and allow 'break' and 'continue' to
#take an optional label to decide which loop to actually jump out
#of or continue.
#
# for :outer (i = 0; i < n; ++i) {
# while (inner) {
# ...;
# if (something)
# continue outer;
# }
# }
LOOP_LABELS = true
#Adds a global named 'nil' which is of no type and can be assigned
#to anything. No typechecking will be performed on assignments.
#Assigning to it is forbidden, using it in any other kind of
#expression is also not allowed.
#
#Note that this is different from fteqcc's __NULL__: In fteqcc,
#__NULL__ maps to the integer written as '0i'. It's can be
#assigned to function pointers and integers, but it'll error about
#invalid instructions when assigning it to floats without enabling
#the FTE instruction set. There's also a bug which allows it to be
#assigned to vectors, for which the source will be the global at
#offset 0, meaning the vector's y and z components will contain
#the OFS_RETURN x and y components.#
#
#In that gmqcc the nil global is an actual global filled with
#zeroes, and can be assigned to anything including fields, vectors
#or function pointers, and they end up becoming zeroed.
UNTYPED_NIL = true
#Various effects, usually to weaken some conditions.
# with -funtyped-nil
# Allow local variables named nil. (This will not
# allow declaring a global of that name.)
PERMISSIVE = false
#Allow variadic parameters to be accessed by QC code. This can be
#achieved via the '...' function, which takes a parameter index
#and a typename.
#
#Example:
#
# void vafunc(string...count) {
# float i;
# for (i = 0; i < count; ++i)
# print(...(i, string), "\n");
# }
VARIADIC_ARGS = true
#Most Quake VMs, including the one from FTEQW or up till recently
#Darkplaces, do not cope well with vector instructions with over
#lapping input and output. This option will avoid producing such
#code.
LEGACY_VECTOR_MATHS = false
#Usually builtin-numbers are just immediate constants. With this
#flag expressions can be used, as long as they are compile-time
#constant.
#
#Example:
#
# void printA() = #1; // the usual way
# void printB() = #2-1; // with a constant expression
EXPRESSIONS_FOR_BUILTINS = true
#Enabiling this option will allow assigning values or expressions
#to the return keyword as if it were a local variable of the same
#type as the function's signature's return type.
#
#Example:
#
# float bar() { return 1024; }
# float fun() {
# return = bar();
# return; // returns value of bar (this can be omitted)
# }
RETURN_ASSIGNMENTS = true
#When passing on varargs to a different functions, this turns some
#static error cases into warnings. Like when the caller's varargs
#are restricted to a different type than the callee's parameter.
#Or a list of unrestricted varargs is passed into restricted
#varargs.
UNSAFE_VARARGS = false
#Always use STORE_F, LOAD_F, STOREP_F when accessing scalar variables.
#This is somewhat incorrect assembly instruction use, but in all engines
#they do exactly the same. This makes disassembly output harder to read,
#breaks decompilers, but causes the output file to be better compressible.
TYPELESS_STORES = false
#In commutative instructions, always put the lower-numbered operand first.
#This shaves off 1 byte of entropy from all these instructions, reducing
#compressed size of the output file.
SORT_OPERANDS = false
#Emulate OP_STATE operations in code rather than using the instruction.
#The desired fps can be set via -state-fps=NUM, defaults to 10.
EMULATE_STATE = false
#Turn on arithmetic exception tests in the compiler. In constant expressions
#which trigger exceptions like division by zero, overflow, underflow, etc,
#the following flag will produce diagnostics for what triggered that
#exception.
ARITHMETIC_EXCEPTIONS = false
#Split vector-literals which are only used dirctly as function parameters
#into 3 floats stored separately to reduce the number of globals at the
#expense of additional instructions.
SPLIT_VECTOR_PARAMETERS = false
#Force all expressions to be "eraseable" which permits the compiler
#to remove unused functions, variables and statements. This is
#equivlant to putting [[eraseable]] on all definitions. This is
#dangerous as it breaks auto cvars, definitions for functions the
#engine may be looking for and translatable strings. Instead, you
#can mark a definition with [[noerase]] to prevent this from happening.
DEFAULT_ERASEABLE = false
# These are all the warnings, usually present via the -W prefix from
# the command line.
[warnings]
# ?? Used for debugging ??
DEBUG = false
#Generate a warning about variables which are declared but never
#used. This can be avoided by adding the noref keyword in front
#of the variable declaration. Additionally a complete section of
#unreferenced variables can be opened using #pragma noref 1 and
#closed via #pragma noref 0.
# Enables warnings about unused variables.
UNUSED_VARIABLE = true
UNUSED_VARIABLE = false
# Enables warnings about uninitialized variables.
USED_UNINITIALIZED = true
# Enables warnings about the unknown control sequences in the source
# stream.
UNKNOWN_CONTROL_SEQUENCE = true
#Generate a warning about vector variables which are declared but
#components of it are never used.
# Enables warnings about the use of (an) extension(s).
EXTENSIONS = true
UNUSED_COMPONENT = false
# Enables warnings about redeclared fields.
FIELD_REDECLARED = true
#Generate a warning if it is possible that a variable can be used
#without prior initialization. Note that this warning is not nec
#essarily reliable if the initialization happens only under cer
#tain conditions. The other way is not possible: that the warning
#is not generated when uninitialized use is possible.
# Enables warnings about missing return values.
MISSING_RETURN_VALUES = true
USED_UNINITIALIZED = false
# Enables warnings about missing parameters for function calls.
INVALID_PARAMETER_COUNT = true
# Enables warnings about locals shadowing parameters or other locals.
LOCAL_SHADOWS = true
#Generate an error when an unrecognized control sequence in a
#string is used. Meaning: when there's a character after a back
#slash in a string which has no known meaning.
# Enables warnings about constants specified as locals.
LOCAL_CONSTANTS = true
UNKNOWN_CONTROL_SEQUENCE = false
# Enables warnings about variables declared as type void.
VOID_VARIABLES = true
# Enables warnings about implicitally declared function pointers.
IMPLICIT_FUNCTION_POINTER = true
#Warn when using special extensions which are not part of the
#selected standard.
# Enables warnings for use of varadics for non-builtin functions.
VARIADIC_FUNCTION = true
EXTENSIONS = false
# Enables warnings about duplicated frame macros.
FRAME_MACROS = true
# Enables warnings about effectivless statements.
EFFECTLESS_STATEMENT = true
#Generally QC compilers ignore redeclaration of fields. Here you
#can optionally enable a warning.
# Enables warnings of "end_sys_fields" beiing declared a field.
END_SYS_FIELDS = true
FIELD_REDECLARED = false
# Enables warnings for infompatible function pointer signatures used
# in assignment.
ASSIGN_FUNCTION_TYPES = true
# Enables warnings about redefined macros in the preprocessor
PREPROCESSOR = true
#Functions which aren't of type void will warn if it possible to
#reach the end without returning an actual value.
# Enables warnings about multi-file if statements
MULTIFILE_IF = true
MISSING_RETURN_VALUES = false
# Enables warnings about double declarations
DOUBLE_DECLARATION = true
# Enables warnings about type qualifiers containing both 'var' and
# 'const'
CONST_VAR = true
#Warn about a function call with an invalid number of parameters.
# Enables warnings about the use of multibytes characters / constants
MULTIBYTE_CHARACTER = true
INVALID_PARAMETER_COUNT = false
# Enables warnings about ternary expressions whos precedence may be
# not what was initially expected.
TERNARY_PRECEDENCE = true
# Enables warnings about unknown pragmas.
UNKNOWN_PRAGMAS = true
#Warn when a locally declared variable shadows variable.
# Enables warnings about unreachable code.
UNREACHABLE_CODE = true
LOCAL_SHADOWS = false
# Enables preprocessor "#warnings"
CPP = true
# With the [[attribute]] syntax enabled, warn when an unknown
# attribute is encountered. Its first token will be included in the
# message.
UNKNOWN_ATTRIBUTE = true
#Warn when the initialization of a local variable turns the vari
#able into a constant. This is default behaviour unless
#-finitialized-nonconstants is used.
# Warn when declaring variables or fields with a reserved name like 'nil'
RESERVED_NAMES = true
LOCAL_CONSTANTS = false
# Warn about 'const'-qualified global variables with no initializing value.
UNINITIALIZED_CONSTANT = true
# Warn about non-constant global variables with no initializing value.
UNINITIALIZED_GLOBAL = true
#There are only 2 known global variables of type void:
#end_sys_globals and end_sys_fields. Any other void-variable
#will warn.
# Redeclaring a 'const' as 'var' or the other way round.
DIFFERENT_QUALIFIERS = true
VOID_VARIABLES = false
# Redeclaring a function with different attributes such as
# [[noreturn]]
DIFFERENT_ATTRIBUTES = true
# Warn when a function is marked with the attribute
# "[[deprecated]]". This flag enables a warning on calls to functions
# marked as such.
DEPRECATED = true
#A global function which is not declared with the var keyword is
#expected to have an implementing body, or be a builtin. If nei
#ther is the case, it implicitly becomes a function pointer, and a
#warning is generated.
IMPLICIT_FUNCTION_POINTER = false
#Currently there's no way for an in QC implemented function to
#access variadic parameters. If a function with variadic parame
#ters has an implementing body, a warning will be generated.
VARIADIC_FUNCTION = false
#Generate warnings about $frame commands, for instance about
#duplicate frame definitions.
FRAME_MACROS = false
#Warn about statements which have no effect. Any expression which
#does not call a function or assigns a variable.
EFFECTLESS_STATEMENT = false
#The end_sys_fields variable is supposed to be a global variable
#of type void. It is also recognized as a field but this will
#generate a warning.
END_SYS_FIELDS = false
#Warn when assigning to a function pointer with an unmatching sig
#nature. This usually happens in cases like assigning the null
#function to an entity's .think function pointer.
ASSIGN_FUNCTION_TYPES = false
#Show warnings created using the preprocessor's '#warning' directive
CPP = true
#Warn if there's a preprocessor #if spanning across several files.
MULTIFILE_IF = true
#Warn about multiple declarations of globals. This seems pretty
#common in QC code so you probably do not want this unless you
#want to clean up your code.
DOUBLE_DECLARATION = false
#The combination of const and var is not illegal, however differ
#ent compilers may handle them differently. We were told, the
#intention is to create a function-pointer which is not assigna
#ble. This is exactly how we interpret it. However for this
#interpretation the var keyword is considered superfluous (and
#philosophically wrong), so it is possible to generate a warning
#about this.
CONST_VAR = true
#Warn about multibyte character constants, they do not work right
#now.
MULTIBYTE_CHARACTER = false
#Warn if a ternary expression which contains a comma operator is
#used without enclosing parenthesis, since this is most likely not
#what you actually want. We recommend the -fcorrect-ternary
#option.
TERNARY_PRECEDENCE = false
#Warn when encountering an unrecognized #pragma line.
UNKNOWN_PRAGMAS = true
#Warn about unreachable code. That is: code after a return state
#ment, or code after a call to a function marked as 'noreturn'.
UNREACHABLE_CODE = true
#Enable some warnings added in order to help debugging in the com
#piler. You won't need this.
DEBUG = false
#Warn on an unknown attribute. The warning will inlclude only the
#first token inside the enclosing attribute-brackets. This may
#change when the actual attribute syntax is better defined.
UNKNOWN_ATTRIBUTE = true
#Warn when using reserved names such as nil.
RESERVED_NAMES = true
#Warn about global constants (using the const keyword) with no
#assigned value.
UNINITIALIZED_CONSTANT = true
#Warn about global variables with no initializing value. This is
#off by default, and is added mostly to help find null-values
#which are supposed to be replaced by the untyped 'nil' constant.
UNINITIALIZED_GLOBAL = true
#Warn when a variables is redeclared with a different qualifier.
#For example when redeclaring a variable as 'var' which was previ
#ously marked 'const'.
DIFFERENT_QUALIFIERS = true
#Similar to the above but for attributes like [[noreturn]].
DIFFERENT_ATTRIBUTES = true
#Warn when a function is marked with the attribute "[[depre
#cated]]". This flag enables a warning on calls to functions
#marked as such.
DEPRECATED = true
#Warn about possible mistakes caused by missing or wrong parenthe
#sis, like an assignment in an 'if' condition when there's no
#additional set of parens around the assignment.
PARENTHESIS = true
#When passing variadic parameters via ...(N) it can happen that
#incompatible types are passed to functions. This enables several
#warnings when static typechecking cannot guarantee consistent
#behavior.
UNSAFE_TYPES = true
#When compiling original id1 QC there is a definition for `break`
#which conflicts with the 'break' keyword in GMQCC. Enabling this
#print a warning when the definition occurs. The definition is
#ignored for both cases.
BREAKDEF = true
#When compiling original QuakeWorld QC there are instances where
#code overwrites constants. This is considered an error, however
#for QuakeWorld to compile it needs to be treated as a warning
#instead, as such this warning only works when -std=qcc.
CONST_OVERWRITE = true
#Warn about the use of preprocessor directives inside macros.
DIRECTIVE_INMACRO = true
#When using a function that is not explicitly defined, the compiler
#will search its intrinsics table for something that matches that
#function name by appending "__builtin_" to it. This behaviour may
#be unexpected, so enabling this will produce a diagnostic when
#such a function is resolved to a builtin.
BUILTINS = true
#When comparing an inexact value such as `1.0/3.0' the result is
#pathologically wrong. Enabling this will trigger a compiler warning
#on such expressions.
INEXACT_COMPARES = true
# Warn about possible problems from missing parenthesis, like an
# assignment used as truth value without additional parens around.
PARENTHESIS = true
# Finally these are all the optimizations, usually present via the -O
# prefix from the command line.
[optimizations]
# Enables peephole optimizations.
PEEPHOLE = true
#Some general peephole optimizations. For instance the code `a = b
#+ c` typically generates 2 instructions, an ADD and a STORE. This
#optimization removes the STORE and lets the ADD write directly
#into A.
# Enables localtemp omission optimizations.
LOCALTEMPS = true
PEEPHOLE = true
# Enables tail recrusion optimizationd.
TAIL_RECURSION = true
# Enables tail-call optimizations. (Not implemented)
TAIL_CALLS = true
#Tail recursive function calls will be turned into loops to avoid
#the overhead of the CALL and RETURN instructions.
# Every function where it is safe to do so will share its local data section
# with the others. The criteria are currently that the function must not have
# any possibly uninitialized locals, or local arrays regardless of how they
# are initialized.
OVERLAP_LOCALS = false
TAIL_RECURSION = true
# Strip out the names of constants to save some space in the progs.dat
STRIP_CONSTANT_NAMES = true
# Aggressivly reuse strings in the string-section
OVERLAP_STRINGS = true
#Make all functions which use neither local arrays nor have locals
#which are seen as possibly uninitialized use the same local sec
#tion. This should be pretty safe compared to other compilers
#which do not check for uninitialized values properly. The problem
#is that there's QC code out there which really doesn't initialize
#some values. This is fine as long as this kind of optimization
#isn't used, but also, only as long as the functions cannot be
#called in a recursive manner. Since it's hard to know whether or
#not an array is actually fully initialized, especially when ini
#tializing it via a loop, we assume functions with arrays to be
#too dangerous for this optimization.
# Have expressions which are used as function parameters evaluate directly
# into the parameter-globals if possible.
# This avoids a whole lot of copying.
CALL_STORES = true
OVERLAP_LOCALS = true
# Do not create a RETURN instruction at the end functions of return-type void.
VOID_RETURN = true
# Turn extraction-multiplications such as (a_vector * '0 1 0')
# into direct component accesses
VECTOR_COMPONENTS = true
#This promotes locally declared variables to "temps". Meaning when
#a temporary result of an operation has to be stored somewhere, a
#local variable which is not 'alive' at that point can be used to
#keep the result. This can reduce the size of the global section.
#This will not have declared variables overlap, even if it was
#possible.
LOCAL_TEMPS = true
#Causes temporary values which do not need to be backed up on a
#CALL to not be stored in the function's locals-area. With this, a
#CALL to a function may need to back up fewer values and thus exe
#cute faster.
GLOBAL_TEMPS = true
#Don't generate defs for immediate values or even declared con
#stants. Meaning variables which are implicitly constant or qual
#ified as such using the 'const' keyword.
STRIP_CONSTANT_NAMES = true
#Aggressively reuse strings in the string section. When a string
#should be added which is the trailing substring of an already
#existing string, the existing string's tail will be returned
#instead of the new string being added.
#
#For example the following code will only generate 1 string:
#
# print("Hello you!\n");
# print("you!\n"); // trailing substring of "Hello you!\n"
#
#There's however one limitation. Strings are still processed in
#order, so if the above print statements were reversed, this opti
#mization would not happen.
OVERLAP_STRINGS = true
#By default, all parameters of a CALL are copied into the parame
#ter-globals right before the CALL instructions. This is the easi
#est and safest way to translate calls, but also adds a lot of
#unnecessary copying and unnecessary temporary values. This opti
#mization makes operations which are used as a parameter evaluate
#directly into the parameter-global if that is possible, which is
#when there's no other CALL instruction in between.
CALL_STORES = true
#Usually an empty RETURN instruction is added to the end of a void
#typed function. However, additionally after every function a DONE
#instruction is added for several reasons. (For example the qcvm's
#disassemble switch uses it to know when the function ends.). This
#optimization replaces that last RETURN with DONE rather than
#adding the DONE additionally.
VOID_RETURN = true
#Because traditional QC code doesn't allow you to access individ
#ual vector components of a computed vector without storing it in
#a local first, sometimes people multiply it by a constant like
#'0 1 0' to get, in this case, the y component of a vector. This
#optimization will turn such a multiplication into a direct compo
#nent access. If the factor is anything other than 1, a float-mul
#tiplication will be added, which is still faster than a vector
#multiplication.
VECTOR_COMPONENTS = true
#For constant expressions that result in dead code (such as a
#branch whos condition can be evaluated at compile-time), this
#will eliminate the branch and else body (if present) to produce
#more optimal code.
CONST_FOLD_DCE = true
#For constant expressions we can fold them to immediate values.
#this option cannot be disabled or enabled, the compiler forces
#it to stay enabled by ignoring the value entierly. There are
#plans to enable some level of constant fold disabling, but right
#now the language can't function without it. This is merley here
#as an exercise to the reader.
CONST_FOLD = true

2048
intrin.cpp Normal file

File diff suppressed because it is too large Load diff

478
intrin.h
View file

@ -1,418 +1,74 @@
/*
* 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.
*/
#ifndef GMQCC_INTRIN_HDR
#define GMQCC_INTRIN_HDR
#include "gmqcc.h"
/*
* 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;
struct fold;
struct parser_t;
ht intrin_intrinsics() {
static ht intrinsics = NULL;
if (!intrinsics)
intrinsics = util_htnew(PARSER_HT_SIZE);
struct ast_function;
struct ast_expression;
struct ast_value;
return intrinsics;
}
struct intrin;
#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"}
struct intrin_func_t {
ast_expression *(intrin::*function)();
const char *name;
const char *alias;
size_t args;
};
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));
struct intrin {
intrin() = default;
intrin(parser_t *parser);
ast_expression *debug_typestring();
ast_expression *do_fold(ast_value *val, ast_expression **exprs);
ast_expression *func_try(size_t offset, const char *compare);
ast_expression *func_self(const char *name, const char *from);
ast_expression *func(const char *name);
protected:
lex_ctx_t ctx() const;
ast_function *value(ast_value **out, const char *name, qc_type vtype);
void reg(ast_value *const value, ast_function *const func);
ast_expression *nullfunc();
ast_expression *isfinite_();
ast_expression *isinf_();
ast_expression *isnan_();
ast_expression *isnormal_();
ast_expression *signbit_();
ast_expression *acosh_();
ast_expression *asinh_();
ast_expression *atanh_();
ast_expression *exp_();
ast_expression *exp2_();
ast_expression *expm1_();
ast_expression *pow_();
ast_expression *mod_();
ast_expression *fabs_();
ast_expression *epsilon_();
ast_expression *nan_();
ast_expression *inf_();
ast_expression *ln_();
ast_expression *log_variant(const char *name, float base);
ast_expression *log_();
ast_expression *log10_();
ast_expression *log2_();
ast_expression *logb_();
ast_expression *shift_variant(const char *name, size_t instr);
ast_expression *lshift();
ast_expression *rshift();
void error(const char *fmt, ...);
private:
parser_t *m_parser;
fold *m_fold;
std::vector<intrin_func_t> m_intrinsics;
std::vector<ast_expression*> m_generated;
};
#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 (ast_expression*)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;
}

3978
ir.c

File diff suppressed because it is too large Load diff

4094
ir.cpp Normal file

File diff suppressed because it is too large Load diff

508
ir.h
View file

@ -1,360 +1,334 @@
/*
* Copyright (C) 2012, 2013
* Wolfgang Bumiller
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef GMQCC_IR_HDR
#define GMQCC_IR_HDR
#include "gmqcc.h"
/* ir_value */
typedef struct
{
/*
* Type large enough to hold all the possible IR flags. This should be
* changed if the static assertion at the end of this file fails.
*/
typedef uint8_t ir_flag_t;
struct ir_value;
struct ir_instr;
struct ir_block;
struct ir_function;
struct ir_builder;
struct ir_life_entry_t {
/* both inclusive */
size_t start;
size_t end;
} ir_life_entry_t;
};
struct ir_function_s;
typedef struct ir_value_s {
char *name;
int vtype;
int store;
lex_ctx context;
/* even the IR knows the subtype of a field */
int fieldtype;
/* and the output type of a function */
int outtype;
/* 'const' vs 'var' qualifier */
int cvq;
uint32_t flags;
enum {
IR_FLAG_HAS_ARRAYS = 1 << 0,
IR_FLAG_HAS_UNINITIALIZED = 1 << 1,
IR_FLAG_HAS_GOTO = 1 << 2,
IR_FLAG_INCLUDE_DEF = 1 << 3,
IR_FLAG_ERASABLE = 1 << 4,
IR_FLAG_BLOCK_COVERAGE = 1 << 5,
IR_FLAG_NOREF = 1 << 6,
IR_FLAG_SPLIT_VECTOR = 1 << 7,
struct ir_instr_s **reads;
struct ir_instr_s **writes;
IR_FLAG_LAST,
IR_FLAG_MASK_NO_OVERLAP = (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED),
IR_FLAG_MASK_NO_LOCAL_TEMPS = (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED)
};
/* constantvalues */
bool hasvalue;
struct ir_value {
ir_value(std::string&& name, store_type storetype, qc_type vtype);
ir_value(ir_function *owner, std::string&& name, store_type storetype, qc_type vtype);
~ir_value();
ir_value *vectorMember(unsigned int member);
bool GMQCC_WARN setFloat(float);
bool GMQCC_WARN setFunc(int);
bool GMQCC_WARN setString(const char*);
bool GMQCC_WARN setVector(vec3_t);
bool GMQCC_WARN setField(ir_value*);
#if 0
bool GMQCC_WARN setInt(int);
#endif
bool lives(size_t at);
void dumpLife(int (*oprintf)(const char*, ...)) const;
void setCodeAddress(int32_t gaddr);
int32_t codeAddress() const;
bool insertLife(size_t idx, ir_life_entry_t);
bool setAlive(size_t position);
bool mergeLife(const ir_value *other);
std::string m_name;
qc_type m_vtype;
store_type m_store;
lex_ctx_t m_context;
qc_type m_fieldtype; // even the IR knows the subtype of a field
qc_type m_outtype; // and the output type of a function
int m_cvq; // 'const' vs 'var' qualifier
ir_flag_t m_flags;
std::vector<ir_instr *> m_reads;
std::vector<ir_instr *> m_writes;
// constant values
bool m_hasvalue;
union {
float vfloat;
int vint;
vector vvec;
int32_t ivec[3];
char *vstring;
struct ir_value_s *vpointer;
struct ir_function_s *vfunc;
} constval;
qcfloat_t vfloat;
int vint;
vec3_t vvec;
int32_t ivec[3];
char *vstring;
ir_value *vpointer;
ir_function *vfunc;
} m_constval;
struct {
int32_t globaladdr;
int32_t name;
/* filled by the local-allocator */
int32_t local;
/* added for members */
int32_t addroffset;
/* to generate field-addresses early */
int32_t fieldaddr;
} code;
int32_t local; // filled by the local-allocator
int32_t addroffset; // added for members
int32_t fieldaddr; // to generate field-addresses early
} m_code;
/* for acessing vectors */
struct ir_value_s *members[3];
struct ir_value_s *memberof;
// for accessing vectors
ir_value *m_members[3];
ir_value *m_memberof;
/* arrays will never overlap with temps */
bool unique_life;
/* temps living during a CALL must be locked */
bool locked;
bool callparam;
bool m_unique_life; // arrays will never overlap with temps
bool m_locked; // temps living during a CALL must be locked
bool m_callparam;
/* For the temp allocator */
ir_life_entry_t *life;
} ir_value;
std::vector<ir_life_entry_t> m_life; // For the temp allocator
int32_t ir_value_code_addr(const ir_value*);
size_t size() const;
/* ir_value can be a variable, or created by an operation */
ir_value* ir_value_var(const char *name, int st, int vtype);
/* if a result of an operation: the function should store
* it to remember to delete it / garbage collect it
*/
ir_value* ir_value_out(struct ir_function_s *owner, const char *name, int st, int vtype);
void ir_value_delete(ir_value*);
bool ir_value_set_name(ir_value*, const char *name);
ir_value* ir_value_vector_member(ir_value*, unsigned int member);
bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx);
bool GMQCC_WARN ir_value_set_float(ir_value*, float f);
bool GMQCC_WARN ir_value_set_func(ir_value*, int f);
#if 0
bool GMQCC_WARN ir_value_set_int(ir_value*, int i);
#endif
bool GMQCC_WARN ir_value_set_string(ir_value*, const char *s);
bool GMQCC_WARN ir_value_set_vector(ir_value*, vector v);
bool GMQCC_WARN ir_value_set_field(ir_value*, ir_value *fld);
/*bool ir_value_set_pointer_v(ir_value*, ir_value* p); */
/*bool ir_value_set_pointer_i(ir_value*, int i); */
/* merge an instruction into the life-range */
/* returns false if the lifepoint was already known */
bool ir_value_life_merge(ir_value*, size_t);
bool ir_value_life_merge_into(ir_value*, const ir_value*);
/* check if a value lives at a specific point */
bool ir_value_lives(ir_value*, size_t);
/* check if the life-range of 2 values overlaps */
bool ir_values_overlap(const ir_value*, const ir_value*);
void ir_value_dump(ir_value*, int (*oprintf)(const char*,...));
void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...));
void dump(int (*oprintf)(const char*, ...)) const;
};
/* PHI data */
typedef struct ir_phi_entry_s
{
ir_value *value;
struct ir_block_s *from;
} ir_phi_entry_t;
struct ir_phi_entry_t {
ir_value *value;
ir_block *from;
};
/* instruction */
typedef struct ir_instr_s
{
int opcode;
lex_ctx context;
ir_value* (_ops[3]);
struct ir_block_s* (bops[2]);
struct ir_instr {
ir_instr(lex_ctx_t, ir_block *owner, int opcode);
~ir_instr();
ir_phi_entry_t *phi;
ir_value **params;
int m_opcode;
lex_ctx_t m_context;
ir_value *(_m_ops[3]) = { nullptr, nullptr, nullptr };
ir_block *(m_bops[2]) = { nullptr, nullptr };
/* For the temp-allocation */
size_t eid;
std::vector<ir_phi_entry_t> m_phi;
std::vector<ir_value *> m_params;
/* For IFs */
bool likely;
// For the temp-allocation
size_t m_eid = 0;
struct ir_block_s *owner;
} ir_instr;
// For IFs
bool m_likely = true;
ir_instr* ir_instr_new(lex_ctx ctx, struct ir_block_s *owner, int opcode);
void ir_instr_delete(ir_instr*);
bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx);
bool ir_instr_op(ir_instr*, int op, ir_value *value, bool writing);
void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...));
ir_block *m_owner;
};
/* block */
typedef struct ir_block_s
{
char *label;
lex_ctx context;
bool final; /* once a jump is added we're done */
struct ir_block {
ir_block(ir_function *owner, const std::string& name);
~ir_block();
ir_instr **instr;
struct ir_block_s **entries;
struct ir_block_s **exits;
ir_value **living;
ir_function *m_owner;
std::string m_label;
lex_ctx_t m_context;
bool m_final = false; /* once a jump is added we're done */
std::vector<ir_instr *> m_instr;
std::vector<ir_block *> m_entries;
std::vector<ir_block *> m_exits;
std::vector<ir_value *> m_living;
/* For the temp-allocation */
size_t entry_id;
size_t eid;
bool is_return;
size_t m_entry_id = 0;
size_t m_eid = 0;
bool m_is_return = false;
struct ir_function_s *owner;
bool m_generated = false;
size_t m_code_start = 0;
};
bool generated;
size_t code_start;
} ir_block;
ir_block* ir_block_new(struct ir_function_s *owner, const char *label);
void ir_block_delete(ir_block*);
bool ir_block_set_label(ir_block*, const char *label);
ir_value* ir_block_create_binop(ir_block*, lex_ctx, const char *label, int op,
ir_value *left, ir_value *right);
ir_value* ir_block_create_unary(ir_block*, lex_ctx, const char *label, int op,
ir_value *operand);
bool GMQCC_WARN ir_block_create_store_op(ir_block*, lex_ctx, int op, ir_value *target, ir_value *what);
bool GMQCC_WARN ir_block_create_store(ir_block*, lex_ctx, ir_value *target, ir_value *what);
bool GMQCC_WARN ir_block_create_storep(ir_block*, lex_ctx, ir_value *target, ir_value *what);
/* field must be of TYPE_FIELD */
ir_value* ir_block_create_load_from_ent(ir_block*, lex_ctx, const char *label, ir_value *ent, ir_value *field, int outype);
ir_value* ir_block_create_fieldaddress(ir_block*, lex_ctx, const char *label, ir_value *entity, ir_value *field);
ir_value* ir_block_create_binop(ir_block*, lex_ctx_t, const char *label, int op, ir_value *left, ir_value *right);
ir_value* ir_block_create_unary(ir_block*, lex_ctx_t, const char *label, int op, ir_value *operand);
bool GMQCC_WARN ir_block_create_store_op(ir_block*, lex_ctx_t, int op, ir_value *target, ir_value *what);
bool GMQCC_WARN ir_block_create_storep(ir_block*, lex_ctx_t, ir_value *target, ir_value *what);
ir_value* ir_block_create_load_from_ent(ir_block*, lex_ctx_t, const char *label, ir_value *ent, ir_value *field, qc_type outype);
ir_value* ir_block_create_fieldaddress(ir_block*, lex_ctx_t, const char *label, ir_value *entity, ir_value *field);
bool GMQCC_WARN ir_block_create_state_op(ir_block*, lex_ctx_t, ir_value *frame, ir_value *think);
/* This is to create an instruction of the form
* <outtype>%label := opcode a, b
*/
ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx, const char *label,
int op, ir_value *a, ir_value *b, int outype);
ir_instr* ir_block_create_phi(ir_block*, lex_ctx, const char *label, int vtype);
ir_instr* ir_block_create_phi(ir_block*, lex_ctx_t, const char *label, qc_type vtype);
ir_value* ir_phi_value(ir_instr*);
void ir_phi_add(ir_instr*, ir_block *b, ir_value *v);
ir_instr* ir_block_create_call(ir_block*, lex_ctx, const char *label, ir_value *func, bool noreturn);
ir_instr* ir_block_create_call(ir_block*, lex_ctx_t, const char *label, ir_value *func, bool noreturn);
ir_value* ir_call_value(ir_instr*);
void ir_call_param(ir_instr*, ir_value*);
bool GMQCC_WARN ir_block_create_return(ir_block*, lex_ctx, ir_value *opt_value);
bool GMQCC_WARN ir_block_create_return(ir_block*, lex_ctx_t, ir_value *opt_value);
bool GMQCC_WARN ir_block_create_if(ir_block*, lex_ctx, ir_value *cond,
bool GMQCC_WARN ir_block_create_if(ir_block*, lex_ctx_t, ir_value *cond,
ir_block *ontrue, ir_block *onfalse);
/* A 'goto' is an actual 'goto' coded in QC, whereas
/*
* A 'goto' is an actual 'goto' coded in QC, whereas
* a 'jump' is a virtual construct which simply names the
* next block to go to.
* A goto usually becomes an OP_GOTO in the resulting code,
* whereas a 'jump' usually doesn't add any actual instruction.
*/
bool GMQCC_WARN ir_block_create_jump(ir_block*, lex_ctx, ir_block *to);
bool GMQCC_WARN ir_block_create_goto(ir_block*, lex_ctx, ir_block *to);
void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...));
bool GMQCC_WARN ir_block_create_jump(ir_block*, lex_ctx_t, ir_block *to);
bool GMQCC_WARN ir_block_create_goto(ir_block*, lex_ctx_t, ir_block *to);
/* function */
struct ir_function {
ir_function(ir_builder *owner, qc_type returntype);
~ir_function();
typedef struct ir_function_s
{
char *name;
int outtype;
int *params;
ir_block **blocks;
ir_builder *m_owner;
uint32_t flags;
std::string m_name;
qc_type m_outtype;
std::vector<int> m_params;
ir_flag_t m_flags = 0;
int m_builtin = 0;
int builtin;
std::vector<std::unique_ptr<ir_block>> m_blocks;
ir_value *value;
/* values generated from operations
/*
* values generated from operations
* which might get optimized away, so anything
* in there needs to be deleted in the dtor.
*/
ir_value **values;
std::vector<std::unique_ptr<ir_value>> m_values;
std::vector<std::unique_ptr<ir_value>> m_locals; /* locally defined variables */
ir_value *m_value = nullptr;
/* locally defined variables */
ir_value **locals;
size_t m_allocated_locals = 0;
size_t m_globaltemps = 0;
size_t allocated_locals;
size_t globaltemps;
ir_block* m_first = nullptr;
ir_block* m_last = nullptr;
ir_block* first;
ir_block* last;
lex_ctx_t m_context;
lex_ctx context;
/* for prototypes - first we generate all the
/*
* for prototypes - first we generate all the
* globals, and we remember teh function-defs
* so we can later fill in the entry pos
*
* remember the ID:
*/
qcint code_function_def;
qcint_t m_code_function_def = -1;
/* for temp allocation */
size_t run_id;
struct ir_builder_s *owner;
size_t m_run_id = 0;
/* vararg support: */
size_t max_varargs;
} ir_function;
#define IR_FLAG_HAS_ARRAYS (1<<1)
#define IR_FLAG_HAS_UNINITIALIZED (1<<2)
#define IR_FLAG_HAS_GOTO (1<<3)
#define IR_FLAG_INCLUDE_DEF (1<<4)
#define IR_FLAG_MASK_NO_OVERLAP (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED)
#define IR_FLAG_MASK_NO_LOCAL_TEMPS (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED)
size_t m_max_varargs = 0;
};
ir_function* ir_function_new(struct ir_builder_s *owner, int returntype);
void ir_function_delete(ir_function*);
void ir_function_collect_value(ir_function*, ir_value *value);
bool ir_function_set_name(ir_function*, const char *name);
ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param);
ir_value* ir_function_create_local(ir_function *self, const std::string& name, qc_type vtype, bool param);
bool GMQCC_WARN ir_function_finalize(ir_function*);
/*
bool ir_function_naive_phi(ir_function*);
bool ir_function_enumerate(ir_function*);
bool ir_function_calculate_liferanges(ir_function*);
*/
ir_block* ir_function_create_block(lex_ctx ctx, ir_function*, const char *label);
void ir_function_dump(ir_function*, char *ind, int (*oprintf)(const char*,...));
ir_block* ir_function_create_block(lex_ctx_t ctx, ir_function*, const char *label);
/* builder */
#define IR_HT_SIZE 1024
typedef struct ir_builder_s
{
char *name;
ir_function **functions;
ir_value **globals;
ir_value **fields;
#define IR_HT_SIZE 1024
#define IR_MAX_VINSTR_TEMPS 2
ht htfunctions;
ht htglobals;
ht htfields;
struct ir_builder {
ir_builder(const std::string& modulename);
~ir_builder();
ir_value **extparams;
ir_value **extparam_protos;
ir_function *createFunction(const std::string &name, qc_type outtype);
ir_value *createGlobal(const std::string &name, qc_type vtype);
ir_value *createField(const std::string &name, qc_type vtype);
ir_value *get_va_count();
bool generate(const char *filename);
void dump(int (*oprintf)(const char*, ...)) const;
/* the highest func->allocated_locals */
size_t max_locals;
size_t max_globaltemps;
uint32_t first_common_local;
uint32_t first_common_globaltemp;
ir_value *generateExtparamProto();
void generateExtparam();
const char **filenames;
qcint *filestrings;
/* we cache the #IMMEDIATE string here */
qcint str_immediate;
/* there should just be this one nil */
ir_value *nil;
ir_value *reserved_va_count;
} ir_builder;
ir_value *literalFloat(float value, bool add_to_list);
ir_builder* ir_builder_new(const char *modulename);
void ir_builder_delete(ir_builder*);
std::string m_name;
std::vector<std::unique_ptr<ir_function>> m_functions;
std::vector<std::unique_ptr<ir_value>> m_globals;
std::vector<std::unique_ptr<ir_value>> m_fields;
// for reusing them in vector-splits, TODO: sort this or use a radix-tree
std::vector<ir_value*> m_const_floats;
bool ir_builder_set_name(ir_builder *self, const char *name);
ht m_htfunctions;
ht m_htglobals;
ht m_htfields;
ir_function* ir_builder_get_function(ir_builder*, const char *fun);
ir_function* ir_builder_create_function(ir_builder*, const char *name, int outtype);
// extparams' ir_values reference the ones from extparam_protos
std::vector<std::unique_ptr<ir_value>> m_extparam_protos;
std::vector<ir_value*> m_extparams;
ir_value* ir_builder_get_global(ir_builder*, const char *fun);
ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype);
ir_value* ir_builder_get_field(ir_builder*, const char *fun);
ir_value* ir_builder_create_field(ir_builder*, const char *name, int vtype);
// the highest func->allocated_locals
size_t m_max_locals = 0;
size_t m_max_globaltemps = 0;
uint32_t m_first_common_local = 0;
uint32_t m_first_common_globaltemp = 0;
ir_value* ir_builder_get_va_count(ir_builder*);
std::vector<const char*> m_filenames;
std::vector<qcint_t> m_filestrings;
bool ir_builder_generate(ir_builder *self, const char *filename);
// we cache the #IMMEDIATE string here
qcint_t m_str_immediate = 0;
void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...));
// there should just be this one nil
ir_value *m_nil;
ir_value *m_reserved_va_count = nullptr;
ir_value *m_coverage_func = nullptr;
/* This code assumes 32 bit floats while generating binary */
extern int check_int_and_float_size
[ (sizeof(int32_t) == sizeof(qcfloat)) ? 1 : -1 ];
/* some virtual instructions require temps, and their code is isolated
* so that we don't need to keep track of their liveness.
*/
ir_value *m_vinstr_temp[IR_MAX_VINSTR_TEMPS];
/* code generator */
std::unique_ptr<code_t> m_code;
private:
qcint_t filestring(const char *filename);
bool generateGlobal(ir_value*, bool is_local);
bool generateGlobalFunction(ir_value*);
bool generateGlobalFunctionCode(ir_value*);
bool generateFunctionLocals(ir_value*);
};
/*
* This code assumes 32 bit floats while generating binary
* Blub: don't use extern here, it's annoying and shows up in nm
* for some reason :P
*/
typedef int static_assert_is_32bit_float [(sizeof(int32_t) == 4) ? 1 : -1];
typedef int static_assert_is_32bit_integer[(sizeof(qcfloat_t) == 4) ? 1 : -1];
/*
* If the condition creates a situation where this becomes -1 size it means there are
* more IR_FLAGs than the type ir_flag_t is capable of holding. So either eliminate
* the IR flag count or change the ir_flag_t typedef to a type large enough to accomodate
* all the flags.
*/
typedef int static_assert_is_ir_flag_safe [((IR_FLAG_LAST) <= (ir_flag_t)(-1)) ? 1 : -1];
#endif

View file

@ -1,29 +1,5 @@
/*
* Copyright (C) 2012, 2013
* Wolfgang Bumiller
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include "gmqcc.h"
#include "lexer.h"
@ -40,8 +16,6 @@ static const char *keywords_qc[] = {
"return",
"const"
};
static size_t num_keywords_qc = sizeof(keywords_qc) / sizeof(keywords_qc[0]);
/* For fte/gmgqcc */
static const char *keywords_fg[] = {
"switch", "case", "default",
@ -52,34 +26,33 @@ static const char *keywords_fg[] = {
"__builtin_debug_printtype"
};
static size_t num_keywords_fg = sizeof(keywords_fg) / sizeof(keywords_fg[0]);
/*
* Lexer code
*/
static char* *lex_filenames;
void lexerror(lex_file *lex, const char *fmt, ...)
static void lexerror(lex_file *lex, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (lex)
con_vprintmsg(LVL_ERROR, lex->name, lex->sline, "parse error", fmt, ap);
con_vprintmsg(LVL_ERROR, lex->name, lex->sline, lex->column, "parse error", fmt, ap);
else
con_vprintmsg(LVL_ERROR, "", 0, "parse error", fmt, ap);
con_vprintmsg(LVL_ERROR, "", 0, 0, "parse error", fmt, ap);
va_end(ap);
}
bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...)
static bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...)
{
bool r;
lex_ctx ctx;
va_list ap;
bool r;
lex_ctx_t ctx;
va_list ap;
ctx.file = lex->name;
ctx.line = lex->sline;
ctx.file = lex->name;
ctx.line = lex->sline;
ctx.column = lex->column;
va_start(ap, fmt);
r = vcompile_warning(ctx, warntype, fmt, ap);
@ -87,125 +60,59 @@ bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...)
return r;
}
#if 0
token* token_new()
{
token *tok = (token*)mem_a(sizeof(token));
if (!tok)
return NULL;
memset(tok, 0, sizeof(*tok));
return tok;
}
void token_delete(token *self)
{
if (self->next && self->next->prev == self)
self->next->prev = self->prev;
if (self->prev && self->prev->next == self)
self->prev->next = self->next;
MEM_VECTOR_CLEAR(self, value);
mem_d(self);
}
token* token_copy(const token *cp)
{
token* self = token_new();
if (!self)
return NULL;
/* copy the value */
self->value_alloc = cp->value_count + 1;
self->value_count = cp->value_count;
self->value = (char*)mem_a(self->value_alloc);
if (!self->value) {
mem_d(self);
return NULL;
}
memcpy(self->value, cp->value, cp->value_count);
self->value[self->value_alloc-1] = 0;
/* rest */
self->ctx = cp->ctx;
self->ttype = cp->ttype;
memcpy(&self->constval, &cp->constval, sizeof(self->constval));
return self;
}
void token_delete_all(token *t)
{
token *n;
do {
n = t->next;
token_delete(t);
t = n;
} while(t);
}
token* token_copy_all(const token *cp)
{
token *cur;
token *out;
out = cur = token_copy(cp);
if (!out)
return NULL;
while (cp->next) {
cp = cp->next;
cur->next = token_copy(cp);
if (!cur->next) {
token_delete_all(out);
return NULL;
}
cur->next->prev = cur;
cur = cur->next;
}
return out;
}
#else
static void lex_token_new(lex_file *lex)
{
#if 0
if (lex->tok)
token_delete(lex->tok);
lex->tok = token_new();
#else
if (lex->tok.value)
vec_shrinkto(lex->tok.value, 0);
lex->tok.constval.t = 0;
lex->tok.ctx.line = lex->sline;
lex->tok.ctx.file = lex->name;
#endif
lex->tok.constval.t = TYPE_VOID;
lex->tok.ctx.line = lex->sline;
lex->tok.ctx.file = lex->name;
lex->tok.ctx.column = lex->column;
}
#endif
static void lex_ungetch(lex_file *lex, int ch);
static int lex_getch(lex_file *lex);
lex_file* lex_open(const char *file)
{
lex_file *lex;
FILE *in = fs_file_open(file, "rb");
lex_file *lex;
FILE *in = fopen(file, "rb");
uint32_t read;
if (!in) {
lexerror(NULL, "open failed: '%s'\n", file);
return NULL;
lexerror(nullptr, "open failed: '%s'\n", file);
return nullptr;
}
lex = (lex_file*)mem_a(sizeof(*lex));
if (!lex) {
fs_file_close(in);
lexerror(NULL, "out of memory\n");
return NULL;
fclose(in);
lexerror(nullptr, "out of memory\n");
return nullptr;
}
memset(lex, 0, sizeof(*lex));
lex->file = in;
lex->name = util_strdup(file);
lex->line = 1; /* we start counting at 1 */
lex->file = in;
lex->name = util_strdup(file);
lex->line = 1; /* we start counting at 1 */
lex->column = 0;
lex->peekpos = 0;
lex->eof = false;
lex->eof = false;
/* handle BOM */
if ((read = (lex_getch(lex) << 16) | (lex_getch(lex) << 8) | lex_getch(lex)) != 0xEFBBBF) {
lex_ungetch(lex, (read & 0x0000FF));
lex_ungetch(lex, (read & 0x00FF00) >> 8);
lex_ungetch(lex, (read & 0xFF0000) >> 16);
} else {
/*
* otherwise the lexer has advanced 3 bytes for the BOM, we need
* to set the column back to 0
*/
lex->column = 0;
}
vec_push(lex_filenames, lex->name);
return lex;
@ -217,22 +124,22 @@ lex_file* lex_open_string(const char *str, size_t len, const char *name)
lex = (lex_file*)mem_a(sizeof(*lex));
if (!lex) {
lexerror(NULL, "out of memory\n");
return NULL;
lexerror(nullptr, "out of memory\n");
return nullptr;
}
memset(lex, 0, sizeof(*lex));
lex->file = NULL;
lex->file = nullptr;
lex->open_string = str;
lex->open_string_length = len;
lex->open_string_pos = 0;
lex->name = util_strdup(name ? name : "<string-source>");
lex->line = 1; /* we start counting at 1 */
lex->name = util_strdup(name ? name : "<string-source>");
lex->line = 1; /* we start counting at 1 */
lex->peekpos = 0;
lex->eof = false;
lex->eof = false;
lex->column = 0;
vec_push(lex_filenames, lex->name);
@ -258,24 +165,26 @@ void lex_close(lex_file *lex)
vec_free(lex->modelname);
if (lex->file)
fs_file_close(lex->file);
#if 0
if (lex->tok)
token_delete(lex->tok);
#else
fclose(lex->file);
vec_free(lex->tok.value);
#endif
/* mem_d(lex->name); collected in lex_filenames */
mem_d(lex);
}
static int lex_fgetc(lex_file *lex)
{
if (lex->file)
return fs_file_getc(lex->file);
if (lex->file) {
lex->column++;
return fgetc(lex->file);
}
if (lex->open_string) {
if (lex->open_string_pos >= lex->open_string_length)
return EOF;
lex->column++;
return lex->open_string[lex->open_string_pos++];
}
return EOF;
@ -286,21 +195,26 @@ static int lex_fgetc(lex_file *lex)
* are working on.
* The are merely wrapping get/put in order to count line numbers.
*/
static void lex_ungetch(lex_file *lex, int ch);
static int lex_try_trigraph(lex_file *lex, int old)
{
int c2, c3;
c2 = lex_fgetc(lex);
if (!lex->push_line && c2 == '\n')
if (!lex->push_line && c2 == '\n') {
lex->line++;
lex->column = 0;
}
if (c2 != '?') {
lex_ungetch(lex, c2);
return old;
}
c3 = lex_fgetc(lex);
if (!lex->push_line && c3 == '\n')
if (!lex->push_line && c3 == '\n') {
lex->line++;
lex->column = 0;
}
switch (c3) {
case '=': return '#';
case '/': return '\\';
@ -347,14 +261,18 @@ static int lex_getch(lex_file *lex)
if (lex->peekpos) {
lex->peekpos--;
if (!lex->push_line && lex->peek[lex->peekpos] == '\n')
if (!lex->push_line && lex->peek[lex->peekpos] == '\n') {
lex->line++;
lex->column = 0;
}
return lex->peek[lex->peekpos];
}
ch = lex_fgetc(lex);
if (!lex->push_line && ch == '\n')
if (!lex->push_line && ch == '\n') {
lex->line++;
lex->column = 0;
}
else if (ch == '?')
return lex_try_trigraph(lex, ch);
else if (!lex->flags.nodigraphs && (ch == '<' || ch == ':' || ch == '%'))
@ -365,8 +283,11 @@ static int lex_getch(lex_file *lex)
static void lex_ungetch(lex_file *lex, int ch)
{
lex->peek[lex->peekpos++] = ch;
if (!lex->push_line && ch == '\n')
lex->column--;
if (!lex->push_line && ch == '\n') {
lex->line--;
lex->column = 0;
}
}
/* classify characters
@ -376,12 +297,12 @@ static void lex_ungetch(lex_file *lex, int ch)
/* Idents are alphanumberic, but they start with alpha or _ */
static bool isident_start(int ch)
{
return isalpha(ch) || ch == '_';
return util_isalpha(ch) || ch == '_';
}
static bool isident(int ch)
static bool isident(int ch, bool allow_dot)
{
return isident_start(ch) || isdigit(ch);
return isident_start(ch) || util_isdigit(ch) || (allow_dot && ch == '.');
}
/* isxdigit_only is used when we already know it's not a digit
@ -408,9 +329,9 @@ static void lex_endtoken(lex_file *lex)
static bool lex_try_pragma(lex_file *lex)
{
int ch;
char *pragma = NULL;
char *command = NULL;
char *param = NULL;
char *pragma = nullptr;
char *command = nullptr;
char *param = nullptr;
size_t line;
if (lex->flags.preprocessing)
@ -471,11 +392,12 @@ static bool lex_try_pragma(lex_file *lex)
goto unroll;
}
else if (!strcmp(command, "file")) {
lex->framevalue = 0;
lex->name = util_strdup(param);
vec_push(lex_filenames, lex->name);
}
else if (!strcmp(command, "line")) {
line = strtol(param, NULL, 0)-1;
line = strtol(param, nullptr, 0)-1;
}
else
goto unroll;
@ -561,7 +483,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
do
{
ch = lex_getch(lex);
while (ch != EOF && isspace(ch)) {
while (ch != EOF && util_isspace(ch)) {
if (ch == '\n') {
if (lex_try_pragma(lex))
continue;
@ -593,10 +515,6 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
if (lex->flags.preprocessing) {
haswhite = true;
/*
lex_tokench(lex, '/');
lex_tokench(lex, '/');
*/
lex_tokench(lex, ' ');
lex_tokench(lex, ' ');
}
@ -618,10 +536,6 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
/* multiline comment */
if (lex->flags.preprocessing) {
haswhite = true;
/*
lex_tokench(lex, '/');
lex_tokench(lex, '*');
*/
lex_tokench(lex, ' ');
lex_tokench(lex, ' ');
}
@ -633,10 +547,6 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
ch = lex_getch(lex);
if (ch == '/') {
if (lex->flags.preprocessing) {
/*
lex_tokench(lex, '*');
lex_tokench(lex, '/');
*/
lex_tokench(lex, ' ');
lex_tokench(lex, ' ');
}
@ -648,7 +558,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
if (ch == '\n')
lex_tokench(lex, '\n');
else
lex_tokench(lex, ' '); /* ch); */
lex_tokench(lex, ' ');
}
}
ch = ' '; /* cause TRUE in the isspace check */
@ -659,7 +569,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
ch = '/';
break;
}
} while (ch != EOF && isspace(ch));
} while (ch != EOF && util_isspace(ch));
if (haswhite) {
lex_endtoken(lex);
@ -670,12 +580,12 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
}
/* Get a token */
static bool GMQCC_WARN lex_finish_ident(lex_file *lex)
static bool GMQCC_WARN lex_finish_ident(lex_file *lex, bool allow_dot)
{
int ch;
ch = lex_getch(lex);
while (ch != EOF && isident(ch))
while (ch != EOF && isident(ch, allow_dot))
{
lex_tokench(lex, ch);
ch = lex_getch(lex);
@ -695,19 +605,19 @@ static int lex_parse_frame(lex_file *lex)
lex_token_new(lex);
ch = lex_getch(lex);
while (ch != EOF && ch != '\n' && isspace(ch))
while (ch != EOF && ch != '\n' && util_isspace(ch))
ch = lex_getch(lex);
if (ch == '\n')
return 1;
if (!isident_start(ch)) {
lexerror(lex, "invalid framename, must start with one of a-z or _, got %c", ch);
lexerror(lex, "invalid framename, must start with one of a-z, or _, got %c", ch);
return -1;
}
lex_tokench(lex, ch);
if (!lex_finish_ident(lex))
if (!lex_finish_ident(lex, true))
return -1;
lex_endtoken(lex);
return 0;
@ -749,10 +659,11 @@ static bool lex_finish_frames(lex_file *lex)
static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
{
uchar_t chr;
int ch = 0;
utf8ch_t chr = 0;
int ch = 0, texttype = 0;
int nextch;
bool hex;
bool oct;
char u8buf[8]; /* way more than enough */
int u8len, uc;
@ -784,13 +695,12 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
case '\\': break;
case '\'': break;
case '"': break;
case 'a': ch = '\a'; break;
case 'b': ch = '\b'; break;
case 'r': ch = '\r'; break;
case 'n': ch = '\n'; break;
case 't': ch = '\t'; break;
case 'f': ch = '\f'; break;
case 'v': ch = '\v'; break;
case 'a': ch = '\a'; break;
case 'r': ch = '\r'; break;
case 'n': ch = '\n'; break;
case 't': ch = '\t'; break;
case 'f': ch = '\f'; break;
case 'v': ch = '\v'; break;
case 'x':
case 'X':
/* same procedure as in fteqcc */
@ -838,17 +748,18 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
chr = 0;
nextch = lex_getch(lex);
hex = (nextch == 'x');
if (!hex)
oct = (nextch == '0');
if (!hex && !oct)
lex_ungetch(lex, nextch);
for (nextch = lex_getch(lex); nextch != '}'; nextch = lex_getch(lex)) {
if (!hex) {
if (!hex && !oct) {
if (nextch >= '0' && nextch <= '9')
chr = chr * 10 + nextch - '0';
else {
lexerror(lex, "bad character code");
return (lex->tok.ttype = TOKEN_ERROR);
}
} else {
} else if (!oct) {
if (nextch >= '0' && nextch <= '9')
chr = chr * 0x10 + nextch - '0';
else if (nextch >= 'a' && nextch <= 'f')
@ -859,6 +770,13 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
lexerror(lex, "bad character code");
return (lex->tok.ttype = TOKEN_ERROR);
}
} else {
if (nextch >= '0' && nextch <= '9')
chr = chr * 8 + chr - '0';
else {
lexerror(lex, "bad character code");
return (lex->tok.ttype = TOKEN_ERROR);
}
}
if (chr > 0x10FFFF || (!OPTS_FLAG(UTF8) && chr > 255))
{
@ -867,14 +785,16 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
}
}
if (OPTS_FLAG(UTF8) && chr >= 128) {
u8len = u8_fromchar(chr, u8buf, sizeof(u8buf));
u8len = utf8_from(u8buf, chr);
if (!u8len)
ch = 0;
else {
--u8len;
lex->column += u8len;
for (uc = 0; uc < u8len; ++uc)
lex_tokench(lex, u8buf[uc]);
/* the last character will be inserted with the tokench() call
/*
* the last character will be inserted with the tokench() call
* below the switch
*/
ch = u8buf[uc];
@ -883,7 +803,15 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
else
ch = chr;
break;
case '\n': ch = '\n'; break;
/* high bit text */
case 'b': case 's':
texttype ^= 128;
continue;
case '\n':
ch = '\n';
break;
default:
lexwarn(lex, WARN_UNKNOWN_CONTROL_SEQUENCE, "unrecognized control sequence: \\%c", ch);
@ -891,7 +819,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
lex_tokench(lex, '\\');
}
/* add the character finally */
lex_tokench(lex, ch);
lex_tokench(lex, ch | texttype);
}
else
lex_tokench(lex, ch);
@ -904,6 +832,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
{
bool ishex = false;
bool isoct = false;
int ch = lastch;
@ -916,7 +845,16 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
lex_tokench(lex, ch);
ch = lex_getch(lex);
if (ch != '.' && !isdigit(ch))
if (lastch == '0' && util_isdigit(ch)) {
if (ch < '0' || ch > '7') {
lexerror(lex, "invalid octal constant");
return (lex->tok.ttype = TOKEN_ERROR);
}
isoct = true;
}
if (!isoct && ch != '.' && !util_isdigit(ch))
{
if (lastch != '0' || ch != 'x')
{
@ -937,7 +875,7 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
{
lex_tokench(lex, ch);
ch = lex_getch(lex);
while (isdigit(ch) || (ishex && isxdigit_only(ch)))
while (util_isdigit(ch) || (ishex && isxdigit_only(ch)))
{
lex_tokench(lex, ch);
ch = lex_getch(lex);
@ -952,7 +890,7 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
/* continue digits-only */
ch = lex_getch(lex);
while (isdigit(ch))
while (util_isdigit(ch))
{
lex_tokench(lex, ch);
ch = lex_getch(lex);
@ -964,17 +902,22 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
ch = lex_getch(lex);
/* generally we don't want words to follow numbers: */
if (isident(ch)) {
if (isident(ch, false)) {
lexerror(lex, "unexpected trailing characters after number");
return (lex->tok.ttype = TOKEN_ERROR);
}
lex_ungetch(lex, ch);
lex_endtoken(lex);
if (lex->tok.ttype == TOKEN_FLOATCONST)
lex->tok.constval.f = strtod(lex->tok.value, NULL);
else
lex->tok.constval.i = strtol(lex->tok.value, NULL, 0);
if (lex->tok.ttype == TOKEN_FLOATCONST) {
lex->tok.constval.f = strtod(lex->tok.value, nullptr);
} else {
/* determine base for strtol */
int base = 10;
if (ishex) base = 16;
if (isoct) base = 8;
lex->tok.constval.i = strtol(lex->tok.value, nullptr, base);
}
return lex->tok.ttype;
}
@ -984,10 +927,6 @@ int lex_do(lex_file *lex)
bool hadwhite = false;
lex_token_new(lex);
#if 0
if (!lex->tok)
return TOKEN_FATAL;
#endif
while (true) {
ch = lex_skipwhite(lex, hadwhite);
@ -1034,7 +973,7 @@ int lex_do(lex_file *lex)
return lex_do(lex);
}
lex_tokench(lex, ch);
if (!lex_finish_ident(lex))
if (!lex_finish_ident(lex, true))
return (lex->tok.ttype = TOKEN_ERROR);
lex_endtoken(lex);
/* skip the known commands */
@ -1055,10 +994,10 @@ int lex_do(lex_file *lex)
if (!strcmp(v, "framevalue"))
{
ch = lex_getch(lex);
while (ch != EOF && isspace(ch) && ch != '\n')
while (ch != EOF && util_isspace(ch) && ch != '\n')
ch = lex_getch(lex);
if (!isdigit(ch)) {
if (!util_isdigit(ch)) {
lexerror(lex, "$framevalue requires an integer parameter");
return lex_do(lex);
}
@ -1119,11 +1058,11 @@ int lex_do(lex_file *lex)
frame_macro m;
m.value = lex->framevalue;
m.name = lex->modelname;
lex->modelname = NULL;
lex->modelname = nullptr;
vec_push(lex->frames, m);
}
lex->modelname = lex->tok.value;
lex->tok.value = NULL;
lex->tok.value = nullptr;
return lex_do(lex);
}
@ -1216,7 +1155,7 @@ int lex_do(lex_file *lex)
if (ch == '.') {
nextch = lex_getch(lex);
/* digits starting with a dot */
if (isdigit(nextch)) {
if (util_isdigit(nextch)) {
lex_ungetch(lex, nextch);
lex->tok.ttype = lex_finish_digit(lex, ch);
lex_endtoken(lex);
@ -1232,10 +1171,6 @@ int lex_do(lex_file *lex)
*/
switch (ch)
{
/*
case '+':
case '-':
*/
case '*':
case '/':
case '<':
@ -1293,16 +1228,22 @@ int lex_do(lex_file *lex)
}
if (ch == '+' || ch == '-' || /* ++, --, +=, -= and -> as well! */
ch == '>' || ch == '<' || /* <<, >>, <=, >= */
ch == '>' || ch == '<' || /* <<, >>, <=, >= and >< as well! */
ch == '=' || ch == '!' || /* <=>, ==, != */
ch == '&' || ch == '|' || /* &&, ||, &=, |= */
ch == '~' /* ~=, ~ */
ch == '~' || ch == '^' /* ~=, ~, ^ */
) {
lex_tokench(lex, ch);
nextch = lex_getch(lex);
if ((nextch == '=' && ch != '<') || (nextch == ch && ch != '!')) {
if ((nextch == '=' && ch != '<') || (nextch == '<' && ch == '>'))
lex_tokench(lex, nextch);
else if (nextch == ch && ch != '!') {
lex_tokench(lex, nextch);
if ((thirdch = lex_getch(lex)) == '=')
lex_tokench(lex, thirdch);
else
lex_ungetch(lex, thirdch);
} else if (ch == '<' && nextch == '=') {
lex_tokench(lex, nextch);
if ((thirdch = lex_getch(lex)) == '>')
@ -1324,7 +1265,7 @@ int lex_do(lex_file *lex)
}
}
else if (lex->flags.preprocessing &&
ch == '-' && isdigit(nextch))
ch == '-' && util_isdigit(nextch))
{
lex->tok.ttype = lex_finish_digit(lex, nextch);
if (lex->tok.ttype == TOKEN_INTCONST)
@ -1341,15 +1282,6 @@ int lex_do(lex_file *lex)
return (lex->tok.ttype = TOKEN_OPERATOR);
}
/*
if (ch == '^' || ch == '~' || ch == '!')
{
lex_tokench(lex, ch);
lex_endtoken(lex);
return (lex->tok.ttype = TOKEN_OPERATOR);
}
*/
if (ch == '*' || ch == '/') /* *=, /= */
{
lex_tokench(lex, ch);
@ -1375,7 +1307,7 @@ int lex_do(lex_file *lex)
const char *v;
lex_tokench(lex, ch);
if (!lex_finish_ident(lex)) {
if (!lex_finish_ident(lex, false)) {
/* error? */
return (lex->tok.ttype = TOKEN_ERROR);
}
@ -1401,14 +1333,16 @@ int lex_do(lex_file *lex)
} else if (!strcmp(v, "vector")) {
lex->tok.ttype = TOKEN_TYPENAME;
lex->tok.constval.t = TYPE_VECTOR;
} else if (!strcmp(v, "_length")) {
lex->tok.ttype = TOKEN_OPERATOR;
} else {
size_t kw;
for (kw = 0; kw < num_keywords_qc; ++kw) {
for (kw = 0; kw < GMQCC_ARRAY_COUNT(keywords_qc); ++kw) {
if (!strcmp(v, keywords_qc[kw]))
return (lex->tok.ttype = TOKEN_KEYWORD);
}
if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_QCC) {
for (kw = 0; kw < num_keywords_fg; ++kw) {
for (kw = 0; kw < GMQCC_ARRAY_COUNT(keywords_fg); ++kw) {
if (!strcmp(v, keywords_fg[kw]))
return (lex->tok.ttype = TOKEN_KEYWORD);
}
@ -1457,14 +1391,10 @@ int lex_do(lex_file *lex)
lex_endtoken(lex);
lex->tok.ttype = TOKEN_CHARCONST;
/* It's a vector if we can successfully scan 3 floats */
#ifdef _MSC_VER
if (sscanf_s(lex->tok.value, " %f %f %f ",
/* It's a vector if we can successfully scan 3 floats */
if (util_sscanf(lex->tok.value, " %f %f %f ",
&lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
#else
if (sscanf(lex->tok.value, " %f %f %f ",
&lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
#endif
{
lex->tok.ttype = TOKEN_VECTORCONST;
@ -1472,9 +1402,9 @@ int lex_do(lex_file *lex)
else
{
if (!lex->flags.preprocessing && strlen(lex->tok.value) > 1) {
uchar_t u8char;
utf8ch_t u8char;
/* check for a valid utf8 character */
if (!OPTS_FLAG(UTF8) || !u8_analyze(lex->tok.value, NULL, NULL, &u8char, 8)) {
if (!OPTS_FLAG(UTF8) || !utf8_to(&u8char, (const unsigned char *)lex->tok.value, 8)) {
if (lexwarn(lex, WARN_MULTIBYTE_CHARACTER,
( OPTS_FLAG(UTF8) ? "invalid multibyte character sequence `%s`"
: "multibyte character: `%s`" ),
@ -1491,7 +1421,7 @@ int lex_do(lex_file *lex)
return lex->tok.ttype;
}
if (isdigit(ch))
if (util_isdigit(ch))
{
lex->tok.ttype = lex_finish_digit(lex, ch);
lex_endtoken(lex);
@ -1504,6 +1434,6 @@ int lex_do(lex_file *lex)
return (lex->tok.ttype = ch);
}
lexerror(lex, "unknown token: `%s`", lex->tok.value);
lexerror(lex, "unknown token: `%c`", ch);
return (lex->tok.ttype = TOKEN_ERROR);
}

339
lexer.h
View file

@ -1,58 +1,19 @@
/*
* Copyright (C) 2012, 2013
* Wolfgang Bumiller
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef GMQCC_LEXER_HDR
#define GMQCC_LEXER_HDR
#include "gmqcc.h"
typedef struct token_s token;
struct token_s {
struct token {
int ttype;
char *value;
union {
vector v;
int i;
double f;
int t; /* type */
vec3_t v;
int i;
qcfloat_t f;
qc_type t; /* type */
} constval;
#if 0
struct token_s *next;
struct token_s *prev;
#endif
lex_ctx ctx;
lex_ctx_t ctx;
};
#if 0
token* token_new();
void token_delete(token*);
token* token_copy(const token *cp);
void token_delete_all(token *t);
token* token_copy_all(const token *cp);
#endif
/* Lexer
*
*/
@ -87,7 +48,11 @@ enum {
TOKEN_WHITE,
TOKEN_EOL,
TOKEN_EOF,
/* if we add additional tokens before this, the exposed API
* should not be broken anyway, but EOF/ERROR/... should
* still be at the bottom
*/
TOKEN_EOF = 1024,
/* We use '< TOKEN_ERROR', so TOKEN_FATAL must come after it and any
* other error related tokens as well
@ -96,13 +61,13 @@ enum {
TOKEN_FATAL /* internal error, eg out of memory */
};
typedef struct {
struct frame_macro {
char *name;
int value;
} frame_macro;
int value;
};
typedef struct lex_file_s {
FILE *file;
struct lex_file {
FILE *file;
const char *open_string;
size_t open_string_length;
size_t open_string_pos;
@ -110,6 +75,7 @@ typedef struct lex_file_s {
char *name;
size_t line;
size_t sline; /* line at the start of a token */
size_t column;
int peek[256];
size_t peekpos;
@ -119,18 +85,18 @@ typedef struct lex_file_s {
token tok; /* not a pointer anymore */
struct {
bool noops;
bool nodigraphs; /* used when lexing string constants */
bool preprocessing; /* whitespace and EOLs become actual tokens */
bool mergelines; /* backslash at the end of a line escapes the newline */
} flags;
unsigned noops:1;
unsigned nodigraphs:1; /* used when lexing string constants */
unsigned preprocessing:1; /* whitespace and EOLs become actual tokens */
unsigned mergelines:1; /* backslash at the end of a line escapes the newline */
} flags; /* sizeof == 1 */
int framevalue;
frame_macro *frames;
char *modelname;
size_t push_line;
} lex_file;
};
lex_file* lex_open (const char *file);
lex_file* lex_open_string(const char *str, size_t len, const char *name);
@ -150,187 +116,188 @@ enum {
#define OP_SUFFIX 1
#define OP_PREFIX 2
typedef struct {
struct oper_info {
const char *op;
unsigned int operands;
unsigned int id;
unsigned int assoc;
signed int prec;
unsigned int flags;
} oper_info;
bool folds;
};
#define opid1(a) (a)
#define opid2(a,b) ((a<<8)|b)
#define opid3(a,b,c) ((a<<16)|(b<<8)|c)
/*
* Explicit uint8_t casts since the left operand of shift operator cannot
* be negative, even though it won't happen, this supresses the future
* possibility.
*/
#define opid1(a) ((uint8_t)a)
#define opid2(a,b) (((uint8_t)a<<8) |(uint8_t)b)
#define opid3(a,b,c) (((uint8_t)a<<16)|((uint8_t)b<<8)|(uint8_t)c)
static const oper_info c_operators[] = {
{ "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */
{ "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* paren expression - non function call */
{ "_length", 1, opid3('l','e','n'), ASSOC_RIGHT, 98, OP_PREFIX, true},
{ "++", 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('S','+','+'), ASSOC_LEFT, 17, OP_SUFFIX, false},
{ "--", 1, opid3('S','-','-'), ASSOC_LEFT, 17, OP_SUFFIX, false},
{ ".", 2, opid1('.'), ASSOC_LEFT, 17, 0, false},
{ "(", 0, opid1('('), ASSOC_LEFT, 17, 0, false}, /* function call */
{ "[", 2, opid1('['), ASSOC_LEFT, 17, 0, false}, /* array subscript */
{ "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 16, OP_PREFIX },
{ "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 16, OP_PREFIX },
{ "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 16, OP_PREFIX, false},
{ "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 16, OP_PREFIX, false},
{ "**", 2, opid2('*', '*'), ASSOC_RIGHT, 15, 0 },
{ "**", 2, opid2('*','*'), ASSOC_RIGHT, 14, 0, true},
{ "!", 1, opid2('!','P'), ASSOC_RIGHT, 14, OP_PREFIX, true},
{ "~", 1, opid2('~','P'), ASSOC_RIGHT, 14, OP_PREFIX, true},
{ "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
{ "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX, true},
/* { "&", 1, opid2('&','P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, */
{ "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
{ "~", 1, opid2('~', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
{ "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX },
{ "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX },
/* { "&", 1, opid2('&','P'), ASSOC_RIGHT, 14, OP_PREFIX }, */
{ "*", 2, opid1('*'), ASSOC_LEFT, 13, 0, true},
{ "/", 2, opid1('/'), ASSOC_LEFT, 13, 0, true},
{ "%", 2, opid1('%'), ASSOC_LEFT, 13, 0, true},
{ "><", 2, opid2('>','<'), ASSOC_LEFT, 13, 0, true},
{ "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 },
{ "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 },
{ "%", 2, opid1('%'), ASSOC_LEFT, 13, 0 },
{ "+", 2, opid1('+'), ASSOC_LEFT, 12, 0, true},
{ "-", 2, opid1('-'), ASSOC_LEFT, 12, 0, true},
{ "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 },
{ "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 },
{ "<<", 2, opid2('<','<'), ASSOC_LEFT, 11, 0, true},
{ ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0, true},
{ "<<", 2, opid2('<','<'), ASSOC_LEFT, 11, 0 },
{ ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0 },
{ "<", 2, opid1('<'), ASSOC_LEFT, 10, 0, false},
{ ">", 2, opid1('>'), ASSOC_LEFT, 10, 0, false},
{ "<=>", 2, opid3('<','=','>'), ASSOC_LEFT, 10, 0, true},
{ "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0, false},
{ ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0, false},
{ "<", 2, opid1('<'), ASSOC_LEFT, 10, 0 },
{ ">", 2, opid1('>'), ASSOC_LEFT, 10, 0 },
{ "<=>", 2, opid3('<','=','>'), ASSOC_LEFT, 10, 0 },
{ "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0 },
{ ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0 },
{ "==", 2, opid2('=','='), ASSOC_LEFT, 9, 0, true},
{ "!=", 2, opid2('!','='), ASSOC_LEFT, 9, 0, true},
{ "==", 2, opid2('=','='), ASSOC_LEFT, 9, 0 },
{ "!=", 2, opid2('!','='), ASSOC_LEFT, 9, 0 },
{ "&", 2, opid1('&'), ASSOC_LEFT, 8, 0, true},
{ "&", 2, opid1('&'), ASSOC_LEFT, 8, 0 },
{ "^", 2, opid1('^'), ASSOC_LEFT, 7, 0, true},
{ "^", 2, opid1('^'), ASSOC_LEFT, 7, 0 },
{ "|", 2, opid1('|'), ASSOC_LEFT, 6, 0, true},
{ "|", 2, opid1('|'), ASSOC_LEFT, 6, 0 },
{ "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0, true},
{ "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 },
{ "||", 2, opid2('|','|'), ASSOC_LEFT, 4, 0, true},
{ "||", 2, opid2('|','|'), ASSOC_LEFT, 4, 0 },
{ "?", 3, opid2('?',':'), ASSOC_RIGHT, 3, 0, true},
{ "?", 3, opid2('?',':'), ASSOC_RIGHT, 3, 0 },
{ "=", 2, opid1('='), ASSOC_RIGHT, 2, 0, false},
{ "+=", 2, opid2('+','='), ASSOC_RIGHT, 2, 0, false},
{ "-=", 2, opid2('-','='), ASSOC_RIGHT, 2, 0, false},
{ "*=", 2, opid2('*','='), ASSOC_RIGHT, 2, 0, false},
{ "/=", 2, opid2('/','='), ASSOC_RIGHT, 2, 0, false},
{ "%=", 2, opid2('%','='), ASSOC_RIGHT, 2, 0, false},
{ ">>=", 2, opid3('>','>','='), ASSOC_RIGHT, 2, 0, false},
{ "<<=", 2, opid3('<','<','='), ASSOC_RIGHT, 2, 0, false},
{ "&=", 2, opid2('&','='), ASSOC_RIGHT, 2, 0, false},
{ "^=", 2, opid2('^','='), ASSOC_RIGHT, 2, 0, false},
{ "|=", 2, opid2('|','='), ASSOC_RIGHT, 2, 0, false},
{ "=", 2, opid1('='), ASSOC_RIGHT, 2, 0 },
{ "+=", 2, opid2('+','='), ASSOC_RIGHT, 2, 0 },
{ "-=", 2, opid2('-','='), ASSOC_RIGHT, 2, 0 },
{ "*=", 2, opid2('*','='), ASSOC_RIGHT, 2, 0 },
{ "/=", 2, opid2('/','='), ASSOC_RIGHT, 2, 0 },
{ "%=", 2, opid2('%','='), ASSOC_RIGHT, 2, 0 },
{ ">>=", 2, opid3('>','>','='), ASSOC_RIGHT, 2, 0 },
{ "<<=", 2, opid3('<','<','='), ASSOC_RIGHT, 2, 0 },
{ "&=", 2, opid2('&','='), ASSOC_RIGHT, 2, 0 },
{ "^=", 2, opid2('^','='), ASSOC_RIGHT, 2, 0 },
{ "|=", 2, opid2('|','='), ASSOC_RIGHT, 2, 0 },
{ "&~=", 2, opid3('&','~','='), ASSOC_RIGHT, 2, 0 },
{ ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0, false},
{ ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0 },
{ ",", 2, opid1(','), ASSOC_LEFT, 0, 0 }
{ ",", 2, opid1(','), ASSOC_LEFT, 0, 0, false}
};
static const size_t c_operator_count = (sizeof(c_operators) / sizeof(c_operators[0]));
static const oper_info fte_operators[] = {
{ "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */
{ "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* 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, 15, OP_SUFFIX, false},
{ "--", 1, opid3('S','-','-'), ASSOC_LEFT, 15, OP_SUFFIX, false},
{ ".", 2, opid1('.'), ASSOC_LEFT, 15, 0, false},
{ "(", 0, opid1('('), ASSOC_LEFT, 15, 0, false}, /* function call */
{ "[", 2, opid1('['), ASSOC_LEFT, 15, 0, false}, /* array subscript */
{ "!", 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, true},
{ "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
{ "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX, true},
{ "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
{ "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
{ "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 },
{ "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 },
{ "&", 2, opid1('&'), ASSOC_LEFT, 13, 0 },
{ "|", 2, opid1('|'), ASSOC_LEFT, 13, 0 },
{ "*", 2, opid1('*'), ASSOC_LEFT, 13, 0, true},
{ "/", 2, opid1('/'), ASSOC_LEFT, 13, 0, true},
{ "&", 2, opid1('&'), ASSOC_LEFT, 13, 0, true},
{ "|", 2, opid1('|'), ASSOC_LEFT, 13, 0, true},
{ "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 },
{ "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 },
{ "+", 2, opid1('+'), ASSOC_LEFT, 12, 0, true},
{ "-", 2, opid1('-'), ASSOC_LEFT, 12, 0, true},
{ "<<", 2, opid2('<','<'), ASSOC_LEFT, 11, 0 },
{ ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0 },
{ "<<", 2, opid2('<','<'), ASSOC_LEFT, 11, 0, true},
{ ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0, true},
{ "<", 2, opid1('<'), ASSOC_LEFT, 10, 0 },
{ ">", 2, opid1('>'), ASSOC_LEFT, 10, 0 },
{ "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0 },
{ ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0 },
{ "==", 2, opid2('=','='), ASSOC_LEFT, 10, 0 },
{ "!=", 2, opid2('!','='), ASSOC_LEFT, 10, 0 },
{ "<", 2, opid1('<'), ASSOC_LEFT, 10, 0, false},
{ ">", 2, opid1('>'), ASSOC_LEFT, 10, 0, false},
{ "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0, false},
{ ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0, false},
{ "==", 2, opid2('=','='), ASSOC_LEFT, 10, 0, true},
{ "!=", 2, opid2('!','='), ASSOC_LEFT, 10, 0, true},
{ "?", 3, opid2('?',':'), ASSOC_RIGHT, 9, 0 },
{ "?", 3, opid2('?',':'), ASSOC_RIGHT, 9, 0, true},
{ "=", 2, opid1('='), ASSOC_RIGHT, 8, 0 },
{ "+=", 2, opid2('+','='), ASSOC_RIGHT, 8, 0 },
{ "-=", 2, opid2('-','='), ASSOC_RIGHT, 8, 0 },
{ "*=", 2, opid2('*','='), ASSOC_RIGHT, 8, 0 },
{ "/=", 2, opid2('/','='), ASSOC_RIGHT, 8, 0 },
{ "%=", 2, opid2('%','='), ASSOC_RIGHT, 8, 0 },
{ "&=", 2, opid2('&','='), ASSOC_RIGHT, 8, 0 },
{ "|=", 2, opid2('|','='), ASSOC_RIGHT, 8, 0 },
{ "&~=", 2, opid3('&','~','='), ASSOC_RIGHT, 8, 0 },
{ "=", 2, opid1('='), ASSOC_RIGHT, 8, 0, false},
{ "+=", 2, opid2('+','='), ASSOC_RIGHT, 8, 0, false},
{ "-=", 2, opid2('-','='), ASSOC_RIGHT, 8, 0, false},
{ "*=", 2, opid2('*','='), ASSOC_RIGHT, 8, 0, false},
{ "/=", 2, opid2('/','='), ASSOC_RIGHT, 8, 0, false},
{ "%=", 2, opid2('%','='), ASSOC_RIGHT, 8, 0, false},
{ "&=", 2, opid2('&','='), ASSOC_RIGHT, 8, 0, false},
{ "|=", 2, opid2('|','='), ASSOC_RIGHT, 8, 0, false},
{ "&~=", 2, opid3('&','~','='), ASSOC_RIGHT, 8, 0, false},
{ "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 },
{ "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 0 },
{ "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0, true},
{ "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 0, true},
/* Leave precedence 3 for : with -fcorrect-ternary */
{ ",", 2, opid1(','), ASSOC_LEFT, 2, 0 },
{ ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0 }
{ ",", 2, opid1(','), ASSOC_LEFT, 2, 0, false},
{ ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0, false}
};
static const size_t fte_operator_count = (sizeof(fte_operators) / sizeof(fte_operators[0]));
static const oper_info qcc_operators[] = {
{ "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */
{ "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* paren expression - non function call */
{ ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 },
{ "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */
{ "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */
{ ".", 2, opid1('.'), ASSOC_LEFT, 15, 0, false},
{ "(", 0, opid1('('), ASSOC_LEFT, 15, 0, false}, /* function call */
{ "[", 2, opid1('['), ASSOC_LEFT, 15, 0, false}, /* array subscript */
{ "!", 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, true},
{ "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
{ "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX, true},
{ "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 },
{ "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 },
{ "&", 2, opid1('&'), ASSOC_LEFT, 13, 0 },
{ "|", 2, opid1('|'), ASSOC_LEFT, 13, 0 },
{ "*", 2, opid1('*'), ASSOC_LEFT, 13, 0, true},
{ "/", 2, opid1('/'), ASSOC_LEFT, 13, 0, true},
{ "&", 2, opid1('&'), ASSOC_LEFT, 13, 0, true},
{ "|", 2, opid1('|'), ASSOC_LEFT, 13, 0, true},
{ "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 },
{ "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 },
{ "+", 2, opid1('+'), ASSOC_LEFT, 12, 0, true},
{ "-", 2, opid1('-'), ASSOC_LEFT, 12, 0, true},
{ "<", 2, opid1('<'), ASSOC_LEFT, 10, 0 },
{ ">", 2, opid1('>'), ASSOC_LEFT, 10, 0 },
{ "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0 },
{ ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0 },
{ "==", 2, opid2('=','='), ASSOC_LEFT, 10, 0 },
{ "!=", 2, opid2('!','='), ASSOC_LEFT, 10, 0 },
{ "<", 2, opid1('<'), ASSOC_LEFT, 10, 0, false},
{ ">", 2, opid1('>'), ASSOC_LEFT, 10, 0, false},
{ "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0, false},
{ ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0, false},
{ "==", 2, opid2('=','='), ASSOC_LEFT, 10, 0, true},
{ "!=", 2, opid2('!','='), ASSOC_LEFT, 10, 0, true},
{ "=", 2, opid1('='), ASSOC_RIGHT, 8, 0 },
{ "+=", 2, opid2('+','='), ASSOC_RIGHT, 8, 0 },
{ "-=", 2, opid2('-','='), ASSOC_RIGHT, 8, 0 },
{ "*=", 2, opid2('*','='), ASSOC_RIGHT, 8, 0 },
{ "/=", 2, opid2('/','='), ASSOC_RIGHT, 8, 0 },
{ "%=", 2, opid2('%','='), ASSOC_RIGHT, 8, 0 },
{ "&=", 2, opid2('&','='), ASSOC_RIGHT, 8, 0 },
{ "|=", 2, opid2('|','='), ASSOC_RIGHT, 8, 0 },
{ "=", 2, opid1('='), ASSOC_RIGHT, 8, 0, false},
{ "+=", 2, opid2('+','='), ASSOC_RIGHT, 8, 0, false},
{ "-=", 2, opid2('-','='), ASSOC_RIGHT, 8, 0, false},
{ "*=", 2, opid2('*','='), ASSOC_RIGHT, 8, 0, false},
{ "/=", 2, opid2('/','='), ASSOC_RIGHT, 8, 0, false},
{ "%=", 2, opid2('%','='), ASSOC_RIGHT, 8, 0, false},
{ "&=", 2, opid2('&','='), ASSOC_RIGHT, 8, 0, false},
{ "|=", 2, opid2('|','='), ASSOC_RIGHT, 8, 0, false},
{ "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 },
{ "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 0 },
{ "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0, true},
{ "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 0, true},
{ ",", 2, opid1(','), ASSOC_LEFT, 2, 0 },
{ ",", 2, opid1(','), ASSOC_LEFT, 2, 0, false},
};
static const size_t qcc_operator_count = (sizeof(qcc_operators) / sizeof(qcc_operators[0]));
extern const oper_info *operators;
extern size_t operator_count;
void lexerror(lex_file*, const char *fmt, ...);
#endif

View file

@ -1,41 +1,20 @@
/*
* Copyright (C) 2012, 2013
* Dale Weiler
* Wolfgang Bumiller
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include "gmqcc.h"
#include "lexer.h"
#include <time.h>
#include "parser.h"
/* TODO: cleanup this whole file .. it's a fuckign mess */
/* set by the standard */
const oper_info *operators = NULL;
size_t operator_count = 0;
static bool opts_output_wasset = false;
typedef struct { char *filename; int type; } argitem;
typedef struct { char *name; char *value; } ppitem;
static argitem *items = NULL;
static ppitem *ppems = NULL;
const oper_info *operators = nullptr;
size_t operator_count = 0;
static bool opts_output_wasset = false;
struct argitem { char *filename; int type; };
struct ppitem { char *name; char *value; };
static argitem *items = nullptr;
static ppitem *ppems = nullptr;
#define TYPE_QC 0
#define TYPE_ASM 1
@ -43,27 +22,21 @@ static ppitem *ppems = NULL;
static const char *app_name;
static void version() {
con_out("GMQCC %d.%d.%d Built %s %s\n",
static void version(void) {
con_out("GMQCC %d.%d.%d Built %s %s\n" GMQCC_DEV_VERSION_STRING,
GMQCC_VERSION_MAJOR,
GMQCC_VERSION_MINOR,
GMQCC_VERSION_PATCH,
__DATE__,
__TIME__
);
#ifdef GMQCC_GITINFO
con_out("git build: %s\n", GMQCC_GITINFO);
#elif defined(GMQCC_VERION_TYPE_DEVEL)
con_out("development build\n");
#endif
}
static int usage() {
static int usage(void) {
con_out("usage: %s [options] [files...]", app_name);
con_out("options:\n"
" -h, --help show this help message\n"
" -debug turns on compiler debug messages\n"
" -memchk turns on compiler memory leak check\n");
" -debug turns on compiler debug messages\n");
con_out(" -o, --output=file output file, defaults to progs.dat\n"
" -s filename add a progs.src file to be used\n");
con_out(" -E stop after preprocessing\n");
@ -88,6 +61,8 @@ static int usage() {
" -Ono-<name> disable specific optimization\n"
" -Ohelp list optimizations\n");
con_out(" -force-crc=num force a specific checksum into the header\n");
con_out(" -state-fps=num emulate OP_STATE with the specified FPS\n");
con_out(" -coverage add coverage support\n");
return -1;
}
@ -142,19 +117,16 @@ static bool options_long_gcc(const char *optname, int *argc_, char ***argv_, cha
return options_long_witharg_all(optname, argc_, argv_, out, 1, false);
}
static bool options_parse(int argc, char **argv) {
static bool options_parse(int argc, char **argv, bool *has_progs_src) {
bool argend = false;
size_t itr;
char buffer[1024];
char *redirout = NULL;
char *redirerr = NULL;
char *config = NULL;
char *memdumpcols = NULL;
char buffer[1024];
char *config = nullptr;
while (!argend && argc > 1) {
char *argarg;
argitem item;
ppitem macro;
ppitem macro;
++argv;
--argc;
@ -166,6 +138,9 @@ static bool options_parse(int argc, char **argv) {
opts_set(opts.flags, ADJUST_VECTOR_FIELDS, true);
opts_set(opts.flags, CORRECT_LOGIC, true);
opts_set(opts.flags, SHORT_LOGIC, true);
opts_set(opts.flags, UNTYPED_NIL, true);
opts_set(opts.flags, VARIADIC_ARGS, true);
opts_set(opts.flags, FALSE_EMPTY_STRINGS, false);
opts_set(opts.flags, TRUE_EMPTY_STRINGS, true);
opts_set(opts.flags, LOOP_LABELS, true);
@ -173,6 +148,9 @@ static bool options_parse(int argc, char **argv) {
opts_set(opts.flags, INITIALIZED_NONCONSTANTS, true);
opts_set(opts.werror, WARN_INVALID_PARAMETER_COUNT, true);
opts_set(opts.werror, WARN_MISSING_RETURN_VALUES, true);
opts_set(opts.flags, EXPRESSIONS_FOR_BUILTINS, true);
opts_set(opts.warn, WARN_BREAKDEF, true);
OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_GMQCC;
@ -192,6 +170,7 @@ static bool options_parse(int argc, char **argv) {
opts_set(opts.flags, ASSIGN_FUNCTION_TYPES, true);
opts_set(opts.flags, CORRECT_TERNARY, false);
opts_set(opts.warn, WARN_TERNARY_PRECEDENCE, true);
opts_set(opts.warn, WARN_BREAKDEF, true);
OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_FTEQCC;
@ -209,23 +188,21 @@ static bool options_parse(int argc, char **argv) {
if (options_long_gcc("force-crc", &argc, &argv, &argarg)) {
OPTS_OPTION_BOOL(OPTION_FORCECRC) = true;
OPTS_OPTION_U16 (OPTION_FORCED_CRC) = strtol(argarg, NULL, 0);
OPTS_OPTION_U16 (OPTION_FORCED_CRC) = strtol(argarg, nullptr, 0);
continue;
}
if (options_long_gcc("redirout", &argc, &argv, &redirout)) {
con_change(redirout, redirerr);
continue;
}
if (options_long_gcc("redirerr", &argc, &argv, &redirerr)) {
con_change(redirout, redirerr);
if (options_long_gcc("state-fps", &argc, &argv, &argarg)) {
OPTS_OPTION_U32(OPTION_STATE_FPS) = strtol(argarg, nullptr, 0);
opts_set(opts.flags, EMULATE_STATE, true);
continue;
}
if (options_long_gcc("config", &argc, &argv, &argarg)) {
config = argarg;
continue;
}
if (options_long_gcc("memdumpcols", &argc, &argv, &memdumpcols)) {
OPTS_OPTION_U16(OPTION_MEMDUMPCOLS) = (uint16_t)strtol(memdumpcols, NULL, 10);
if (options_long_gcc("progsrc", &argc, &argv, &argarg)) {
OPTS_OPTION_STR(OPTION_PROGSRC) = argarg;
*has_progs_src = true;
continue;
}
@ -264,14 +241,14 @@ static bool options_parse(int argc, char **argv) {
OPTS_OPTION_BOOL(OPTION_DUMPFIN) = true;
continue;
}
if (!strcmp(argv[0]+1, "memchk")) {
OPTS_OPTION_BOOL(OPTION_MEMCHK) = true;
continue;
}
if (!strcmp(argv[0]+1, "nocolor")) {
con_color(0);
continue;
}
if (!strcmp(argv[0]+1, "coverage")) {
OPTS_OPTION_BOOL(OPTION_COVERAGE) = true;
continue;
}
switch (argv[0][1]) {
/* -h, show usage but exit with 0 */
@ -307,7 +284,7 @@ static bool options_parse(int argc, char **argv) {
if (!(argarg = strchr(argv[0] + 2, '='))) {
macro.name = util_strdup(argv[0]+2);
macro.value = NULL;
macro.value = nullptr;
} else {
*argarg='\0'; /* terminate for name */
macro.name = util_strdup(argv[0]+2);
@ -353,7 +330,7 @@ static bool options_parse(int argc, char **argv) {
else if (!strcmp(argv[0]+2, "NO_ERROR") ||
!strcmp(argv[0]+2, "NO_ERROR_ALL"))
{
for (itr = 0; itr < sizeof(opts.werror)/sizeof(opts.werror[0]); ++itr)
for (itr = 0; itr < GMQCC_ARRAY_COUNT(opts.werror); ++itr)
opts.werror[itr] = 0;
break;
}
@ -361,19 +338,19 @@ static bool options_parse(int argc, char **argv) {
!strcmp(argv[0]+2, "ERROR_ALL"))
{
opts_backup_non_Werror_all();
for (itr = 0; itr < sizeof(opts.werror)/sizeof(opts.werror[0]); ++itr)
for (itr = 0; itr < GMQCC_ARRAY_COUNT(opts.werror); ++itr)
opts.werror[itr] = 0xFFFFFFFFL;
opts_restore_non_Werror_all();
break;
}
else if (!strcmp(argv[0]+2, "NONE")) {
for (itr = 0; itr < sizeof(opts.warn)/sizeof(opts.warn[0]); ++itr)
for (itr = 0; itr < GMQCC_ARRAY_COUNT(opts.warn); ++itr)
opts.warn[itr] = 0;
break;
}
else if (!strcmp(argv[0]+2, "ALL")) {
opts_backup_non_Wall();
for (itr = 0; itr < sizeof(opts.warn)/sizeof(opts.warn[0]); ++itr)
for (itr = 0; itr < GMQCC_ARRAY_COUNT(opts.warn); ++itr)
opts.warn[itr] = 0xFFFFFFFFL;
opts_restore_non_Wall();
break;
@ -407,8 +384,8 @@ static bool options_parse(int argc, char **argv) {
con_out("option -O requires a numerical argument, or optimization name with an optional 'no-' prefix\n");
return false;
}
if (isdigit(argarg[0])) {
uint32_t val = (uint32_t)strtol(argarg, NULL, 10);
if (util_isdigit(argarg[0])) {
uint32_t val = (uint32_t)strtol(argarg, nullptr, 10);
OPTS_OPTION_U32(OPTION_O) = val;
opts_setoptimlevel(val);
} else {
@ -424,7 +401,8 @@ static bool options_parse(int argc, char **argv) {
else if (!strcmp(argarg, "ALL"))
opts_setoptimlevel(OPTS_OPTION_U32(OPTION_O) = 9999);
else if (!strncmp(argarg, "NO_", 3)) {
if (!opts_setoptim(argarg+3, false)) {
/* constant folding cannot be turned off for obvious reasons */
if (!strcmp(argarg, "NO_CONST_FOLD") || !opts_setoptim(argarg+3, false)) {
con_out("unknown optimization: %s\n", argarg+3);
return false;
}
@ -457,6 +435,9 @@ static bool options_parse(int argc, char **argv) {
}
item.filename = argarg;
vec_push(items, item);
if (item.type == TYPE_SRC) {
*has_progs_src = true;
}
break;
case '-':
@ -478,14 +459,6 @@ static bool options_parse(int argc, char **argv) {
OPTS_OPTION_BOOL(OPTION_QUIET) = true;
break;
}
else if (!strcmp(argv[0]+2, "correct")) {
OPTS_OPTION_BOOL(OPTION_CORRECTION) = true;
break;
}
else if (!strcmp(argv[0]+2, "no-correct")) {
OPTS_OPTION_BOOL(OPTION_CORRECTION) = false;
break;
}
else if (!strcmp(argv[0]+2, "add-info")) {
OPTS_OPTION_BOOL(OPTION_ADD_INFO) = true;
break;
@ -520,21 +493,21 @@ static bool options_parse(int argc, char **argv) {
}
/* returns the line number, or -1 on error */
static bool progs_nextline(char **out, size_t *alen,FILE *src) {
static bool progs_nextline(char **out, size_t *alen, FILE *src) {
int len;
char *line;
char *start;
char *end;
line = *out;
len = fs_file_getline(&line, alen, src);
len = util_getline(&line, alen, src);
if (len == -1)
return false;
/* start at first non-blank */
for (start = line; isspace(*start); ++start) {}
for (start = line; util_isspace(*start); ++start) {}
/* end at the first non-blank */
for (end = start; *end && !isspace(*end); ++end) {}
for (end = start; *end && !util_isspace(*end); ++end) {}
*out = line;
/* move the actual filename to the beginning */
@ -546,22 +519,21 @@ 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;
struct parser_s *parser = NULL;
struct ftepp_s *ftepp = NULL;
size_t itr;
int retval = 0;
bool operators_free = false;
bool has_progs_src = false;
FILE *outfile = nullptr;
parser_t *parser = nullptr;
ftepp_t *ftepp = nullptr;
app_name = argv[0];
con_init ();
opts_init("progs.dat", COMPILER_GMQCC, (1024 << 3));
opts_init("progs.dat", COMPILER_QCC, (1024 << 3));
util_seed(time(0));
if (!options_parse(argc, argv)) {
if (!options_parse(argc, argv, &has_progs_src)) {
return usage();
}
@ -573,13 +545,13 @@ int main(int argc, char **argv) {
/* the standard decides which set of operators to use */
if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
operators = c_operators;
operator_count = c_operator_count;
operator_count = GMQCC_ARRAY_COUNT(c_operators);
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC) {
operators = fte_operators;
operator_count = fte_operator_count;
operator_count = GMQCC_ARRAY_COUNT(fte_operators);
} else {
operators = qcc_operators;
operator_count = qcc_operator_count;
operator_count = GMQCC_ARRAY_COUNT(qcc_operators);
}
if (operators == fte_operators) {
@ -615,7 +587,7 @@ int main(int argc, char **argv) {
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
if (opts_output_wasset) {
outfile = fs_file_open(OPTS_OPTION_STR(OPTION_OUTPUT), "wb");
outfile = fopen(OPTS_OPTION_STR(OPTION_OUTPUT), "wb");
if (!outfile) {
con_err("failed to open `%s` for writing\n", OPTS_OPTION_STR(OPTION_OUTPUT));
retval = 1;
@ -643,8 +615,6 @@ int main(int argc, char **argv) {
}
}
util_debug("COM", "starting ...\n");
/* add macros */
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
for (itr = 0; itr < vec_size(ppems); itr++) {
@ -657,54 +627,55 @@ int main(int argc, char **argv) {
}
}
if (!vec_size(items)) {
if (!vec_size(items) && !has_progs_src) {
FILE *fp = fopen(OPTS_OPTION_STR(OPTION_PROGSRC), "rb");
if (fp) {
has_progs_src = true;
fclose(fp);
}
}
if (has_progs_src) {
FILE *src;
char *line;
char *line = nullptr;
size_t linelen = 0;
bool has_first_line = false;
progs_src = true;
src = fs_file_open("progs.src", "rb");
src = fopen(OPTS_OPTION_STR(OPTION_PROGSRC), "rb");
if (!src) {
con_err("failed to open `progs.src` for reading\n");
con_err("failed to open `%s` for reading\n", OPTS_OPTION_STR(OPTION_PROGSRC));
retval = 1;
goto cleanup;
}
line = NULL;
if (!progs_nextline(&line, &linelen, src) || !line[0]) {
con_err("illformatted progs.src file: expected output filename in first line\n");
retval = 1;
goto srcdone;
}
if (!opts_output_wasset) {
OPTS_OPTION_STR(OPTION_OUTPUT) = util_strdup(line);
opts_output_free = true;
}
while (progs_nextline(&line, &linelen, src)) {
argitem item;
if (!line[0] || (line[0] == '/' && line[1] == '/'))
if (!line[0] || (line[0] == '/' && line[1] == '/')) {
continue;
item.filename = util_strdup(line);
item.type = TYPE_QC;
vec_push(items, item);
}
if (has_first_line) {
item.filename = util_strdup(line);
item.type = TYPE_QC;
vec_push(items, item);
} else {
if (!opts_output_wasset) {
OPTS_OPTION_DUP(OPTION_OUTPUT) = util_strdup(line);
}
has_first_line = true;
}
}
srcdone:
fs_file_close(src);
fclose(src);
mem_d(line);
}
if (retval)
goto cleanup;
if (vec_size(items)) {
if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
{
con_out("Mode: %s\n", (progs_src ? "progs.src" : "manual"));
con_out("Mode: %s\n", (has_progs_src ? "progs.src" : "manual"));
con_out("There are %lu items to compile:\n", (unsigned long)vec_size(items));
}
@ -720,6 +691,10 @@ srcdone:
("unknown"))))));
}
if (items[itr].type == TYPE_SRC) {
continue;
}
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
const char *out;
if (!ftepp_preprocess_file(ftepp, items[itr].filename)) {
@ -728,7 +703,7 @@ srcdone:
}
out = ftepp_get(ftepp);
if (out)
fs_file_printf(outfile, "%s", out);
fprintf(outfile, "%s", out);
ftepp_flush(ftepp);
}
else {
@ -755,14 +730,14 @@ srcdone:
}
}
if (progs_src) {
if (has_progs_src) {
mem_d(items[itr].filename);
items[itr].filename = NULL;
items[itr].filename = nullptr;
}
}
ftepp_finish(ftepp);
ftepp = NULL;
ftepp = nullptr;
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
if (!parser_finish(parser, OPTS_OPTION_STR(OPTION_OUTPUT))) {
retval = 1;
@ -771,19 +746,7 @@ srcdone:
}
}
/* stuff */
if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
{
for (itr = 0; itr < COUNT_OPTIMIZATIONS; ++itr) {
if (opts_optimizationcount[itr]) {
con_out("%s: %u\n", opts_opt_list[itr].name, (unsigned int)opts_optimizationcount[itr]);
}
}
}
cleanup:
util_debug("COM", "cleaning ...\n");
if (ftepp)
ftepp_finish(ftepp);
con_close();
@ -791,13 +754,19 @@ cleanup:
vec_free(ppems);
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
parser_cleanup(parser);
if (opts_output_free)
mem_d(OPTS_OPTION_STR(OPTION_OUTPUT));
delete parser;
/* free allocated option strings */
for (itr = 0; itr < OPTION_COUNT; itr++)
if (OPTS_OPTION_DUPED(itr))
mem_d(OPTS_OPTION_STR(itr));
if (operators_free)
mem_d((void*)operators);
lex_cleanup();
util_meminfo();
if (!retval && compile_errors)
retval = 1;
return retval;
}

View file

@ -41,3 +41,11 @@ check_opt() {
check_opt FLAGS f
check_opt WARNS W
check_opt OPTIMIZATIONS O
# TODO: linux version
if [ "$(uname -s)" != "Linux" ]; then
for i in doc/*.1;
do
mandoc -Tlint -Wall "$i";
done
fi

View file

@ -1,38 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmqcc", "gmqcc\gmqcc.vcxproj", "{A6BD74E1-31BB-4D00-A9E0-09FF1BC76ED6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qcvm", "qcvm\qcvm.vcxproj", "{DC980E20-C7A8-4112-A517-631DBDA788E7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pak", "pak\pak.vcxproj", "{A6F66BE9-57EF-4E93-AA9D-6E0C8B0990AD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsuite", "testsuite\testsuite.vcxproj", "{7E2839D9-9C1A-4489-9FF9-FDC854EBED3D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A6BD74E1-31BB-4D00-A9E0-09FF1BC76ED6}.Debug|Win32.ActiveCfg = Debug|Win32
{A6BD74E1-31BB-4D00-A9E0-09FF1BC76ED6}.Debug|Win32.Build.0 = Debug|Win32
{A6BD74E1-31BB-4D00-A9E0-09FF1BC76ED6}.Release|Win32.ActiveCfg = Release|Win32
{A6BD74E1-31BB-4D00-A9E0-09FF1BC76ED6}.Release|Win32.Build.0 = Release|Win32
{DC980E20-C7A8-4112-A517-631DBDA788E7}.Debug|Win32.ActiveCfg = Debug|Win32
{DC980E20-C7A8-4112-A517-631DBDA788E7}.Debug|Win32.Build.0 = Debug|Win32
{DC980E20-C7A8-4112-A517-631DBDA788E7}.Release|Win32.ActiveCfg = Release|Win32
{DC980E20-C7A8-4112-A517-631DBDA788E7}.Release|Win32.Build.0 = Release|Win32
{A6F66BE9-57EF-4E93-AA9D-6E0C8B0990AD}.Debug|Win32.ActiveCfg = Debug|Win32
{A6F66BE9-57EF-4E93-AA9D-6E0C8B0990AD}.Debug|Win32.Build.0 = Debug|Win32
{A6F66BE9-57EF-4E93-AA9D-6E0C8B0990AD}.Release|Win32.ActiveCfg = Release|Win32
{A6F66BE9-57EF-4E93-AA9D-6E0C8B0990AD}.Release|Win32.Build.0 = Release|Win32
{7E2839D9-9C1A-4489-9FF9-FDC854EBED3D}.Debug|Win32.ActiveCfg = Debug|Win32
{7E2839D9-9C1A-4489-9FF9-FDC854EBED3D}.Debug|Win32.Build.0 = Debug|Win32
{7E2839D9-9C1A-4489-9FF9-FDC854EBED3D}.Release|Win32.ActiveCfg = Release|Win32
{7E2839D9-9C1A-4489-9FF9-FDC854EBED3D}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -1,90 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A6BD74E1-31BB-4D00-A9E0-09FF1BC76ED6}</ProjectGuid>
<RootNamespace>gmqcc</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\ast.c" />
<ClCompile Include="..\..\code.c" />
<ClCompile Include="..\..\conout.c" />
<ClCompile Include="..\..\correct.c" />
<ClCompile Include="..\..\fs.c" />
<ClCompile Include="..\..\ftepp.c" />
<ClCompile Include="..\..\ir.c" />
<ClCompile Include="..\..\lexer.c" />
<ClCompile Include="..\..\main.c" />
<ClCompile Include="..\..\opts.c" />
<ClCompile Include="..\..\parser.c" />
<ClCompile Include="..\..\utf8.c" />
<ClCompile Include="..\..\util.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\ast.h" />
<ClInclude Include="..\..\gmqcc.h" />
<ClInclude Include="..\..\intrin.h" />
<ClInclude Include="..\..\ir.h" />
<ClInclude Include="..\..\lexer.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\opts.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\ast.c" />
<ClCompile Include="..\..\code.c" />
<ClCompile Include="..\..\conout.c" />
<ClCompile Include="..\..\correct.c" />
<ClCompile Include="..\..\fs.c" />
<ClCompile Include="..\..\ftepp.c" />
<ClCompile Include="..\..\ir.c" />
<ClCompile Include="..\..\lexer.c" />
<ClCompile Include="..\..\main.c" />
<ClCompile Include="..\..\opts.c" />
<ClCompile Include="..\..\parser.c" />
<ClCompile Include="..\..\utf8.c" />
<ClCompile Include="..\..\util.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\ast.h" />
<ClInclude Include="..\..\gmqcc.h" />
<ClInclude Include="..\..\intrin.h" />
<ClInclude Include="..\..\ir.h" />
<ClInclude Include="..\..\lexer.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\opts.def" />
</ItemGroup>
</Project>

View file

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A6F66BE9-57EF-4E93-AA9D-6E0C8B0990AD}</ProjectGuid>
<RootNamespace>pak</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\conout.c" />
<ClCompile Include="..\..\fs.c" />
<ClCompile Include="..\..\opts.c" />
<ClCompile Include="..\..\pak.c" />
<ClCompile Include="..\..\util.c" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\opts.def" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\gmqcc.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\conout.c" />
<ClCompile Include="..\..\fs.c" />
<ClCompile Include="..\..\opts.c" />
<ClCompile Include="..\..\pak.c" />
<ClCompile Include="..\..\util.c" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\opts.def" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\gmqcc.h" />
</ItemGroup>
</Project>

View file

@ -1,76 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{DC980E20-C7A8-4112-A517-631DBDA788E7}</ProjectGuid>
<RootNamespace>qcvm</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>QCVM_EXECUTOR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>QCVM_EXECUTOR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\conout.c" />
<ClCompile Include="..\..\exec.c" />
<ClCompile Include="..\..\fs.c" />
<ClCompile Include="..\..\util.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\gmqcc.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\conout.c" />
<ClCompile Include="..\..\exec.c" />
<ClCompile Include="..\..\fs.c" />
<ClCompile Include="..\..\util.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\gmqcc.h" />
</ItemGroup>
</Project>

View file

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{7E2839D9-9C1A-4489-9FF9-FDC854EBED3D}</ProjectGuid>
<RootNamespace>testsuite</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\conout.c" />
<ClCompile Include="..\..\fs.c" />
<ClCompile Include="..\..\test.c" />
<ClCompile Include="..\..\util.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\gmqcc.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\conout.c" />
<ClCompile Include="..\..\fs.c" />
<ClCompile Include="..\..\test.c" />
<ClCompile Include="..\..\util.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\gmqcc.h" />
</ItemGroup>
</Project>

View file

@ -1,33 +1,42 @@
/*
* Copyright (C) 2012, 2013
* Wolfgang Bumiller
* Dale Weiler
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "gmqcc.h"
unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS];
opts_cmd_t opts; /* command lien options */
#include <string.h>
#include <stdlib.h>
static void opts_setdefault() {
#include "gmqcc.h"
const unsigned int opts_opt_oflag[COUNT_OPTIMIZATIONS+1] = {
# define GMQCC_TYPE_OPTIMIZATIONS
# define GMQCC_DEFINE_FLAG(NAME, MIN_O) MIN_O,
# include "opts.def"
0
};
const opts_flag_def_t opts_opt_list[COUNT_OPTIMIZATIONS+1] = {
# define GMQCC_TYPE_OPTIMIZATIONS
# define GMQCC_DEFINE_FLAG(NAME, MIN_O) { #NAME, LONGBIT(OPTIM_##NAME) },
# include "opts.def"
{ nullptr, LONGBIT(0) }
};
const opts_flag_def_t opts_warn_list[COUNT_WARNINGS+1] = {
# define GMQCC_TYPE_WARNS
# define GMQCC_DEFINE_FLAG(X) { #X, LONGBIT(WARN_##X) },
# include "opts.def"
{ nullptr, LONGBIT(0) }
};
const opts_flag_def_t opts_flag_list[COUNT_FLAGS+1] = {
# define GMQCC_TYPE_FLAGS
# define GMQCC_DEFINE_FLAG(X) { #X, LONGBIT(X) },
# include "opts.def"
{ nullptr, LONGBIT(0) }
};
unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS];
opts_cmd_t opts; /* command line options */
static void opts_setdefault(void) {
memset(&opts, 0, sizeof(opts_cmd_t));
OPTS_OPTION_BOOL(OPTION_CORRECTION) = true;
OPTS_OPTION_STR(OPTION_PROGSRC) = "progs.src";
/* warnings */
opts_set(opts.warn, WARN_UNUSED_VARIABLE, true);
@ -57,6 +66,10 @@ static void opts_setdefault() {
opts_set(opts.warn, WARN_UNINITIALIZED_CONSTANT, true);
opts_set(opts.warn, WARN_DEPRECATED, true);
opts_set(opts.warn, WARN_PARENTHESIS, true);
opts_set(opts.warn, WARN_CONST_OVERWRITE, true);
opts_set(opts.warn, WARN_DIRECTIVE_INMACRO, true);
opts_set(opts.warn, WARN_BUILTINS, true);
opts_set(opts.warn, WARN_INEXACT_COMPARES, true);
/* flags */
opts_set(opts.flags, ADJUST_VECTOR_FIELDS, true);
@ -65,6 +78,8 @@ static void opts_setdefault() {
opts_set(opts.flags, LEGACY_VECTOR_MATHS, true);
opts_set(opts.flags, DARKPLACES_STRING_TABLE_BUG, true);
/* options */
OPTS_OPTION_U32(OPTION_STATE_FPS) = 10;
}
void opts_backup_non_Wall() {
@ -94,13 +109,12 @@ void opts_restore_non_Werror_all() {
void opts_init(const char *output, int standard, size_t arraysize) {
opts_setdefault();
OPTS_OPTION_STR(OPTION_OUTPUT) = (char*)output;
OPTS_OPTION_STR(OPTION_OUTPUT) = 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) {
static bool opts_setflag_all(const char *name, bool on, uint32_t *flags, const opts_flag_def_t *list, size_t listsize) {
size_t i;
for (i = 0; i < listsize; ++i) {
@ -135,9 +149,9 @@ void opts_set(uint32_t *flags, size_t idx, bool on) {
LONGBIT_SET(lb, idx);
if (on)
flags[lb.idx] |= (1<<(lb.bit));
flags[lb.idx] |= (1u<<(lb.bit));
else
flags[lb.idx] &= ~(1<<(lb.bit));
flags[lb.idx] &= ~(1u<<(lb.bit));
}
void opts_setoptimlevel(unsigned int level) {
@ -157,14 +171,14 @@ void opts_setoptimlevel(unsigned int level) {
* from a progs.src.
*/
static char *opts_ini_rstrip(char *s) {
char *p = s + strlen(s);
while(p > s && isspace(*--p))
*p = '\0';
char *p = s + strlen(s) - 1;
while (p > s && util_isspace(*p))
*p = '\0', p--;
return s;
}
static char *opts_ini_lskip(const char *s) {
while (*s && isspace(*s))
while (*s && util_isspace(*s))
s++;
return (char*)s;
}
@ -172,20 +186,21 @@ static char *opts_ini_lskip(const char *s) {
static char *opts_ini_next(const char *s, char c) {
bool last = false;
while (*s && *s != c && !(last && *s == ';'))
last = !!isspace(*s), s++;
last = !!util_isspace(*s), s++;
return (char*)s;
}
static size_t opts_ini_parse (
FILE *filehandle,
char *(*loadhandle)(const char *, const char *, const char *),
char **errorhandle
FILE *filehandle,
char *(*loadhandle)(const char *, const char *, const char *, char **),
char **errorhandle,
char **parse_file
) {
size_t linesize;
size_t lineno = 1;
size_t error = 0;
char *line = NULL;
char *line = nullptr;
char section_data[2048] = "";
char oldname_data[2048] = "";
@ -195,7 +210,7 @@ static size_t opts_ini_parse (
char *read_name;
char *read_value;
while (fs_file_getline(&line, &linesize, filehandle) != EOF) {
while (util_getline(&line, &linesize, filehandle) != EOF) {
parse_beg = line;
/* handle BOM */
@ -226,7 +241,7 @@ static size_t opts_ini_parse (
} else if (*parse_beg && *parse_beg != ';') {
/* not a comment, must be a name value pair :) */
if (*(parse_end = opts_ini_next(parse_beg, '=')) != '=')
parse_end = opts_ini_next(parse_beg, ':');
parse_end = opts_ini_next(parse_beg, ':');
if (*parse_end == '=' || *parse_end == ':') {
*parse_end = '\0'; /* terminate bro */
@ -240,8 +255,20 @@ static size_t opts_ini_parse (
util_strncpy(oldname_data, read_name, sizeof(oldname_data));
oldname_data[sizeof(oldname_data) - 1] ='\0';
if ((*errorhandle = loadhandle(section_data, read_name, read_value)) && !error)
if ((*errorhandle = loadhandle(section_data, read_name, read_value, parse_file)) && !error)
error = lineno;
} else if (!strcmp(section_data, "includes")) {
/* Includes are special */
if (*(parse_end = opts_ini_next(parse_beg, '=')) == '='
|| *(parse_end = opts_ini_next(parse_beg, ':')) == ':') {
static const char *invalid_include = "invalid use of include";
vec_append(*errorhandle, strlen(invalid_include), invalid_include);
error = lineno;
} else {
read_name = opts_ini_rstrip(parse_beg);
if ((*errorhandle = loadhandle(section_data, read_name, read_name, parse_file)) && !error)
error = lineno;
}
} else if (!error) {
/* otherwise set error to the current line number */
error = lineno;
@ -251,6 +278,7 @@ static size_t opts_ini_parse (
}
mem_d(line);
return error;
}
/*
@ -259,11 +287,11 @@ 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 !!strtol(value, NULL, 10);
return !!strtol(value, nullptr, 10);
}
static char *opts_ini_load(const char *section, const char *name, const char *value) {
char *error = NULL;
static char *opts_ini_load(const char *section, const char *name, const char *value, char **parse_file) {
char *error = nullptr;
bool found = false;
/*
@ -274,6 +302,26 @@ static char *opts_ini_load(const char *section, const char *name, const char *va
#undef GMQCC_TYPE_OPTIMIZATIONS
#undef GMQCC_TYPE_WARNS
/* deal with includes */
if (!strcmp(section, "includes")) {
static const char *include_error_beg = "failed to open file `";
static const char *include_error_end = "' for inclusion";
FILE *file = fopen(value, "r");
found = true;
if (!file) {
vec_append(error, strlen(include_error_beg), include_error_beg);
vec_append(error, strlen(value), value);
vec_append(error, strlen(include_error_end), include_error_end);
} else {
if (opts_ini_parse(file, &opts_ini_load, &error, parse_file) != 0)
found = false;
/* Change the file name */
mem_d(*parse_file);
*parse_file = util_strdup(value);
fclose(file);
}
}
/* flags */
#define GMQCC_TYPE_FLAGS
#define GMQCC_DEFINE_FLAG(X) \
@ -312,24 +360,29 @@ static char *opts_ini_load(const char *section, const char *name, const char *va
/* nothing was found ever! */
if (!found) {
if (strcmp(section, "flags") &&
strcmp(section, "warnings") &&
if (strcmp(section, "includes") &&
strcmp(section, "flags") &&
strcmp(section, "warnings") &&
strcmp(section, "optimizations"))
{
vec_upload(error, "invalid section `", 17);
vec_upload(error, section, strlen(section));
vec_push (error, '`');
vec_push (error, '\0');
static const char *invalid_section = "invalid_section `";
vec_append(error, strlen(invalid_section), invalid_section);
vec_append(error, strlen(section), section);
vec_push(error, '`');
} else if (strcmp(section, "includes")) {
static const char *invalid_variable = "invalid_variable `";
static const char *in_section = "` in section: `";
vec_append(error, strlen(invalid_variable), invalid_variable);
vec_append(error, strlen(name), name);
vec_append(error, strlen(in_section), in_section);
vec_append(error, strlen(section), section);
vec_push(error, '`');
} else {
vec_upload(error, "invalid variable `", 18);
vec_upload(error, name, strlen(name));
vec_push (error, '`');
vec_upload(error, " in section: `", 14);
vec_upload(error, section, strlen(section));
vec_push (error, '`');
vec_push (error, '\0');
static const char *expected_something = "expected something";
vec_append(error, strlen(expected_something), expected_something);
}
}
vec_push(error, '\0');
return error;
}
@ -343,27 +396,29 @@ void opts_ini_init(const char *file) {
* gmqcc.ini
* gmqcc.cfg
*/
char *error;
char *error = nullptr;
char *parse_file = nullptr;
size_t line;
FILE *ini;
FILE *ini;
if (!file) {
/* try ini */
if (!(ini = fs_file_open((file = "gmqcc.ini"), "r")))
if (!(ini = fopen((file = "gmqcc.ini"), "r")))
/* try cfg */
if (!(ini = fs_file_open((file = "gmqcc.cfg"), "r")))
if (!(ini = fopen((file = "gmqcc.cfg"), "r")))
return;
} else if (!(ini = fs_file_open(file, "r")))
} else if (!(ini = fopen(file, "r")))
return;
con_out("found ini file `%s`\n", file);
if ((line = opts_ini_parse(ini, &opts_ini_load, &error)) != 0) {
parse_file = util_strdup(file);
if ((line = opts_ini_parse(ini, &opts_ini_load, &error, &parse_file)) != 0) {
/* there was a parse error with the ini file */
con_printmsg(LVL_ERROR, file, line, "error", error);
con_printmsg(LVL_ERROR, parse_file, line, 0 /*TODO: column for ini error*/, "error", error);
vec_free(error);
}
mem_d(parse_file);
fs_file_close(ini);
fclose(ini);
}

View file

@ -1,26 +1,3 @@
/*
* Copyright (C) 2012, 2013
* Wolfgang Bumiller
* Dale Weiler
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* 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.
*/
#ifndef GMQCC_DEFINE_FLAG
# error "bad opts.def usage"
#endif
@ -31,6 +8,8 @@
GMQCC_DEFINE_FLAG(ADJUST_VECTOR_FIELDS)
GMQCC_DEFINE_FLAG(FTEPP)
GMQCC_DEFINE_FLAG(FTEPP_PREDEFS)
GMQCC_DEFINE_FLAG(FTEPP_MATHDEFS)
GMQCC_DEFINE_FLAG(FTEPP_INDIRECT_EXPANSION)
GMQCC_DEFINE_FLAG(RELAXED_SWITCH)
GMQCC_DEFINE_FLAG(SHORT_LOGIC)
GMQCC_DEFINE_FLAG(PERL_LOGIC)
@ -50,6 +29,15 @@
GMQCC_DEFINE_FLAG(PERMISSIVE)
GMQCC_DEFINE_FLAG(VARIADIC_ARGS)
GMQCC_DEFINE_FLAG(LEGACY_VECTOR_MATHS)
GMQCC_DEFINE_FLAG(EXPRESSIONS_FOR_BUILTINS)
GMQCC_DEFINE_FLAG(RETURN_ASSIGNMENTS)
GMQCC_DEFINE_FLAG(UNSAFE_VARARGS)
GMQCC_DEFINE_FLAG(TYPELESS_STORES)
GMQCC_DEFINE_FLAG(SORT_OPERANDS)
GMQCC_DEFINE_FLAG(EMULATE_STATE)
GMQCC_DEFINE_FLAG(ARITHMETIC_EXCEPTIONS)
GMQCC_DEFINE_FLAG(SPLIT_VECTOR_PARAMETERS)
GMQCC_DEFINE_FLAG(DEFAULT_ERASEABLE)
#endif
/* warning flags */
@ -57,6 +45,7 @@
GMQCC_DEFINE_FLAG(UNINITIALIZED_GLOBAL)
GMQCC_DEFINE_FLAG(DEBUG)
GMQCC_DEFINE_FLAG(UNUSED_VARIABLE)
GMQCC_DEFINE_FLAG(UNUSED_COMPONENT)
GMQCC_DEFINE_FLAG(USED_UNINITIALIZED)
GMQCC_DEFINE_FLAG(UNKNOWN_CONTROL_SEQUENCE)
GMQCC_DEFINE_FLAG(EXTENSIONS)
@ -87,6 +76,12 @@
GMQCC_DEFINE_FLAG(DIFFERENT_ATTRIBUTES)
GMQCC_DEFINE_FLAG(DEPRECATED)
GMQCC_DEFINE_FLAG(PARENTHESIS)
GMQCC_DEFINE_FLAG(UNSAFE_TYPES)
GMQCC_DEFINE_FLAG(BREAKDEF)
GMQCC_DEFINE_FLAG(CONST_OVERWRITE)
GMQCC_DEFINE_FLAG(DIRECTIVE_INMACRO)
GMQCC_DEFINE_FLAG(BUILTINS)
GMQCC_DEFINE_FLAG(INEXACT_COMPARES)
#endif
#ifdef GMQCC_TYPE_OPTIMIZATIONS
@ -100,6 +95,8 @@
GMQCC_DEFINE_FLAG(CALL_STORES, 3)
GMQCC_DEFINE_FLAG(VOID_RETURN, 1)
GMQCC_DEFINE_FLAG(VECTOR_COMPONENTS, 1)
GMQCC_DEFINE_FLAG(CONST_FOLD_DCE, 2)
GMQCC_DEFINE_FLAG(CONST_FOLD, 0) /* cannot be turned off */
#endif
#ifdef GMQCC_TYPE_OPTIONS
@ -109,8 +106,6 @@
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)
GMQCC_DEFINE_FLAG(FORCECRC)
@ -118,7 +113,9 @@
GMQCC_DEFINE_FLAG(PP_ONLY)
GMQCC_DEFINE_FLAG(MAX_ARRAY_SIZE)
GMQCC_DEFINE_FLAG(ADD_INFO)
GMQCC_DEFINE_FLAG(CORRECTION)
GMQCC_DEFINE_FLAG(PROGSRC)
GMQCC_DEFINE_FLAG(COVERAGE)
GMQCC_DEFINE_FLAG(STATE_FPS)
#endif
/* some cleanup so we don't have to */

581
pak.c
View file

@ -1,581 +0,0 @@
/*
* Copyright (C) 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.
*/
#include "gmqcc.h"
/*
* The PAK format uses a FOURCC concept for storing the magic ident within
* the header as a uint32_t.
*/
#define PAK_FOURCC ((uint32_t)(('P' | ('A' << 8) | ('C' << 16) | ('K' << 24))))
typedef struct {
uint32_t magic; /* "PACK" */
/*
* Offset to first directory entry in PAK file. It's often
* best to store the directories at the end of the file opposed
* to the front, since it allows easy insertion without having
* to load the entire file into memory again.
*/
uint32_t diroff;
uint32_t dirlen;
} pak_header_t;
/*
* A directory, is sort of a "file entry". The concept of
* a directory in Quake world is a "file entry/record". This
* describes a file (with directories/nested ones too in it's
* file name). Hence it can be a file, file with directory, or
* file with directories.
*/
typedef struct {
char name[56];
uint32_t pos;
uint32_t len;
} pak_directory_t;
/*
* Used to get the next token from a string, where the
* strings themselfs are seperated by chracters from
* `sep`. This is essentially strsep.
*/
static char *pak_tree_sep(char **str, const char *sep) {
char *beg = *str;
char *end;
if (!beg)
return NULL;
if (*(end = beg + strcspn(beg, sep)))
* end++ = '\0'; /* null terminate */
else
end = 0;
*str = end;
return beg;
}
/*
* When given a string like "a/b/c/d/e/file"
* this function will handle the creation of
* the directory structure, included nested
* directories.
*/
static void pak_tree_build(const char *entry) {
char *directory;
char *elements[28];
char *pathsplit;
char *token;
size_t itr;
size_t jtr;
pathsplit = (char *)mem_a(56);
directory = (char *)mem_a(56);
memset(pathsplit, 0, 56);
util_strncpy(directory, entry, 56);
for (itr = 0; (token = pak_tree_sep(&directory, "/")) != NULL; itr++) {
elements[itr] = token;
}
for (jtr = 0; jtr < itr - 1; jtr++) {
util_strcat(pathsplit, elements[jtr]);
util_strcat(pathsplit, "/");
if (fs_dir_make(pathsplit)) {
mem_d(pathsplit);
mem_d(directory);
/* TODO: undo on fail */
return;
}
}
mem_d(pathsplit);
mem_d(directory);
}
typedef struct {
pak_directory_t *directories;
pak_header_t header;
FILE *handle;
bool insert;
} pak_file_t;
static pak_file_t *pak_open_read(const char *file) {
pak_file_t *pak;
size_t itr;
if (!(pak = (pak_file_t*)mem_a(sizeof(pak_file_t))))
return NULL;
if (!(pak->handle = fs_file_open(file, "rb"))) {
mem_d(pak);
return NULL;
}
pak->directories = NULL;
pak->insert = false; /* read doesn't allow insert */
memset (&pak->header, 0, sizeof(pak_header_t));
fs_file_read (&pak->header, sizeof(pak_header_t), 1, pak->handle);
util_endianswap(&pak->header, 1, sizeof(pak_header_t));
/*
* Every PAK file has "PACK" stored as FOURCC data in the
* header. If this data cannot compare (as checked here), it's
* probably not a PAK file.
*/
if (pak->header.magic != PAK_FOURCC) {
fs_file_close(pak->handle);
mem_d (pak);
return NULL;
}
/*
* Time to read in the directory handles and prepare the directories
* vector. We're going to be reading some the file inwards soon.
*/
fs_file_seek(pak->handle, pak->header.diroff, SEEK_SET);
/*
* Read in all directories from the PAK file. These are considered
* to be the "file entries".
*/
for (itr = 0; itr < pak->header.dirlen / 64; itr++) {
pak_directory_t dir;
fs_file_read (&dir, sizeof(pak_directory_t), 1, pak->handle);
util_endianswap(&dir, 1, sizeof(pak_directory_t));
vec_push(pak->directories, dir);
}
return pak;
}
static pak_file_t *pak_open_write(const char *file) {
pak_file_t *pak;
if (!(pak = (pak_file_t*)mem_a(sizeof(pak_file_t))))
return NULL;
/*
* Generate the required directory structure / tree for
* writing this PAK file too.
*/
pak_tree_build(file);
if (!(pak->handle = fs_file_open(file, "wb"))) {
/*
* The directory tree that was created, needs to be
* removed entierly if we failed to open a file.
*/
/* TODO backup directory clean */
mem_d(pak);
return NULL;
}
memset(&(pak->header), 0, sizeof(pak_header_t));
/*
* We're in "insert" mode, we need to do things like header
* "patching" and writing the directories at the end of the
* file.
*/
pak->insert = true;
pak->header.magic = PAK_FOURCC;
/* on BE systems we need to swap the byte order of the FOURCC */
util_endianswap(&pak->header.magic, 1, sizeof(uint32_t));
/*
* We need to write out the header since files will be wrote out to
* this even with directory entries, and that not wrote. The header
* will need to be patched in later with a file_seek, and overwrite,
* we could use offsets and other trickery. This is just easier.
*/
fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);
return pak;
}
pak_file_t *pak_open(const char *file, const char *mode) {
if (!file || !mode)
return NULL;
switch (*mode) {
case 'r': return pak_open_read (file);
case 'w': return pak_open_write(file);
}
return NULL;
}
bool pak_exists(pak_file_t *pak, const char *file, pak_directory_t **dir) {
size_t itr;
if (!pak || !file)
return false;
for (itr = 0; itr < vec_size(pak->directories); itr++) {
if (!strcmp(pak->directories[itr].name, file)) {
/*
* Store back a pointer to the directory that matches
* the request if requested (NULL is not allowed).
*/
if (dir) {
*dir = &(pak->directories[itr]);
}
return true;
}
}
return false;
}
/*
* Extraction abilities. These work as you expect them to.
*/
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)) {
return false;
}
if (!(dat = (unsigned char *)mem_a(dir->len))) {
return false;
}
/*
* Generate the directory structure / tree that will be required
* to store the extracted 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(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);
fs_file_read (dat, 1, dir->len, pak->handle);
/* write */
fs_file_write(dat, 1, dir->len, out);
/* close */
fs_file_close(out);
/* free */
mem_d(dat);
return true;
}
bool pak_extract_all(pak_file_t *pak, const char *dir) {
size_t itr;
if (!fs_dir_make(dir))
return false;
for (itr = 0; itr < vec_size(pak->directories); itr++) {
if (!pak_extract_one(pak, pak->directories[itr].name, dir))
return false;
}
return true;
}
/*
* Insertion functions (the opposite of extraction). Yes for generating
* PAKs.
*/
bool pak_insert_one(pak_file_t *pak, const char *file) {
pak_directory_t dir;
unsigned char *dat;
FILE *fp;
/*
* We don't allow insertion on files that already exist within the
* pak file. Weird shit can happen if we allow that ;). We also
* don't allow insertion if the pak isn't opened in write mode.
*/
if (!pak || !file || !pak->insert || pak_exists(pak, file, NULL))
return false;
if (!(fp = fs_file_open(file, "rb")))
return false;
/*
* Calculate the total file length, since it will be wrote to
* the directory entry, and the actual contents of the file
* to the PAK file itself.
*/
fs_file_seek(fp, 0, SEEK_END);
dir.len = fs_file_tell(fp);
fs_file_seek(fp, 0, SEEK_SET);
dir.pos = fs_file_tell(pak->handle);
/*
* We're limited to 56 bytes for a file name string, that INCLUDES
* the directory and '/' seperators.
*/
if (strlen(file) >= 56) {
fs_file_close(fp);
return false;
}
util_strncpy(dir.name, file, strlen(file));
/*
* Allocate some memory for loading in the data that will be
* redirected into the PAK file.
*/
if (!(dat = (unsigned char *)mem_a(dir.len))) {
fs_file_close(fp);
return false;
}
fs_file_read (dat, dir.len, 1, fp);
fs_file_close(fp);
fs_file_write(dat, dir.len, 1, pak->handle);
/*
* Now add the directory to the directories vector, so pak_close
* can actually write it.
*/
vec_push(pak->directories, dir);
return true;
}
/*
* Like pak_insert_one, except this collects files in all directories
* from a root directory, and inserts them all.
*/
bool pak_insert_all(pak_file_t *pak, const char *dir) {
DIR *dp;
struct dirent *dirp;
if (!(pak->insert))
return false;
if (!(dp = fs_dir_open(dir)))
return false;
while ((dirp = fs_dir_read(dp))) {
if (!(pak_insert_one(pak, dirp->d_name))) {
fs_dir_close(dp);
return false;
}
}
fs_dir_close(dp);
return true;
}
bool pak_close(pak_file_t *pak) {
size_t itr;
if (!pak)
return false;
/*
* In insert mode we need to patch the header, and write
* our directory entries at the end of the file.
*/
if (pak->insert) {
pak->header.dirlen = vec_size(pak->directories) * 64;
pak->header.diroff = ftell(pak->handle);
/* patch header */
fs_file_seek (pak->handle, 0, SEEK_SET);
fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);
/* write directories */
fs_file_seek (pak->handle, pak->header.diroff, SEEK_SET);
for (itr = 0; itr < vec_size(pak->directories); itr++) {
fs_file_write(&(pak->directories[itr]), sizeof(pak_directory_t), 1, pak->handle);
}
}
vec_free (pak->directories);
fs_file_close(pak->handle);
mem_d (pak);
return true;
}
/*
* Fancy GCC-like LONG parsing allows things like --opt=param with
* assignment operator. This is used for redirecting stdout/stderr
* console to specific files of your choice.
*/
static bool parsecmd(const char *optname, int *argc_, char ***argv_, char **out, int ds, bool split) {
int argc = *argc_;
char **argv = *argv_;
size_t len = strlen(optname);
if (strncmp(argv[0]+ds, optname, len))
return false;
/* it's --optname, check how the parameter is supplied */
if (argv[0][ds+len] == '=') {
*out = argv[0]+ds+len+1;
return true;
}
if (!split || argc < ds) /* no parameter was provided, or only single-arg form accepted */
return false;
/* using --opt param */
*out = argv[1];
--*argc_;
++*argv_;
return true;
}
int main(int argc, char **argv) {
bool extract = true;
char *redirout = (char*)stdout;
char *redirerr = (char*)stderr;
char *file = NULL;
char **files = NULL;
pak_file_t *pak = NULL;
size_t iter = 0;
con_init();
/*
* Command line option parsing commences now We only need to support
* a few things in the test suite.
*/
while (argc > 1) {
++argv;
--argc;
if (argv[0][0] == '-') {
if (parsecmd("redirout", &argc, &argv, &redirout, 1, false))
continue;
if (parsecmd("redirerr", &argc, &argv, &redirerr, 1, false))
continue;
if (parsecmd("file", &argc, &argv, &file, 1, false))
continue;
con_change(redirout, redirerr);
switch (argv[0][1]) {
case 'e': extract = true; continue;
case 'c': extract = false; continue;
}
if (!strcmp(argv[0]+1, "debug")) {
OPTS_OPTION_BOOL(OPTION_DEBUG) = true;
continue;
}
if (!strcmp(argv[0]+1, "memchk")) {
OPTS_OPTION_BOOL(OPTION_MEMCHK) = true;
continue;
}
if (!strcmp(argv[0]+1, "nocolor")) {
con_color(0);
continue;
}
}
vec_push(files, argv[0]);
}
con_change(redirout, redirerr);
if (!file) {
con_err("-file must be specified for output/input PAK file\n");
vec_free(files);
return EXIT_FAILURE;
}
if (extract) {
if (!(pak = pak_open(file, "r"))) {
con_err("failed to open PAK file %s\n", file);
vec_free(files);
return EXIT_FAILURE;
}
if (!pak_extract_all(pak, "./")) {
con_err("failed to extract PAK %s (files may be missing)\n", file);
pak_close(pak);
vec_free(files);
return EXIT_FAILURE;
}
/* not possible */
pak_close(pak);
vec_free(files);
util_meminfo();
return EXIT_SUCCESS;
}
if (!(pak = pak_open(file, "w"))) {
con_err("failed to open PAK %s for writing\n", file);
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);
pak_close(pak);
vec_free(files);
return EXIT_FAILURE;
}
}
/* not possible */
pak_close(pak);
vec_free(files);
util_meminfo();
return EXIT_SUCCESS;
}

File diff suppressed because it is too large Load diff

84
parser.h Normal file
View file

@ -0,0 +1,84 @@
#ifndef GMQCC_PARSER_HDR
#define GMQCC_PARSER_HDR
#include "gmqcc.h"
#include "lexer.h"
#include "ast.h"
#include "intrin.h"
#include "fold.h"
struct parser_t;
#define parser_ctx(p) ((p)->lex->tok.ctx)
struct parser_t {
parser_t();
~parser_t();
void remove_ast();
lex_file *lex;
int tok;
bool ast_cleaned;
std::vector<ast_expression *> globals;
std::vector<ast_expression *> fields;
std::vector<ast_function *> functions;
size_t translated;
/* must be deleted first, they reference immediates and values */
std::vector<ast_value *> accessors;
ast_value *nil;
ast_value *reserved_version;
size_t crc_globals;
size_t crc_fields;
ast_function *function;
ht aliases;
/* All the labels the function defined...
* Should they be in ast_function instead?
*/
std::vector<ast_label*> labels;
std::vector<ast_goto*> gotos;
std::vector<const char *> breaks;
std::vector<const char *> continues;
/* A list of hashtables for each scope */
std::vector<ht> variables;
ht htfields;
ht htglobals;
std::vector<ht> typedefs;
/* not to be used directly, we use the hash table */
std::vector<ast_expression*> _locals;
std::vector<size_t> _blocklocals;
std::vector<std::unique_ptr<ast_value>> _typedefs;
std::vector<size_t> _blocktypedefs;
std::vector<lex_ctx_t> _block_ctx;
/* we store the '=' operator info */
const oper_info *assign_op;
/* magic values */
ast_value *const_vec[3];
/* pragma flags */
bool noref;
/* collected information */
size_t max_param_count;
fold m_fold;
intrin m_intrin;
};
/* parser.c */
char *parser_strdup (const char *str);
ast_expression *parser_find_global(parser_t *parser, const char *name);
#endif

250
stat.cpp Normal file
View file

@ -0,0 +1,250 @@
#include <string.h>
#include <stdlib.h>
#include "gmqcc.h"
/*
* strdup does it's own malloc, we need to track malloc. We don't want
* to overwrite malloc though, infact, we can't really hook it at all
* without library specific assumptions. So we re implement strdup.
*/
char *stat_mem_strdup(const char *src, bool empty) {
size_t len = 0;
char *ptr = nullptr;
if (!src)
return nullptr;
len = strlen(src);
if ((!empty ? len : true) && (ptr = (char*)mem_a(len + 1))) {
memcpy(ptr, src, len);
ptr[len] = '\0';
}
return ptr;
}
/*
* The reallocate function for resizing vectors.
*/
void _util_vec_grow(void **a, size_t i, size_t s) {
vector_t *d = nullptr;
size_t m = 0;
void *p = nullptr;
if (*a) {
d = vec_meta(*a);
m = 2 * d->allocated + i;
p = mem_r(d, s * m + sizeof(vector_t));
} else {
m = i + 1;
p = mem_a(s * m + sizeof(vector_t));
((vector_t*)p)->used = 0;
}
d = (vector_t*)p;
d->allocated = m;
*a = d + 1;
}
void _util_vec_delete(void *data) {
mem_d(vec_meta(data));
}
/*
* Hash table for generic data, based on dynamic memory allocations
* all around. This is the internal interface, please look for
* EXPOSED INTERFACE comment below
*/
struct hash_node_t {
char *key; /* the key for this node in table */
void *value; /* pointer to the data as void* */
hash_node_t *next; /* next node (linked list) */
};
size_t hash(const char *key);
size_t util_hthash(hash_table_t *ht, const char *key) {
return hash(key) % ht->size;
}
static hash_node_t *_util_htnewpair(const char *key, void *value) {
hash_node_t *node;
if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t))))
return nullptr;
if (!(node->key = util_strdupe(key))) {
mem_d(node);
return nullptr;
}
node->value = value;
node->next = nullptr;
return node;
}
/*
* EXPOSED INTERFACE for the hashtable implementation
* util_htnew(size) -- to make a new hashtable
* util_htset(table, key, value, sizeof(value)) -- to set something in the table
* util_htget(table, key) -- to get something from the table
* util_htdel(table) -- to delete the table
*/
hash_table_t *util_htnew(size_t size) {
hash_table_t *hashtable = nullptr;
if (size < 1)
return nullptr;
if (!(hashtable = (hash_table_t*)mem_a(sizeof(hash_table_t))))
return nullptr;
if (!(hashtable->table = (hash_node_t**)mem_a(sizeof(hash_node_t*) * size))) {
mem_d(hashtable);
return nullptr;
}
hashtable->size = size;
memset(hashtable->table, 0, sizeof(hash_node_t*) * size);
return hashtable;
}
void util_htseth(hash_table_t *ht, const char *key, size_t bin, void *value) {
hash_node_t *newnode = nullptr;
hash_node_t *next = nullptr;
hash_node_t *last = nullptr;
next = ht->table[bin];
while (next && next->key && strcmp(key, next->key) > 0)
last = next, next = next->next;
/* already in table, do a replace */
if (next && next->key && strcmp(key, next->key) == 0) {
next->value = value;
} else {
/* not found, grow a pair man :P */
newnode = _util_htnewpair(key, value);
if (next == ht->table[bin]) {
newnode->next = next;
ht->table[bin] = newnode;
} else if (!next) {
last->next = newnode;
} else {
newnode->next = next;
last->next = newnode;
}
}
}
void util_htset(hash_table_t *ht, const char *key, void *value) {
util_htseth(ht, key, util_hthash(ht, key), value);
}
void *util_htgeth(hash_table_t *ht, const char *key, size_t bin) {
hash_node_t *pair = ht->table[bin];
while (pair && pair->key && strcmp(key, pair->key) > 0)
pair = pair->next;
if (!pair || !pair->key || strcmp(key, pair->key) != 0)
return nullptr;
return pair->value;
}
void *util_htget(hash_table_t *ht, const char *key) {
return util_htgeth(ht, key, util_hthash(ht, key));
}
void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin);
void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin) {
hash_node_t *pair;
size_t len, keylen;
int cmp;
keylen = strlen(key);
pair = ht->table[bin];
while (pair && pair->key) {
len = strlen(pair->key);
if (len < keylen) {
pair = pair->next;
continue;
}
if (keylen == len) {
cmp = strcmp(key, pair->key);
if (cmp == 0)
return pair->value;
if (cmp < 0)
return nullptr;
pair = pair->next;
continue;
}
cmp = strcmp(key, pair->key + len - keylen);
if (cmp == 0) {
uintptr_t up = (uintptr_t)pair->value;
up += len - keylen;
return (void*)up;
}
pair = pair->next;
}
return nullptr;
}
/*
* Free all allocated data in a hashtable, this is quite the amount
* of work.
*/
void util_htrem(hash_table_t *ht, void (*callback)(void *data)) {
size_t i = 0;
for (; i < ht->size; ++i) {
hash_node_t *n = ht->table[i];
hash_node_t *p;
/* free in list */
while (n) {
if (n->key)
mem_d(n->key);
if (callback)
callback(n->value);
p = n;
n = p->next;
mem_d(p);
}
}
/* free table */
mem_d(ht->table);
mem_d(ht);
}
void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) {
hash_node_t **pair = &ht->table[bin];
hash_node_t *tmp;
while (*pair && (*pair)->key && strcmp(key, (*pair)->key) > 0)
pair = &(*pair)->next;
tmp = *pair;
if (!tmp || !tmp->key || strcmp(key, tmp->key) != 0)
return;
if (cb)
(*cb)(tmp->value);
*pair = tmp->next;
mem_d(tmp->key);
mem_d(tmp);
}
void util_htrm(hash_table_t *ht, const char *key, void (*cb)(void*)) {
util_htrmh(ht, key, util_hthash(ht, key), cb);
}
void util_htdel(hash_table_t *ht) {
util_htrem(ht, nullptr);
}

View file

@ -1,24 +0,0 @@
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.

View file

@ -1,8 +0,0 @@
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/

View file

@ -1,55 +0,0 @@
[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"

View file

@ -1,5 +0,0 @@
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/

View file

@ -1,173 +0,0 @@
<?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*
(".*?"|&lt;.*&gt;)
</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">
(?&lt;![\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">
(?&lt;![\w\.])
0[xX][a-fA-F0-9]+[uUlL]*
(?![\w\.])
</match>
</context>
<context id="invalid-hexadecimal" style-ref="error">
<match extended="true">
(?&lt;![\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">
(?&lt;![\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>

View file

@ -1,26 +0,0 @@
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>

View file

@ -1,271 +0,0 @@
<?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=",+-=&lt;&gt;/?^&amp;*" />
<!-- 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">??&lt;</SEQ>
<SEQ TYPE="LITERAL4">??!</SEQ>
<SEQ TYPE="LITERAL4">??&gt;</SEQ>
<SEQ TYPE="LITERAL4">??-</SEQ>
<SEQ TYPE="LITERAL4">??=</SEQ>
<!-- Alternate tokens -->
<SEQ TYPE="LITERAL4">&lt;:</SEQ>
<SEQ TYPE="LITERAL4">:&gt;</SEQ>
<SEQ TYPE="LITERAL4">&lt;%</SEQ>
<SEQ TYPE="LITERAL4">%&gt;</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">&gt;</SEQ>
<SEQ TYPE="OPERATOR">&lt;</SEQ>
<SEQ TYPE="OPERATOR">%</SEQ>
<SEQ TYPE="OPERATOR">&amp;</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>/**&lt;</BEGIN>
<END>*/</END>
</SPAN>
<SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">
<BEGIN>/**</BEGIN>
<END>*/</END>
</SPAN>
<EOL_SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">///&lt;</EOL_SPAN>
<EOL_SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">///</EOL_SPAN>
<!-- Doxygen comment, Qt style -->
<SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">
<BEGIN>/*!&lt;</BEGIN>
<END>*/</END>
</SPAN>
<SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">
<BEGIN>/*!</BEGIN>
<END>*/</END>
</SPAN>
<EOL_SPAN TYPE="COMMENT3" DELEGATE="doxygen::DOXYGEN">//!&lt;</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>&lt;</BEGIN>
<END>&gt;</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>

View file

@ -1,9 +0,0 @@
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

View file

@ -1,155 +0,0 @@
<?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="&quot;"/>
<Detect2Chars attribute="Comment" context="Commentar 1" char="/" char1="/"/>
<Detect2Chars attribute="Comment" context="Commentar 2" char="/" char1="*" beginRegion="Comment"/>
<AnyChar attribute="Symbol" context="#stay" String=":!%&amp;()+,-/.*&lt;=&gt;?[]|~^&#59;"/>
</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="&quot;"/>
</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="&quot;" char1="&quot;"/>
<RangeDetect attribute="Prep. Lib" context="#stay" char="&lt;" char1="&gt;"/>
<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="&quot;"/>
<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="&quot;"/>
<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="'&quot;" />
</general>
</language>

View file

@ -1,12 +0,0 @@
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

View file

@ -1,22 +0,0 @@
# 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:]]+$"

File diff suppressed because it is too large Load diff

18
tests/accumulate.qc Normal file
View file

@ -0,0 +1,18 @@
#define ACCUMULATE_FUNCTION(FUNC) \
[[accumulate]] void FUNC ()
ACCUMULATE_FUNCTION(foo) {
print("hello ");
}
ACCUMULATE_FUNCTION(foo) {
print("accumulation ");
}
ACCUMULATE_FUNCTION(foo) {
print("world\n");
}
void main() {
foo();
}

5
tests/accumulate.tmpl Normal file
View file

@ -0,0 +1,5 @@
I: accumulate.qc
D: test function accumulation
T: -execute
C: -std=gmqcc -fftepp
M: hello accumulation world

13
tests/arithexcept.qc Normal file
View file

@ -0,0 +1,13 @@
const float huge = 340282346638528859811704183484516925440.000000; // FLT_MAX
#ifdef DIVBYZERO
const float a = 1.0 / 0.0;
#endif
#ifdef OVERFLOW
const float a = huge * huge;
#endif
#ifdef UNDERFLOW
const float a = 1 / huge;
#endif

4
tests/arithexcept.tmpl Normal file
View file

@ -0,0 +1,4 @@
I: arithexcept.qc
D: arithmetic exceptions (divide by zero)
T: -fail
C: -std=fteqcc -farithmetic-exceptions -DDIVBYZERO

View file

@ -0,0 +1,4 @@
I: arithexcept.qc
D: arithmetic exceptions (overflow)
T: -fail
C: -std=fteqcc -farithmetic-exceptions -DOVERFLOW

View file

@ -0,0 +1,4 @@
I: arithexcept.qc
D: arithmetic exceptions (underflow)
T: -fail
C: -std=fteqcc -farithmetic-exceptions -DUNDERFLOW

View file

@ -1,7 +1,7 @@
I: arrays.qc
D: array accessors and functionality
I: arrays2.qc
D: initialized arrays
T: -execute
C: -std=fteqcc
M: 1001 1101 1201 1301 1401 1501
M: 1001 1101 1201 1301 1401 1501 1601
M: 1001 1101 1201 1301 1401 1501
M: 10 20 30 40 50 60 70
M: 100 200 300 400 500 600 0
M: Hello World

18
tests/arrays2.qc Normal file
View file

@ -0,0 +1,18 @@
float glob1[7] = { 10, 20, 30, 40, 50, 60, 70 };
float glob2[7] = { 100, 200, 300, 400, 500, 600 };
string globs[] = { "Hello ", "World" };
void main() {
float i;
print(ftos(glob1[0]));
for (i = 1; i != 7; ++i)
print(" ", ftos(glob1[i]));
print("\n");
print(ftos(glob2[0]));
for (i = 1; i != 7; ++i)
print(" ", ftos(glob2[i]));
print("\n");
print(globs[0], globs[1], "\n");
}

7
tests/arrays2.tmpl Normal file
View file

@ -0,0 +1,7 @@
I: arrays.qc
D: array accessors and functionality
T: -execute
C: -std=fteqcc
M: 1001 1101 1201 1301 1401 1501
M: 1001 1101 1201 1301 1401 1501 1601
M: 1001 1101 1201 1301 1401 1501

View file

@ -3,12 +3,35 @@ void main() {
float b; b = 1;
float c; c = 1;
float d; d = 1;
vector e; e = '1 1 1';
vector f; f = '1 1 1';
#ifdef __STD_FTEQCC__
a &~= 1; // 0
#else
a &= ~1; // 0
#endif
#ifdef __STD_GMQCC__
b &= ~1; // 0
c &= ~d; // 0
#else
b &~= 1; // 0
c &~= 1; // 0
#endif
#ifdef __STD_FTEQCC__
f &~= e; // '0 0 0'
#else
f &= ~e; // '0 0 0'
#endif
#ifdef __STD_GMQCC__
e &= ~e; // '0 0 0'
#else
e &~= e; // '0 0 0'
#endif
print("a: ", ftos(a), "\nb: ",
ftos(b), "\nc: ",
ftos(c), "\n");
print("e: ", vtos(e), "\n");
print("f: ", vtos(f), "\n");
}

View file

@ -1,9 +1,11 @@
# used to test the builtins
I: bitnot.qc
D: test bitwise not operators
D: test bitwise not operators (fteqcc operators)
T: -execute
C: -std=gmqcc
C: -std=fteqcc
E: $null
M: a: 0
M: b: 0
M: c: 0
M: e: '0 0 0'
M: f: '0 0 0'

11
tests/bitnotgmqcc.tmpl Normal file
View file

@ -0,0 +1,11 @@
# used to test the builtins
I: bitnot.qc
D: test bitwise not operators (gmqcc operators)
T: -execute
C: -std=gmqcc -fftepp
E: $null
M: a: 0
M: b: 0
M: c: 0
M: e: '0 0 0'
M: f: '0 0 0'

View file

@ -8,5 +8,5 @@ void(float a, float b, float c) main = {
sum(sum(sum(a, b, c), b, sum(a, b, c)), b, sum(a, b, sum(a, b, c))),
sum(sum(a, b, c), b, c));
print(ftos(f), "\n");
};

View file

@ -2,7 +2,7 @@ I: correct-logic.qc
D: vector logic flags
T: -execute
C: -std=fteqcc -fshort-logic
M: ! & | i N
M: ! & | i N
M: 0, 0 -> 1 0 0 0 1
M: 0, x -> 1 0 1 0 1
M: x, 0 -> 0 0 1 1 0

View file

@ -2,7 +2,7 @@ I: correct-logic.qc
D: vector logic flags
T: -execute
C: -std=fteqcc
M: ! & | i N
M: ! & | i N
M: 0, 0 -> 1 0 0 0 1
M: 0, x -> 1 0 1 0 1
M: x, 0 -> 0 0 1 1 0

View file

@ -2,7 +2,7 @@ I: correct-logic.qc
D: vector logic flags
T: -execute
C: -std=fteqcc -fcorrect-logic -fshort-logic
M: ! & | i N
M: ! & | i N
M: 0, 0 -> 1 0 0 0 1
M: 0, x -> 1 0 1 0 1
M: x, 0 -> 0 0 1 1 0

View file

@ -2,7 +2,7 @@ I: correct-logic.qc
D: vector logic flags
T: -execute
C: -std=fteqcc -fcorrect-logic
M: ! & | i N
M: ! & | i N
M: 0, 0 -> 1 0 0 0 1
M: 0, x -> 1 0 1 0 1
M: x, 0 -> 0 0 1 1 0

View file

@ -3,17 +3,19 @@
// builtins. I no event shall you even consider adding
// these individually per test.
void (string, ...) print = #1;
string (float) ftos = #2;
entity () spawn = #3;
void (entity) kill = #4;
string (vector) vtos = #5;
void (string) error = #6;
float (vector) vlen = #7;
string (entity) etos = #8;
float (string) stof = #9;
string (...) strcat = #10;
float (string, string) strcmp = #11;
vector (vector) normalize = #12;
float (float) sqrt = #13;
float (float) floor = #14;
void (string str, ...) print = #1;
string (float val) ftos = #2;
entity () spawn = #3;
void (entity ent) kill = #4;
string (vector vec) vtos = #5;
void (string str) error = #6;
float (vector vec) vlen = #7;
string (entity ent) etos = #8;
float (string str) stof = #9;
string (...) strcat = #10;
float (string str1, string str2) strcmp = #11;
vector (vector vec) normalize = #12;
float (float val) sqrt = #13;
float (float val) floor = #14;
float (float val1, float val2) pow = #15;
vector (string str) stov = #16;

27
tests/dots.qc Normal file
View file

@ -0,0 +1,27 @@
entity self;
.float f;
..float fp;
...float fpp;
void try(entity e, ...float pp) {
print("and: ", ftos( e.(e.(e.pp)) ), "\n");
}
typedef float Float;
void try2(entity e, ...Float pp) {
print("and: ", ftos( e.(e.(e.pp)) ), "\n");
}
// whereas the varargs are tested in vararg tests
void main() {
self = spawn();
self.f = 123;
self.fp = f;
self.fpp = fp;
print(ftos( self.(self.fp) ), "\n");
print(ftos( self.(self.(self.fpp)) ), "\n");
try(self, fpp);
try2(self, fpp);
}

8
tests/dots.tmpl Normal file
View file

@ -0,0 +1,8 @@
I: dots.qc
D: TOKEN_DOTS disambiguation
T: -execute
C: -std=fteqcc
M: 123
M: 123
M: and: 123
M: and: 123

View file

@ -1,13 +1,13 @@
float pow(float x, float y) {
return __builtin_pow(x, y);
}
void main() {
float hundy = pow(10, 2); // 10^2 == 100
float hundy = __builtin_pow(10, 2); // 10^2 == 100
print(ftos(hundy), "\n"); // prints: 100
hundy = pow(10, 2);
print(ftos(hundy), "\n");
hundy -= 90; // 100-90 = 10
print(ftos(hundy ** 2), "\n"); // prints: 100
print(ftos(pow(hundy, 2)), "\n"); // prints: 100
hundy = 10.0f;
print(ftos(__builtin_exp(hundy)), "\n"); // prints: 22026.5

View file

@ -6,4 +6,6 @@ C: -std=gmqcc
E: $null
M: 100
M: 100
M: 100
M: 100
M: 22026.5

7
tests/exprforbuiltins.qc Normal file
View file

@ -0,0 +1,7 @@
/* empty line required */
void print(string, ...) = #__LINE__ - 1;
void main(string input) {
print(input, "\n");
}

View file

@ -0,0 +1,7 @@
I: exprforbuiltins.qc
D: expressions for builtins
T: -execute
C: -std=gmqcc -fftepp -fftepp-predefs
F: -no-defs
E: -string test
M: test

Some files were not shown because too many files have changed in this diff Show more