mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-04-07 02:22:22 +00:00
Compare commits
1542 commits
Author | SHA1 | Date | |
---|---|---|---|
|
297eab9e5e | ||
|
da63ad7e07 | ||
|
ddcae703e3 | ||
|
6cf25c0ec6 | ||
|
663723f00a | ||
|
1e8ce1733b | ||
|
47475bb455 | ||
|
71138cbe1a | ||
|
85c79d2f1c | ||
|
13bcb5c5b1 | ||
|
465941f357 | ||
|
237722c0b2 | ||
|
f971f89e1e | ||
|
94c2936bfa | ||
|
2d4a054440 | ||
|
031f827da5 | ||
|
451873ae52 | ||
|
9c81ff263a | ||
|
620bd76e76 | ||
|
2d99ce609d | ||
|
0904a1ceb7 | ||
|
c74fabffda | ||
|
092067482f | ||
|
dac058107a | ||
|
9a21c638fa | ||
|
97a74eb677 | ||
|
f84c8ea629 | ||
|
e920766b10 | ||
|
e006aa8238 | ||
|
73d3d7eec1 | ||
|
3cf2c52fce | ||
|
1580c23556 | ||
|
b14a02e735 | ||
|
679e3771de | ||
|
d9127bf28a | ||
|
fa7dce495b | ||
|
02b20dbd09 | ||
|
6ad5f18ef1 | ||
|
047ecd426f | ||
|
fb3af2831b | ||
|
5a0d645ede | ||
|
27c0886ffb | ||
|
163c4b99a4 | ||
|
eb2d478770 | ||
|
3f5305af58 | ||
|
8538658e83 | ||
|
8b2149e315 | ||
|
c285eb385d | ||
|
2dde6d903e | ||
|
4bf63bb379 | ||
|
95d232ca72 | ||
|
90f190f5e1 | ||
|
566c17a964 | ||
|
a5636899f2 | ||
|
17c0812ae4 | ||
|
3a7848d67c | ||
|
def1a26b12 | ||
|
eab20602b1 | ||
|
69fa4f8dbd | ||
|
966991601c | ||
|
01f3447e5b | ||
|
9821b6a075 | ||
|
6938567c6c | ||
|
0b94d7583c | ||
|
4c48bae203 | ||
|
ad1cfcfeaa | ||
|
eca4e2c309 | ||
|
167207e98c | ||
|
e06ad170de | ||
|
3714a507c2 | ||
|
63c679ee81 | ||
|
be64736dd4 | ||
|
f6bc9705d2 | ||
|
5d8c18dcab | ||
|
1a18ff5294 | ||
|
3f4659b5d5 | ||
|
6024e377ba | ||
|
ee3c1e43c9 | ||
|
a9ac6987a6 | ||
|
fab640da4c | ||
|
fd0cc40b9c | ||
|
6d4539814e | ||
|
896d4c53a3 | ||
|
d8e9b1b35d | ||
|
66d908f39b | ||
|
45236a644f | ||
|
fa21d85820 | ||
|
e922403aa8 | ||
|
ff37abb0c7 | ||
|
90b5a6538a | ||
|
866fc3e247 | ||
|
41a76ab91d | ||
|
b640049912 | ||
|
9335bc2f4f | ||
|
49f4fedecf | ||
|
6149f6a1d0 | ||
|
9d98805dfb | ||
|
e7d1e701c4 | ||
|
5c64437189 | ||
|
5968e3faa0 | ||
|
566e761546 | ||
|
f09c6a5d63 | ||
|
794396df79 | ||
|
380fb3d44f | ||
|
dedb3a49bd | ||
|
9535805c02 | ||
|
44b0d7f658 | ||
|
1826971301 | ||
|
db9c37d18b | ||
|
7e0e041527 | ||
|
e2ba77a546 | ||
|
76278e8b97 | ||
|
6e68526680 | ||
|
0ecfe18f49 | ||
|
e8fbae4b3e | ||
|
f38e6b48db | ||
|
a1f13499f9 | ||
|
539dc4a3dc | ||
|
2e037832d3 | ||
|
987f765c20 | ||
|
b345b4e21b | ||
|
9c31c53cc5 | ||
|
fe95b28a35 | ||
|
317e0499f7 | ||
|
b5d8b44503 | ||
|
35a8c3c9af | ||
|
2e3b3569bf | ||
|
878195bdec | ||
|
aabefd1bfe | ||
|
4de08db0e7 | ||
|
67a3c9b031 | ||
|
d4deaa35ca | ||
|
51a7b8e6a7 | ||
|
65362d93aa | ||
|
a7b45ea14d | ||
|
9d89a059aa | ||
|
dc510baf4f | ||
|
b5ac2745d6 | ||
|
0a00807e57 | ||
|
ff526954b6 | ||
|
42b3640bc5 | ||
|
6caaedd269 | ||
|
8b250457ab | ||
|
644a807731 | ||
|
724bca0eec | ||
|
2c421c3b71 | ||
|
5b9e0a62ab | ||
|
d6bf906647 | ||
|
1ad849d939 | ||
|
044f8b396d | ||
|
893f204b30 | ||
|
486b215706 | ||
|
d8c09c200a | ||
|
e452c176b4 | ||
|
833f315a16 | ||
|
a77797d6a6 | ||
|
783b7b6594 | ||
|
114a1d3b14 | ||
|
6fee3ec363 | ||
|
2b10d588e4 | ||
|
e3577912c8 | ||
|
ac8c7d730a | ||
|
5d5b9a379a | ||
|
8f7242d314 | ||
|
103e549615 | ||
|
ab841b94f7 | ||
|
624e6201e8 | ||
|
8b25e95553 | ||
|
ddb0b7dd9d | ||
|
806850e408 | ||
|
09109bb176 | ||
|
3df51c5979 | ||
|
2a00b386ba | ||
|
15b31e7dc5 | ||
|
fa7d44e0c7 | ||
|
859e9fe3da | ||
|
de22dec56b | ||
|
641136fee3 | ||
|
b08195e2da | ||
|
31cd263e33 | ||
|
a502a5453f | ||
|
2208136403 | ||
|
faacfa018a | ||
|
1a8bb31d2a | ||
|
459356a48d | ||
|
beaba494b5 | ||
|
3e576bd1f3 | ||
|
25caf4b8e8 | ||
|
d5690074e1 | ||
|
823b053e60 | ||
|
4c1c1bc051 | ||
|
bca1a7143d | ||
|
161bbec262 | ||
|
3e43056f5f | ||
|
c33755b007 | ||
|
e7d81937ae | ||
|
53e9ed0d96 | ||
|
05b349c72f | ||
|
463426ad47 | ||
|
655c2482c9 | ||
|
0c85bac71b | ||
|
aed893b6b8 | ||
|
337d7ddbf4 | ||
|
ff80bf1aa2 | ||
|
1497191e3c | ||
|
3945f26d92 | ||
|
4fa694fe82 | ||
|
edb38ce70e | ||
|
536138273f | ||
|
68c2baa7c1 | ||
|
05e20bcdda | ||
|
f1ab19ba0b | ||
|
b7b60e7468 | ||
|
bbeb2517c0 | ||
|
2917d39ef1 | ||
|
cc20d7e4e9 | ||
|
5dc7e62b19 | ||
|
6424ebaf98 | ||
|
7024ebfe7f | ||
|
a371c4ee27 | ||
|
ba0ac97372 | ||
|
8dafdfc5e2 | ||
|
0d8b0d419c | ||
|
0d1a740bc7 | ||
|
0db41f4279 | ||
|
15d1277158 | ||
|
2b7b2ea455 | ||
|
e8133893a0 | ||
|
f1650c42d9 | ||
|
606d7ac110 | ||
|
90533079c8 | ||
|
fe14d1b056 | ||
|
8250124c51 | ||
|
8c0a280a3e | ||
|
9e5d02dab0 | ||
|
827826b9f9 | ||
|
763e85b3ae | ||
|
b21e967581 | ||
|
06e2cb2b1b | ||
|
581c48e337 | ||
|
56edc3db9c | ||
|
52adc2113f | ||
|
69b89dc6ac | ||
|
f7e074d88f | ||
|
7ffda37513 | ||
|
24763aad65 | ||
|
360389638b | ||
|
2ddb5ad50d | ||
|
3070c03fc0 | ||
|
1bf9ebabcc | ||
|
9cc4fe1ed2 | ||
|
fee2986907 | ||
|
669a055594 | ||
|
24f9313952 | ||
|
a140b749ff | ||
|
0f506e768b | ||
|
792c1afd95 | ||
|
4ff68e07e8 | ||
|
5a160b0e88 | ||
|
a934e0fe4b | ||
|
b6b4a87cbf | ||
|
acdc559d1f | ||
|
5319caaaea | ||
|
0b6637cc67 | ||
|
1e30c2b81d | ||
|
26ab792f9c | ||
|
7e88247ed5 | ||
|
f24bdced10 | ||
|
31e13e6e64 | ||
|
103bca7284 | ||
|
d43a270142 | ||
|
4c5a0ff662 | ||
|
4d4851e179 | ||
|
58cd326d85 | ||
|
50f905b821 | ||
|
072bff44e6 | ||
|
af53c0cb83 | ||
|
6a44b72db3 | ||
|
b20e2a9d34 | ||
|
11ecc6cb0b | ||
|
2024b3bd71 | ||
|
78b615fce5 | ||
|
892746056e | ||
|
d14c757076 | ||
|
320784b20d | ||
|
7b7d012255 | ||
|
a20127b063 | ||
|
9b92cb0897 | ||
|
43e9885a08 | ||
|
ac7e1a557d | ||
|
ea801acdb8 | ||
|
4583cb8280 | ||
|
cb97b7f672 | ||
|
1d347eaf66 | ||
|
c3cc6f184e | ||
|
bf127088ca | ||
|
9749ec350a | ||
|
e5fc8fdded | ||
|
2d0f0a3607 | ||
|
25e86c04eb | ||
|
f19d32b29b | ||
|
dc48af195d | ||
|
33c0c83d59 | ||
|
02c6076bfd | ||
|
3209aaa996 | ||
|
8a26ed7664 | ||
|
50d1bfe783 | ||
|
63c0917d24 | ||
|
87a43777ab | ||
|
23904bad52 | ||
|
52cda620b2 | ||
|
1c33bcfceb | ||
|
db182819ae | ||
|
ab2a4f1318 | ||
|
80adfebd23 | ||
|
aee68d80ea | ||
|
457a1b9690 | ||
|
943cb2ca64 | ||
|
556a84a46f | ||
|
b52cf4d47e | ||
|
e2bfaf8109 | ||
|
c68a5c29e1 | ||
|
11f79bb1a6 | ||
|
54f331a64a | ||
|
74b58c5bb8 | ||
|
292c8150b4 | ||
|
b1fd85b711 | ||
|
d9572e3e30 | ||
|
0860b7a68b | ||
|
759fca6921 | ||
|
3b6e7d0ce1 | ||
|
ae9d3d42cf | ||
|
29f2cc302b | ||
|
7011a2ef2c | ||
|
ec03b55d1a | ||
|
9131644412 | ||
|
49bb172a09 | ||
|
73c4015046 | ||
|
1900262df4 | ||
|
f43106017f | ||
|
eb4486a7ac | ||
|
1d5229ee8c | ||
|
eee7d0aac1 | ||
|
de12a24bc9 | ||
|
6ea88c9a3f | ||
|
de14d514f3 | ||
|
99de3cf4f5 | ||
|
7f2b2061e6 | ||
|
1d745fd1f9 | ||
|
7a29f65683 | ||
|
1ca36b7e49 | ||
|
a120209567 | ||
|
b1016c7f48 | ||
|
91c894d4da | ||
|
065a870e7a | ||
|
b87eb89853 | ||
|
c90807dec6 | ||
|
0695ad1659 | ||
|
b5b9559d6f | ||
|
3988aae73e | ||
|
0f6c44d671 | ||
|
8d5e719026 | ||
|
0cfc275f82 | ||
|
c210340081 | ||
|
c675ba8086 | ||
|
9f54610fbd | ||
|
02a1d9f4a1 | ||
|
97217b55d1 | ||
|
dd33f4e498 | ||
|
f8949e17c8 | ||
|
d6f020fd6a | ||
|
05ac126d6f | ||
|
cfea900afd | ||
|
8a9c4edce8 | ||
|
4da820ef61 | ||
|
2c975bb344 | ||
|
1b14c49815 | ||
|
8699053887 | ||
|
003bb9dfb4 | ||
|
0f479f3e88 | ||
|
c63bebd7d8 | ||
|
b147602d78 | ||
|
f53502c9ca | ||
|
50d165e173 | ||
|
eca82511c6 | ||
|
6d8d7ee923 | ||
|
c8413a9a04 | ||
|
8e8b3608fb | ||
|
65a2b83abd | ||
|
19331ee385 | ||
|
ef51b30387 | ||
|
f008cc257d | ||
|
ccb46d7e3b | ||
|
42a9784804 | ||
|
82afdb1e2c | ||
|
62ac7e9966 | ||
|
6da151eba1 | ||
|
856949a5f9 | ||
|
d8b3faa871 | ||
|
92c0d6157c | ||
|
fa14550d38 | ||
|
604c9d25bf | ||
|
4d0bf1607a | ||
|
63fdab8422 | ||
|
87d9371a5c | ||
|
3d5fedcf39 | ||
|
637651f4e1 | ||
|
e9bde1e4e4 | ||
|
34c18ab860 | ||
|
dab528acda | ||
|
e8955f17ea | ||
|
033cf7c7d3 | ||
|
5138a25420 | ||
|
12a864abf5 | ||
|
151606e255 | ||
|
14ef6a1c42 | ||
|
9dabb68d7f | ||
|
f73f2f1ba9 | ||
|
e263506b3f | ||
|
3e362e872c | ||
|
f83cc1b91d | ||
|
6bd6379c87 | ||
|
a02e44100e | ||
|
99e3ae9773 | ||
|
300fb9905b | ||
|
ffdd6df828 | ||
|
2cf5046d38 | ||
|
cc69370575 | ||
|
263fcfbc2f | ||
|
2ebf571129 | ||
|
90824c2093 | ||
|
8f359f3849 | ||
|
08891068c8 | ||
|
b6f08e7fb1 | ||
|
fa14ca93d2 | ||
|
dfbd093348 | ||
|
e928cabfb2 | ||
|
03b56bd41f | ||
|
7249c2ec18 | ||
|
353455e1ad | ||
|
b10de1b240 | ||
|
3c931ecbf1 | ||
|
c6056d441b | ||
|
7c25af973c | ||
|
81df8fa139 | ||
|
8a294683bb | ||
|
c4e92df106 | ||
|
2b3663e18d | ||
|
0d1f20fea3 | ||
|
95b7056427 | ||
|
c8a1b6563e | ||
|
48211572e5 | ||
|
d61c5d3b16 | ||
|
15b0555546 | ||
|
cf2352893f | ||
|
894e1976e3 | ||
|
904c45060b | ||
|
87fcf8d8e8 | ||
|
d2405a9ad8 | ||
|
d664b9f607 | ||
|
13ef558fff | ||
|
3968dc84fd | ||
|
330111d5fc | ||
|
fac4e411bf | ||
|
73eca0848c | ||
|
37a4265e06 | ||
|
69efb404bf | ||
|
99422d0cf4 | ||
|
8d2a6ca419 | ||
|
f25fff1e3d | ||
|
e18849fa42 | ||
|
5a47dd5e62 | ||
|
b6da3613ac | ||
|
241637a980 | ||
|
9726d80e05 | ||
|
94e477e466 | ||
|
5bb245a33a | ||
|
6a235dc25f | ||
|
207d391fcd | ||
|
f44c127fbd | ||
|
c52ad67a7c | ||
|
35f9aef729 | ||
|
46fa12cb26 | ||
|
8ddd126378 | ||
|
ce07e8fe28 | ||
|
7af8c70bf9 | ||
|
3f151321f6 | ||
|
c2cf41baf9 | ||
|
9908209f58 | ||
|
6800d15872 | ||
|
b2c8f3ebc5 | ||
|
64661f54ea | ||
|
69252071ba | ||
|
9032e78349 | ||
|
702a7664de | ||
|
2ff9adecb2 | ||
|
4600f1d7ff | ||
|
79219ae201 | ||
|
87b9fca732 | ||
|
98cb23ca63 | ||
|
a50635bcd7 | ||
|
76c37d9cc0 | ||
|
c8b4eac618 | ||
|
f8af7adcd7 | ||
|
dd289ed0e1 | ||
|
3ed200d08a | ||
|
ff6d55aafc | ||
|
fa468e0673 | ||
|
f140c39063 | ||
|
51ef277e21 | ||
|
a7c1f6f021 | ||
|
ceb79f1897 | ||
|
3b4a5667ea | ||
|
bbe4927a20 | ||
|
ee428b9081 | ||
|
40bcec5044 | ||
|
a80aa89e09 | ||
|
660a22d647 | ||
|
494c30a239 | ||
|
71e7db63aa | ||
|
8aaa268423 | ||
|
a75746d610 | ||
|
045bd4dbda | ||
|
28cd3a3f8f | ||
|
f21216ecad | ||
|
abfe98ce8a | ||
|
988b4b4960 | ||
|
4937fa51c0 | ||
|
1b3d515777 | ||
|
b26f53125d | ||
|
844e84fc16 | ||
|
581d0dfc15 | ||
|
147a6df629 | ||
|
b3c1b46925 | ||
|
f4f805f4c9 | ||
|
fc57fa4064 | ||
|
0e077c6e42 | ||
|
a1f1ec6d65 | ||
|
ba94df47f0 | ||
|
454234ef5f | ||
|
e50b7a2719 | ||
|
5958687795 | ||
|
69cecb74df | ||
|
95138b1e5b | ||
|
efa571043b | ||
|
4990434db7 | ||
|
bbab8969d1 | ||
|
834e8d0d7d | ||
|
a7fdbbe35b | ||
|
6a4e175f86 | ||
|
a93a28230d | ||
|
701363347f | ||
|
a1a9438319 | ||
|
491a706610 | ||
|
963e93e8e8 | ||
|
c13285092c | ||
|
ccd8f1acc6 | ||
|
a31eacf1bd | ||
|
e15046d66c | ||
|
78a3c5d571 | ||
|
e6809acf63 | ||
|
c64005966f | ||
|
2a79339735 | ||
|
dd512ec36a | ||
|
e7dab06f82 | ||
|
94139513db | ||
|
7108c61bec | ||
|
772dbfae26 | ||
|
b30c3ff8d4 | ||
|
d5d38e94ef | ||
|
89893f9a24 | ||
|
079ed491a9 | ||
|
a622d5163b | ||
|
7df42c95d2 | ||
|
91c7209146 | ||
|
ade8626df7 | ||
|
3ece4a964f | ||
|
586a70ea1d | ||
|
bee14a6df7 | ||
|
0a5353532b | ||
|
1201f06a55 | ||
|
f82097b6b8 | ||
|
73d9aa29c4 | ||
|
85ee52128c | ||
|
a68f0fcb35 | ||
|
5e54db46c4 | ||
|
b654594adb | ||
|
b10a2d1fd5 | ||
|
216330a7e2 | ||
|
90e2e5a4ad | ||
|
7669a99c7f | ||
|
69c4dce477 | ||
|
db69d14995 | ||
|
6f749d61b1 | ||
|
24fc2e5146 | ||
|
10b75fd8b9 | ||
|
3e24b5a74b | ||
|
960cb7034a | ||
|
3fa74da2b5 | ||
|
5f2b7e3d57 | ||
|
d0ee56f25f | ||
|
1538e69f93 | ||
|
fa5ad1212e | ||
|
86adb94d7d | ||
|
9ed62eee58 | ||
|
c3da9b237b | ||
|
b0460de935 | ||
|
8dd125c8f3 | ||
|
5e38c800f6 | ||
|
920dbaf1e0 | ||
|
d8b931fbcf | ||
|
2c975fe48f | ||
|
d6ca5673dc | ||
|
a9ab865add | ||
|
c8c25ef6f7 | ||
|
6c0c7aac0f | ||
|
9e2b17e715 | ||
|
ab79dbd22a | ||
|
23af0c0209 | ||
|
bee93f28b3 | ||
|
d684e99d86 | ||
|
557ad9da1a | ||
|
ec0aaa72a3 | ||
|
ce7a9d5a3d | ||
|
0291726c09 | ||
|
c7679722fb | ||
|
8db9724c5d | ||
|
cddf70f46b | ||
|
4a3794ea2b | ||
|
44d5481828 | ||
|
629fe05083 | ||
|
d411d60685 | ||
|
2bfea938b3 | ||
|
96ec279663 | ||
|
697ad9d3a7 | ||
|
764b9abaf4 | ||
|
84ad8ec37a | ||
|
17318af62f | ||
|
b39a748984 | ||
|
b534aca263 | ||
|
adc9e7bf22 | ||
|
560b45dd16 | ||
|
bbffdde2dc | ||
|
063c50fce4 | ||
|
5429b6f189 | ||
|
d39fb653aa | ||
|
e08f00bfcd | ||
|
edf59e4f73 | ||
|
52e7394418 | ||
|
a982d4e524 | ||
|
458cfcb48c | ||
|
5bdf0aff81 | ||
|
1929b129ee | ||
|
ce23e95d0b | ||
|
684112474b | ||
|
fe296de42f | ||
|
996d998ebb | ||
|
125d039e3d | ||
|
6db2e69f9a | ||
|
82fd7fcf68 | ||
|
a2c3388e49 | ||
|
944ec75687 | ||
|
3b8b76328c | ||
|
e6c1d66c35 | ||
|
51eb94f251 | ||
|
7e76b42f11 | ||
|
23cb7f4e09 | ||
|
a04c0d2aa2 | ||
|
ad8d76b212 | ||
|
de8974d03e | ||
|
f8db5a7c6d | ||
|
e6bb7697f9 | ||
|
a3e1342bdb | ||
|
ba85107a85 | ||
|
0e392f91d2 | ||
|
685925398c | ||
|
ec6de55d3c | ||
|
00d1d237bc | ||
|
6de7c45618 | ||
|
004832f6ec | ||
|
82e92811e4 | ||
|
9a6316221c | ||
|
2d654ddcff | ||
|
5d2b57394e | ||
|
17ae2dbe4d | ||
|
a27b7ee6a5 | ||
|
5694c77d16 | ||
|
0c58509417 | ||
|
202fc67f93 | ||
|
b9cf1f1262 | ||
|
a8fddbb7d3 | ||
|
04406b191f | ||
|
290d065a79 | ||
|
3fab06941a | ||
|
f78d653b1e | ||
|
179da9241c | ||
|
7115176c0e | ||
|
fee7794789 | ||
|
5012616cb0 | ||
|
90a016c6e0 | ||
|
6617684a8d | ||
|
8afd373e4f | ||
|
3e75750ad6 | ||
|
17fd017d6f | ||
|
daa1487aef | ||
|
f023b7097f | ||
|
2c59385633 | ||
|
b30368f026 | ||
|
8ce331b563 | ||
|
dc91918c1f | ||
|
633d2ba8a4 | ||
|
bc4a66e9f7 | ||
|
7a36a8bdd8 | ||
|
d631c517b6 | ||
|
b773702a47 | ||
|
0eab97283f | ||
|
ad92a5f27d | ||
|
144672fada | ||
|
4f02d4b556 | ||
|
923e0187bd | ||
|
52d39b7260 | ||
|
81b27ea84a | ||
|
0d52f1ae7c | ||
|
0f98f0fd4a | ||
|
af80d9956b | ||
|
e29b4d35b3 | ||
|
77cf1f8685 | ||
|
11179a2a71 | ||
|
b2348e1de0 | ||
|
06cccbb646 | ||
|
c1a9ce3404 | ||
|
c569e87bd0 | ||
|
100eaf9137 | ||
|
ee42d2a570 | ||
|
564cac859a | ||
|
69b55ccc03 | ||
|
7ea67748fa | ||
|
9af3c502da | ||
|
ec7bf4767a | ||
|
1ce8d2ea6e | ||
|
f884bd2217 | ||
|
79a7aa70b9 | ||
|
c8daf483f3 | ||
|
166b79720c | ||
|
121e080697 | ||
|
280dfdd3f8 | ||
|
d85e86141c | ||
|
655822ec1a | ||
|
062180e9a8 | ||
|
9f2b9e1b46 | ||
|
ff63e5bd73 | ||
|
1dce501b70 | ||
|
ed585f8c04 | ||
|
b0a0769534 | ||
|
0b6269f607 | ||
|
ba781c53ef | ||
|
a76702cb36 | ||
|
5aba29006b | ||
|
9167de1631 | ||
|
afdc0c9dc8 | ||
|
db6ca6c5f8 | ||
|
fd5506b376 | ||
|
1b71caa1fe | ||
|
6d6a2efada | ||
|
2923b718e1 | ||
|
e3f4ae3038 | ||
|
d45956f55e | ||
|
f892b32335 | ||
|
df8b486c98 | ||
|
e02ebfe486 | ||
|
f281de7a3c | ||
|
d70b571769 | ||
|
ef6e2bd583 | ||
|
a0fa90ddd5 | ||
|
802005f571 | ||
|
4d0a5af475 | ||
|
c5225b2fa1 | ||
|
8c8ae71d65 | ||
|
3e7cd8a98b | ||
|
9823b294df | ||
|
c07c78c666 | ||
|
79a5ed0482 | ||
|
721b581376 | ||
|
3d115760a0 | ||
|
a8e2a47da8 | ||
|
f6792c3a05 | ||
|
bc4749d95a | ||
|
90eed12e97 | ||
|
2058ce69a4 | ||
|
4c4aa5534c | ||
|
dc6a7436ee | ||
|
35120caf80 | ||
|
9ace0811ce | ||
|
d4b0e1f588 | ||
|
18cf3641b1 | ||
|
01ead27dd9 | ||
|
b8e536d409 | ||
|
219508e478 | ||
|
75ceab8f51 | ||
|
5007fd7f71 | ||
|
50ff9e4fd0 | ||
|
7e0d6bdd87 | ||
|
9f8bee4bf1 | ||
|
b3e9ef3ad9 | ||
|
1077eb2061 | ||
|
d4f8e4a0dd | ||
|
35692c0b57 | ||
|
b9fb29d740 | ||
|
aed2b1031c | ||
|
68ca2c4962 | ||
|
ce73074d51 | ||
|
c3f4b7153b | ||
|
2eddc464d5 | ||
|
3d8e8cd80d | ||
|
9fee84f250 | ||
|
785ab7c072 | ||
|
73070395eb | ||
|
c6f2c8fc3d | ||
|
2a3376cb52 | ||
|
10dd7aacfe | ||
|
1b5504fb9e | ||
|
bfbb60bbed | ||
|
3a4aba0b31 | ||
|
1a915c7bf7 | ||
|
66305c676a | ||
|
8ffdfbfd97 | ||
|
5d88216f38 | ||
|
19c57c03cc | ||
|
a0f6b00a15 | ||
|
1e9d3e43cb | ||
|
dcd65f18f8 | ||
|
8bee9a6819 | ||
|
6284cc673d | ||
|
b3fc77efd6 | ||
|
35988b6191 | ||
|
dc8523c650 | ||
|
489ad486bc | ||
|
10738da2fb | ||
|
17996dee50 | ||
|
f6d554874b | ||
|
3d9a06591a | ||
|
d6f6241872 | ||
|
c86e778c76 | ||
|
217833dff7 | ||
|
1759388e3f | ||
|
9a1894f587 | ||
|
a879fc28a3 | ||
|
cc3b8dcfd6 | ||
|
53aac525d9 | ||
|
f8fc40c306 | ||
|
0f7634876f | ||
|
ef565adaa5 | ||
|
f9ed308aa8 | ||
|
685fa54daf | ||
|
160e7cf7ee | ||
|
934ff4a5eb | ||
|
2343e13c45 | ||
|
8c08897749 | ||
|
462c06d56b | ||
|
317559e5a5 | ||
|
4a1eb7f948 | ||
|
f3c04d0f37 | ||
|
3cecd5d066 | ||
|
7def17eed5 | ||
|
c362826dc6 | ||
|
0661002257 | ||
|
96c0fa983d | ||
|
6009e2b3ea | ||
|
07e335fdb8 | ||
|
e27eebe0f9 | ||
|
c53fa31a0a | ||
|
79282bfee0 | ||
|
ea0e2c47d5 | ||
|
57d2876021 | ||
|
485866552d | ||
|
b47e3ebccf | ||
|
46752af74b | ||
|
8f2a22b8c3 | ||
|
dc7e18ec73 | ||
|
0b0b6423ba | ||
|
4d394494b6 | ||
|
d7be99c9dd | ||
|
21c6079b7a | ||
|
1f0a1b8140 | ||
|
b82efcf0ce | ||
|
a61c9c6d89 | ||
|
992c6fbfb8 | ||
|
1c51fb80eb | ||
|
f2b21158d8 | ||
|
1a9c82483c | ||
|
1f667c4b35 | ||
|
d5e90a17f9 | ||
|
1caf1b3ebe | ||
|
c2b5a95961 | ||
|
ef528d6710 | ||
|
18fad16a7d | ||
|
7ba7fd5968 | ||
|
752409417f | ||
|
4591b3a4fa | ||
|
eb2a74f7e7 | ||
|
a25bd052d7 | ||
|
ccc2eb3298 | ||
|
3e7340c52c | ||
|
3f546df677 | ||
|
48d6375817 | ||
|
3f40fcb965 | ||
|
95172861f5 | ||
|
c62d88cb57 | ||
|
c74889f648 | ||
|
cb0169a784 | ||
|
7b3bbf05b9 | ||
|
f5ba2e825f | ||
|
5bb10260b3 | ||
|
47ebf7c84c | ||
|
c6bd5e6a2b | ||
|
a6ac90215b | ||
|
c01ad2bfcf | ||
|
50e8618b64 | ||
|
54c89e485a | ||
|
8e122d78be | ||
|
58a04a04e5 | ||
|
6900e50289 | ||
|
c42a853e0b | ||
|
1b02a5204a | ||
|
66b5cf29ba | ||
|
6a0f9d3cb2 | ||
|
11255058cf | ||
|
dfca3743f9 | ||
|
a798859a7a | ||
|
d4785ad6e3 | ||
|
965f8b9041 | ||
|
cbeac3e5f2 | ||
|
9bb586fb5a | ||
|
d8d78f61a7 | ||
|
73c085a461 | ||
|
662612d66f | ||
|
f19adcd1b3 | ||
|
b971ddec3a | ||
|
479f3b9343 | ||
|
12340a6bd0 | ||
|
0367a6175d | ||
|
db229b6f94 | ||
|
bd54fe03b9 | ||
|
f2380a2faa | ||
|
d3c7b6fb39 | ||
|
f59d557dce | ||
|
bedfee1fae | ||
|
bdbfc85243 | ||
|
2146e018f1 | ||
|
a32f59b256 | ||
|
9f06e0e017 | ||
|
b1d1aabbdd | ||
|
aebab8b68a | ||
|
d27c06ea7f | ||
|
80184b0d80 | ||
|
aa27249b88 | ||
|
3593a1b6b8 | ||
|
3b923a0183 | ||
|
3b630ec5dc | ||
|
c7e3e3e306 | ||
|
1dfd375738 | ||
|
3e3b8993aa | ||
|
0b154d69e7 | ||
|
c8959a2452 | ||
|
b5ead871ef | ||
|
5acde18ef1 | ||
|
b0c6dc5ab2 | ||
|
e4554892b0 | ||
|
e4075916f0 | ||
|
fb8fb9f0f7 | ||
|
ac8f510dac | ||
|
02230ca992 | ||
|
533b2144c5 | ||
|
eabb92f7b4 | ||
|
a568d43487 | ||
|
945aba6e10 | ||
|
09a1a37554 | ||
|
8d59d7029d | ||
|
ece64dc779 | ||
|
aef60b7ec1 | ||
|
8ecfc51799 | ||
|
1fa9fbb94b | ||
|
86df8c8a78 | ||
|
d1f4b108a0 | ||
|
ecd9e3be97 | ||
|
eb0e3c2898 | ||
|
9bc774dcd3 | ||
|
cb1a6a6a6b | ||
|
1e60bafcdc | ||
|
21e890602d | ||
|
6fc141733f | ||
|
060bc0be10 | ||
|
3dc8e9bb9c | ||
|
e464cc1ea6 | ||
|
52ffc6db10 | ||
|
9cff2f7b8a | ||
|
b3e87c3280 | ||
|
4b5afe3456 | ||
|
e2c424d607 | ||
|
8e87082e1d | ||
|
72106b0982 | ||
|
fed0f8b6b4 | ||
|
f860759758 | ||
|
15141897ae | ||
|
31ce4c2afa | ||
|
8e1cd4b1df | ||
|
442adee298 | ||
|
e11a17b408 | ||
|
e7aa24bd28 | ||
|
06ff6eb054 | ||
|
ce8b595ff2 | ||
|
46892daa3a | ||
|
e662efae61 | ||
|
530dbd85b2 | ||
|
0d1b40c9c1 | ||
|
c41ef65cc9 | ||
|
95dd0fcd9f | ||
|
2b51b35634 | ||
|
ddb0be6c0a | ||
|
2e07a7b2c1 | ||
|
7b96b0bd6d | ||
|
319783e873 | ||
|
4c0a836ca6 | ||
|
d45853f5fe | ||
|
9bf8f9c505 | ||
|
ccdfd4c65a | ||
|
394f1deade | ||
|
a3559548a8 | ||
|
c34f5d20ed | ||
|
03b933bc7a | ||
|
bf6eb9432e | ||
|
ea15abada5 | ||
|
622c55f254 | ||
|
d7a47eb5f9 | ||
|
a6ecc3cbc4 | ||
|
a1fac66587 | ||
|
9fffb3441c | ||
|
5f9f6c11b8 | ||
|
1916a6e339 | ||
|
b9f46f4ef7 | ||
|
18c317a787 | ||
|
8c6f4c3fc3 | ||
|
835659ac48 | ||
|
44c87bedfc | ||
|
98fd5cd429 | ||
|
ebd6a1ae95 | ||
|
9f5f2b6d74 | ||
|
e12d492d67 | ||
|
36c5722273 | ||
|
d201cfe6b4 | ||
|
6c4c373089 | ||
|
480b2fc7b6 | ||
|
f3c5c40104 | ||
|
76614b311e | ||
|
d61172598e | ||
|
3d35804a7d | ||
|
7ea1033a43 | ||
|
1597f38f45 | ||
|
b9fcd64a1f | ||
|
6fc5b32123 | ||
|
001d853f38 | ||
|
b4fbba5708 | ||
|
370b54251e | ||
|
95e8140555 | ||
|
3518646ad7 | ||
|
03f364a944 | ||
|
44e416e790 | ||
|
3e1c10628c | ||
|
531fbaf28c | ||
|
a94d2fee4e | ||
|
3cc97984bf | ||
|
74ba208a44 | ||
|
b4d3241e27 | ||
|
4500facb2b | ||
|
edfe340d09 | ||
|
b39b61e514 | ||
|
9afe41471b | ||
|
7fb3b97e73 | ||
|
48f8d0e0c3 | ||
|
ad7059156a | ||
|
9b51e7085b | ||
|
31f0c05ebc | ||
|
3c8ce7c866 | ||
|
69e29c3ef8 | ||
|
ef0de47954 | ||
|
32f1a5d2c8 | ||
|
62af1659eb | ||
|
dca9dd56d1 | ||
|
ba207cc04c | ||
|
496aededb1 | ||
|
5d9ad219cf | ||
|
99482a324e | ||
|
57102aea4a | ||
|
1d4c0bb388 | ||
|
de28df33ec | ||
|
a8d5504445 | ||
|
94a83ad969 | ||
|
06f53b1a28 | ||
|
8697fa59f3 | ||
|
1410840ef6 | ||
|
4c0a358e2b | ||
|
d5ba5a6e6a | ||
|
7d2b0e9638 | ||
|
b31e9b63eb | ||
|
81f3a6d186 | ||
|
00a9d2a9e3 | ||
|
e311dffcb3 | ||
|
0ba8455f6a | ||
|
dfad837f5b | ||
|
11450c11d1 | ||
|
dfa6d0c9ad | ||
|
f8f4ad8ee5 | ||
|
e695a5919d | ||
|
b311cd6163 | ||
|
73afc98699 | ||
|
150c6e21e7 | ||
|
c7ca5683b9 | ||
|
0f190026e8 | ||
|
ee7d45f492 | ||
|
b208c1a49f | ||
|
73c86127f7 | ||
|
bfbbe0c771 | ||
|
0962dfdd4d | ||
|
d12e6e15c9 | ||
|
d7f4e981a3 | ||
|
bec05f1bbb | ||
|
ab8cc64dfd | ||
|
a5029a510a | ||
|
3d62cb37f1 | ||
|
e0504ce482 | ||
|
12ffd83d4f | ||
|
8d4e395092 | ||
|
1d05cd28ee | ||
|
3ecae267ad | ||
|
3652a122ed | ||
|
d1def27dbb | ||
|
08200d4f77 | ||
|
7fc88cfe5b | ||
|
61b777f575 | ||
|
f440c3c614 | ||
|
127cc5215b | ||
|
4df6d1e028 | ||
|
47db74c699 | ||
|
7dd31ccf77 | ||
|
5887afae62 | ||
|
a01388ea7d | ||
|
57c0a09800 | ||
|
175623592b | ||
|
e149551744 | ||
|
cd543aad5e | ||
|
e8b5ad6625 | ||
|
2a4ea74a97 | ||
|
1861660585 | ||
|
c10d127fd7 | ||
|
d78997599a | ||
|
973122ed9b | ||
|
6dfdf69a8e | ||
|
c69ba2c734 | ||
|
87ff481abf | ||
|
6a248e2498 | ||
|
ca947d782c | ||
|
2f9db8972e | ||
|
3429e7d0cb | ||
|
30eac57199 | ||
|
5bb4e40c72 | ||
|
7bab7fc42e | ||
|
d6ffcbb8fc | ||
|
199ed6c31f | ||
|
5231279113 | ||
|
3436fa7d89 | ||
|
6df3c625b0 | ||
|
5ea710e317 | ||
|
88cfa53dc2 | ||
|
0d9144eeff | ||
|
f6197a965c | ||
|
4a063d3518 | ||
|
0da4626417 | ||
|
fa90d2d06e | ||
|
0616bb9468 | ||
|
9c2bc7f381 | ||
|
a474f20b84 | ||
|
aa8b9eb1ad | ||
|
a468d0b478 | ||
|
1c1ea1d0f7 | ||
|
101cb09e91 | ||
|
f69f2c2ece | ||
|
16ccaffc3f | ||
|
7a5a328c54 | ||
|
f06a59e3c7 | ||
|
ffba3429fb | ||
|
cf676443cb | ||
|
81cc4194dc | ||
|
428453a132 | ||
|
06101d48e4 | ||
|
d0efaa50d4 | ||
|
96126b435a | ||
|
10c7f4f838 | ||
|
6b0a522bb9 | ||
|
704ddf94f8 | ||
|
4f7113116d | ||
|
be6942d972 | ||
|
9eefe90d78 | ||
|
16e789419d | ||
|
7d4340469e | ||
|
a76ae11241 | ||
|
6ece523552 | ||
|
d6809ed331 | ||
|
4c05230cb3 | ||
|
3f3ed9b6f0 | ||
|
57c3d48711 | ||
|
debfe136a5 | ||
|
ae97ff7a80 | ||
|
63e5bc91de | ||
|
a395a20dba | ||
|
54c8801bec | ||
|
d8ae1cb3e9 | ||
|
cbb91c2026 | ||
|
99249c8fa3 | ||
|
f4d1ef4740 | ||
|
4d72c85f73 | ||
|
5134673461 | ||
|
5d1685b93d | ||
|
dcc511f4c3 | ||
|
e59d50ee5d | ||
|
2531a3695f | ||
|
985a177288 | ||
|
ecb83404ab | ||
|
8ac6bcdad7 | ||
|
4f873e1d9d | ||
|
7cc7e912e7 | ||
|
72f056a4d7 | ||
|
ac5cc49840 | ||
|
9a4e215179 | ||
|
9c8ddb3771 | ||
|
1e17b5f696 | ||
|
3fa771f51d | ||
|
4afe61060d | ||
|
0f4090402d | ||
|
cfdeaf4786 | ||
|
056779d3b8 | ||
|
6f5a20e76b | ||
|
a4c1e63637 | ||
|
cc7e1a3363 | ||
|
ee33b4e5cc | ||
|
0c59274c54 | ||
|
d98cc564b1 | ||
|
44a7154f58 | ||
|
106db76b9d | ||
|
cc8558025b | ||
|
9841240aab | ||
|
e2e4907b60 | ||
|
7e87c61d78 | ||
|
294870c5ba | ||
|
efecd160ca | ||
|
0fb089fbb7 | ||
|
682c43973e | ||
|
726d163631 | ||
|
7a5bb20778 | ||
|
caa44e82e0 | ||
|
41a01c08e1 | ||
|
8bc9d4b427 | ||
|
b8d238d76b | ||
|
0e3bb0e4f4 | ||
|
ec4cd0d258 | ||
|
793547a132 | ||
|
5377835f1e | ||
|
2d96b2a3ec | ||
|
36d02d010e | ||
|
18b9473cf8 | ||
|
d97e032fcf | ||
|
7ef051f58a | ||
|
ab64706cc3 | ||
|
2189dd4b85 | ||
|
861987e13e | ||
|
9edae7fa0a | ||
|
cf293bc669 | ||
|
7d14fdf530 | ||
|
9bda8f61f4 | ||
|
614fcb12f5 | ||
|
ae09831227 | ||
|
e146fd121c | ||
|
0ab15e9f22 | ||
|
a168c5efbe | ||
|
c1734d1b27 | ||
|
c750828632 | ||
|
a2f63aae33 | ||
|
908f6ded8a | ||
|
e08e4a9ce0 | ||
|
a421d9a33b | ||
|
6c076f99f6 | ||
|
467a4740da | ||
|
654eceb33b | ||
|
0d839bd138 | ||
|
558a091c08 | ||
|
14593ce789 | ||
|
359ba5f728 | ||
|
8331a2982d | ||
|
38a664ed72 | ||
|
3c212c8389 | ||
|
dce7a0c72b | ||
|
c7280fca52 | ||
|
686394654f | ||
|
29db4a44ed | ||
|
2f356f12e6 | ||
|
f4c3080824 | ||
|
1182ab55c5 | ||
|
2b1eaa6df3 | ||
|
5a5cb74db2 | ||
|
0c673dfebb | ||
|
12d87fba1b | ||
|
0920cb6ec4 | ||
|
0626bbef8e | ||
|
d8254cede0 | ||
|
17951ac92c | ||
|
d47da25b82 | ||
|
26d43e650f | ||
|
a170154927 | ||
|
2cf4b4e56d | ||
|
4d5153854b | ||
|
819ed10f29 | ||
|
5bb9351a3f | ||
|
2637f6f824 | ||
|
f698e796d2 | ||
|
3538b505da | ||
|
0c4806b4a0 | ||
|
d750d17be5 | ||
|
5a013c5b89 | ||
|
d9282ed988 | ||
|
af3ba03a5b | ||
|
46374e94ca | ||
|
048ef3e796 | ||
|
921877e8a4 | ||
|
755ee5462f | ||
|
432a29e4d9 | ||
|
d961cfb855 | ||
|
64ccc88a9e | ||
|
8bdd060112 | ||
|
d700bb66b2 | ||
|
842b0a1271 | ||
|
33be9d4559 | ||
|
fda4f4d027 | ||
|
3d67b29a7b | ||
|
73bc4cc3e4 | ||
|
c0eca32b92 | ||
|
3567abbd64 | ||
|
82f37c87fc | ||
|
ded1ab3da1 | ||
|
2ac2827256 | ||
|
e37adb8c47 | ||
|
14e954284e | ||
|
898e00f5b4 | ||
|
9315577be6 | ||
|
47baca22d9 | ||
|
dae1291b37 | ||
|
77d454725a | ||
|
2e0216b7c6 | ||
|
40b2a26e89 | ||
|
3f88b5fa14 | ||
|
8f34e9fa37 | ||
|
2ddb49f546 | ||
|
d6e7d8ca75 | ||
|
cb12460b95 | ||
|
3688dab048 | ||
|
a6f51264fd | ||
|
e2f9aa5027 | ||
|
e4b8df2dc6 | ||
|
6935561b41 | ||
|
f58b4a6cd9 | ||
|
f1fa8f6055 | ||
|
126b0fe324 | ||
|
566dda6ad7 | ||
|
a7724bffaa | ||
|
dbb7a87fd8 | ||
|
cfa7119fdb | ||
|
ba25970f27 | ||
|
fb30f11bc1 | ||
|
03c079cb8c | ||
|
a60d0182db | ||
|
c702970a0e | ||
|
ebb7cb2ae3 | ||
|
c6e7e80f23 | ||
|
4187332bb1 | ||
|
b1e0687373 | ||
|
8624af879a | ||
|
517b6fed81 | ||
|
24752b5fd1 | ||
|
5cfd97c344 | ||
|
24f3098418 | ||
|
babdebee79 | ||
|
3f8f2b3f48 | ||
|
d4483bfda6 | ||
|
93dbfa18f1 | ||
|
1cca992a8e | ||
|
3d9760473b | ||
|
00fc3a5686 | ||
|
b42328dbc6 | ||
|
24161543d9 | ||
|
1f867e3920 | ||
|
1ac110d426 | ||
|
56568d24ff | ||
|
de3d8747f7 | ||
|
9bf6b2e1bd | ||
|
c3a867f0c2 | ||
|
f832b86dcd | ||
|
33c7707f56 | ||
|
728a8e975a | ||
|
365fe400b0 | ||
|
b32bd22af3 | ||
|
a2504f6455 | ||
|
700628b2cb | ||
|
14889897da | ||
|
456e80a7d5 | ||
|
5779fea9b4 | ||
|
af5b552a7f | ||
|
47f7611ec9 | ||
|
aee7bf0de0 | ||
|
1172e2b8cc | ||
|
a7c3ef3e22 | ||
|
d7de5cb5ff | ||
|
710f580e15 | ||
|
35ba2dcaf9 | ||
|
307746dc35 | ||
|
fcdff3180a | ||
|
dc691c8a6e | ||
|
da927b5d41 | ||
|
2b468cb0ee | ||
|
c3dfe2c61c | ||
|
55dc45ec3e | ||
|
2d66431af4 | ||
|
f811a4e876 | ||
|
fa155f8a42 | ||
|
0a57c408c0 | ||
|
bd12429cd0 | ||
|
6a93b72ea5 | ||
|
d3568627e9 | ||
|
6a60368a1b | ||
|
1ac913877e | ||
|
63928e231c | ||
|
435dee935b | ||
|
3ef30e850d | ||
|
cff74493a7 | ||
|
fb5a65c51a | ||
|
46c2fe2443 | ||
|
890ca3c782 | ||
|
ee7051c5a4 | ||
|
275b6f777a | ||
|
3c9283cc41 | ||
|
2967dba7ad | ||
|
4f06daf7d0 | ||
|
c91b457054 | ||
|
b8c61f2f88 | ||
|
67bc99223d | ||
|
eabe23cc24 | ||
|
88a6437840 | ||
|
7998a98818 | ||
|
2382fdee50 | ||
|
1731a29c51 | ||
|
84fcd95d4e | ||
|
95965e9ff6 | ||
|
e72d141ec4 | ||
|
3e6c98d65d | ||
|
041f8a86d7 | ||
|
2164afb8cf | ||
|
ac0ca3de81 | ||
|
a707440e52 | ||
|
aec2284f45 | ||
|
fe3d8e44e6 | ||
|
da49a40b96 | ||
|
55117912ab | ||
|
d51a6ab3db | ||
|
5bc815c63f | ||
|
4580dcf1ea | ||
|
e0ea101838 | ||
|
f598fbeaea | ||
|
3b27107676 | ||
|
c3964cf29d | ||
|
d35d953a91 | ||
|
6951f3dfcc | ||
|
4224ac5ca0 | ||
|
d18656c2dc | ||
|
6bc29a1601 | ||
|
13003bf6af | ||
|
9d54ea6b0c | ||
|
aef7ff87fc | ||
|
77639bb21d | ||
|
eb952f1199 | ||
|
96ddc217da | ||
|
e8cd9411b0 | ||
|
7cf0ba5aa8 | ||
|
b38b3b08bd | ||
|
2c2bfab8bc | ||
|
26a80e0868 | ||
|
949cd9bb06 | ||
|
d858237010 | ||
|
1f070b740f | ||
|
0fe71af4ce | ||
|
7efc3a4c21 | ||
|
8459895fdd | ||
|
b4e38a8fed | ||
|
fa401b6f56 | ||
|
7d2a2f2ade | ||
|
322fbaf389 | ||
|
9ba655e74c | ||
|
313e442107 | ||
|
ed11fe130b | ||
|
7753e19ba8 | ||
|
88fee02228 | ||
|
43cf6e7cba | ||
|
48ba6a6189 | ||
|
06ea71d5be | ||
|
c9e3c29a25 | ||
|
3c003bc168 | ||
|
0be55824d4 | ||
|
0e40ef172a | ||
|
bf53f82d16 | ||
|
f78ab9061b | ||
|
36a90bb866 | ||
|
c7a62970a6 | ||
|
e1f0e40341 | ||
|
0bbc8a3350 | ||
|
e38bdecd21 | ||
|
5375400e85 | ||
|
1d3fdea432 | ||
|
8d86d7d1c1 | ||
|
93341dd009 | ||
|
a6547a15f3 | ||
|
8dc6696957 | ||
|
ccbccad994 | ||
|
712be84bba | ||
|
68c4070f62 | ||
|
0988b731b7 | ||
|
b595ec03f8 | ||
|
98b6772db9 | ||
|
4f9c7861ec | ||
|
a985a5cab1 | ||
|
d72cb42b08 | ||
|
db577fdf17 | ||
|
34063108a6 | ||
|
4319922b3c | ||
|
6b9eff19f1 | ||
|
b85441d6af | ||
|
d5cfe74d5d |
200 changed files with 27582 additions and 17515 deletions
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
*.o
|
||||
*.d
|
||||
*.orig
|
||||
*.rej
|
||||
*.patch
|
||||
*.diff
|
||||
*.exe
|
||||
|
||||
gmqcc
|
||||
gmqpak
|
||||
qcvm
|
||||
testsuite
|
||||
|
||||
build/
|
||||
.idea/
|
13
AUTHORS
13
AUTHORS
|
@ -1,3 +1,10 @@
|
|||
GMQCC brought to you by:
|
||||
Dale Weiler
|
||||
Wolfgang Bumiller
|
||||
Authors:
|
||||
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
|
||||
|
|
35
CMakeLists.txt
Normal file
35
CMakeLists.txt
Normal 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)
|
39
INSTALL
39
INSTALL
|
@ -1,39 +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 an ArchLinux PKGBUILD file:
|
||||
|
||||
make DESTDIR=$pkgdir install
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (C) 2012
|
||||
Copyright (C) 2012, 2013, 2014, 2015
|
||||
Dale Weiler
|
||||
Wolfgang Bumiller
|
||||
|
||||
|
|
276
Makefile
276
Makefile
|
@ -1,104 +1,204 @@
|
|||
DESTDIR :=
|
||||
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
|
||||
CFLAGS += -Wall -Wextra -I. -pedantic-errors
|
||||
#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
|
||||
endif
|
||||
ifeq ($(track), no)
|
||||
CFLAGS += -DNOTRACK
|
||||
endif
|
||||
|
||||
OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o
|
||||
OBJ_T = test.o util.o conout.o
|
||||
OBJ_C = main.o lexer.o parser.o
|
||||
OBJ_X = exec-standalone.o util.o conout.o
|
||||
|
||||
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
|
||||
# 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
|
||||
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
|
||||
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
|
||||
QCVM = qcvm
|
||||
GMQCC = gmqcc
|
||||
TESTSUITE = testsuite
|
||||
endif
|
||||
# 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
|
||||
CXXFLAGS += -fomit-frame-pointer
|
||||
endif
|
||||
|
||||
# Highest optimization flag in release builds.
|
||||
CXXFLAGS += -O3
|
||||
endif
|
||||
|
||||
#standard rules
|
||||
default: all
|
||||
%.o: %.c
|
||||
$(CC) -c $< -o $@ $(CFLAGS)
|
||||
# Sanitizer selection
|
||||
ifeq ($(ASAN),1)
|
||||
CXXFLAGS += -fsanitize=address
|
||||
endif
|
||||
ifeq ($(UBSAN),1)
|
||||
CXXFLAGS += -fsanitize=undefined
|
||||
endif
|
||||
|
||||
exec-standalone.o: exec.c
|
||||
$(CC) -c $< -o $@ $(CFLAGS) -DQCVM_EXECUTOR=1
|
||||
#
|
||||
# Dependency flags
|
||||
#
|
||||
DEPFLAGS := -MMD
|
||||
DEPFLAGS += -MP
|
||||
|
||||
$(QCVM): $(OBJ_X)
|
||||
$(CC) -o $@ $^ $(CFLAGS) -lm
|
||||
#
|
||||
# Linker flags
|
||||
#
|
||||
LDFLAGS :=
|
||||
|
||||
$(GMQCC): $(OBJ_C) $(OBJ_D)
|
||||
$(CC) -o $@ $^ $(CFLAGS)
|
||||
# Remove unreferenced sections
|
||||
ifeq ($(UNUSED),1)
|
||||
LDFLAGS += -Wl,--gc-sections
|
||||
endif
|
||||
|
||||
$(TESTSUITE): $(OBJ_T)
|
||||
$(CC) -o $@ $^ $(CFLAGS)
|
||||
# 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
|
||||
STRIP := strip
|
||||
endif
|
||||
|
||||
all: $(GMQCC) $(QCVM) $(TESTSUITE)
|
||||
|
||||
check: all
|
||||
@ ./$(TESTSUITE)
|
||||
# Build artifact directories.
|
||||
$(DEPDIR):
|
||||
@mkdir -p $(DEPDIR)
|
||||
$(OBJDIR):
|
||||
@mkdir -p $(OBJDIR)
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp $(DEPDIR)/%.d | $(OBJDIR) $(DEPDIR)
|
||||
$(CXX) -MT $@ $(DEPFLAGS) -MF $(DEPDIR)/$*.Td $(CXXFLAGS) -c -o $@ $<
|
||||
@mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d
|
||||
|
||||
$(GMQCC): $(filter %.o,$(GSRCS:%.cpp=$(OBJDIR)/%.o))
|
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
$(STRIP) $@
|
||||
|
||||
$(QCVM): $(filter %.o,$(QSRCS:%.cpp=$(OBJDIR)/%.o))
|
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
$(STRIP) $@
|
||||
|
||||
$(TESTSUITE): $(filter %.o,$(TSRCS:%.cpp=$(OBJDIR)/%.o))
|
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
$(STRIP) $@
|
||||
|
||||
# Determine if the tests should be run.
|
||||
RUNTESTS := true
|
||||
ifdef TESTSUITE
|
||||
RUNTESTS := ./$(TESTSUITE)
|
||||
endif
|
||||
|
||||
test: $(QCVM) $(TESTSUITE)
|
||||
@$(RUNTESTS)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) *.dat
|
||||
rm -rf $(DEPDIR) $(OBJDIR)
|
||||
|
||||
# deps
|
||||
$(OBJ_D) $(OBJ_C) $(OBJ_X): gmqcc.h opts.def
|
||||
main.o: lexer.h
|
||||
parser.o: ast.h lexer.h
|
||||
ast.o: ast.h ir.h
|
||||
ir.o: ir.h
|
||||
.PHONY: test clean $(DEPDIR) $(OBJDIR)
|
||||
|
||||
#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 -m755 doc/gmqcc.1 $(DESTDIR)$(MANDIR)/man1/
|
||||
install -m755 doc/qcvm.1 $(DESTDIR)$(MANDIR)/man1/
|
||||
# Dependencies
|
||||
$(filter %.d,$(GSRCS:%.cpp=$(DEPDIR)/%.d)):
|
||||
include $(wildcard $@)
|
||||
|
||||
$(filter %.d,$(QSRCS:%.cpp=$(DEPDIR)/%.d)):
|
||||
include $(wildcard $@)
|
||||
|
||||
$(filter %.d,$(TSRCS:%.cpp=$(DEPDIR)/%.d)):
|
||||
include $(wildcard $@)
|
||||
|
|
10
README
10
README
|
@ -1,9 +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 documentation:
|
||||
See the manpages, or visit the documentation online at
|
||||
http://graphitemaster.github.com/gmqcc/doc.html
|
||||
An improved QuakeC compiler
|
||||
|
|
157
TODO
157
TODO
|
@ -1,157 +0,0 @@
|
|||
GMQCC is quite feature compleat. 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 determinging which values are computed by equivalent expressions.
|
||||
Simaler to Common Subexpression Elimination (CSE), however expressions
|
||||
are determined via underlying equivalnce, opposed to lexically identical
|
||||
expressions (CSE).
|
||||
|
||||
Spare Conditional Constant Propogation:
|
||||
Simultaneously remove dead code and propogates constants. This is
|
||||
not the same as indivial dead code elimination and constant propogation
|
||||
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 Recrusion:
|
||||
Tail recrusive 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 subsitution.
|
||||
|
||||
Classes:
|
||||
Like C++, but minus the stupidity:
|
||||
- No type operator overloads
|
||||
- Keep operator overloading for basic operators though.
|
||||
- No inheritence
|
||||
- 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 Subsitution:
|
||||
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 abilit 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 dissasembly:
|
||||
Proper dissasembly of compiled .dat files. Annotated if possible
|
||||
when -g (is used during compilation)
|
||||
|
||||
Debugging:
|
||||
A step-through debuger -d (with seperate compilation as well)
|
||||
Called -> qcdb Optionally alias to qcvm -d :)
|
||||
|
||||
We should beable to see the assembly and source it matches to
|
||||
and the state of OFS_* and calls.
|
||||
|
||||
Testsuite:
|
||||
The followiung 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 paramaters 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
|
||||
entierly sure if it makes sense.
|
||||
|
||||
|
18
algo.h
Normal file
18
algo.h
Normal 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
|
246
code.c
246
code.c
|
@ -1,246 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Wolfgang Bumiller
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#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;
|
||||
uint32_t code_entfields;
|
||||
|
||||
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}};
|
||||
prog_section_statement empty_statement = {0,{0},{0},{0}};
|
||||
prog_section_def empty_def = {0, 0, 0};
|
||||
int i = 0;
|
||||
|
||||
code_entfields = 0;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
uint32_t code_genstring(const char *str)
|
||||
{
|
||||
uint32_t off = vec_size(code_chars);
|
||||
while (*str) {
|
||||
vec_push(code_chars, *str);
|
||||
++str;
|
||||
}
|
||||
vec_push(code_chars, 0);
|
||||
return off;
|
||||
}
|
||||
|
||||
uint32_t code_cachedstring(const char *str)
|
||||
{
|
||||
size_t s = 0;
|
||||
/* We could implement knuth-morris-pratt or something
|
||||
* and also take substrings, but I'm uncomfortable with
|
||||
* pointing to subparts of strings for the sake of clarity...
|
||||
*/
|
||||
while (s < vec_size(code_chars)) {
|
||||
if (!strcmp(str, code_chars + s))
|
||||
return s;
|
||||
while (code_chars[s]) ++s;
|
||||
++s;
|
||||
}
|
||||
return code_genstring(str);
|
||||
}
|
||||
|
||||
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.forcecrc)
|
||||
code_header.crc16 = opts.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 */
|
||||
}
|
||||
|
||||
if (lnofile) {
|
||||
uint32_t lnotype = *(unsigned int*)"LNOF";
|
||||
uint32_t version = 1;
|
||||
|
||||
fp = util_fopen(lnofile, "wb");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
if (fwrite(&lnotype, sizeof(lnotype), 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, sizeof(code_linenums[0]), vec_size(code_linenums), fp) != vec_size(code_linenums))
|
||||
{
|
||||
con_err("failed to write lno file\n");
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
|
||||
/* ensure all data is in LE format */
|
||||
util_endianswap(&code_header, 1, sizeof(prog_header));
|
||||
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));
|
||||
|
||||
fp = util_fopen(filename, "wb");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
if (1 != fwrite(&code_header, sizeof(prog_header) , 1 , fp) ||
|
||||
vec_size(code_statements) != fwrite(code_statements, sizeof(prog_section_statement), vec_size(code_statements), fp) ||
|
||||
vec_size(code_defs) != fwrite(code_defs, sizeof(prog_section_def) , vec_size(code_defs) , fp) ||
|
||||
vec_size(code_fields) != fwrite(code_fields, sizeof(prog_section_field) , vec_size(code_fields) , fp) ||
|
||||
vec_size(code_functions) != fwrite(code_functions, sizeof(prog_section_function) , vec_size(code_functions) , fp) ||
|
||||
vec_size(code_globals) != fwrite(code_globals, sizeof(int32_t) , vec_size(code_globals) , fp) ||
|
||||
vec_size(code_chars) != fwrite(code_chars, 1 , vec_size(code_chars) , fp))
|
||||
{
|
||||
fclose(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_defs);
|
||||
vec_free(code_fields);
|
||||
vec_free(code_functions);
|
||||
vec_free(code_globals);
|
||||
vec_free(code_chars);
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
348
code.cpp
Normal file
348
code.cpp
Normal 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;
|
||||
}
|
422
conout.c
422
conout.c
|
@ -1,422 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* 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 _MSC_VER
|
||||
#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
|
||||
};
|
||||
|
||||
enum {
|
||||
WBLACK,
|
||||
WBLUE,
|
||||
WGREEN = 2,
|
||||
WRED = 4,
|
||||
WINTENSE = 8,
|
||||
WCYAN = WBLUE | WGREEN,
|
||||
WMAGENTA = WBLUE | WRED,
|
||||
WYELLOW = WGREEN | WRED,
|
||||
WWHITE = WBLUE | WGREEN | WRED
|
||||
}
|
||||
|
||||
static const ansi2win[] = {
|
||||
WBLACK,
|
||||
WRED,
|
||||
WGREEN,
|
||||
WYELLOW,
|
||||
WBLUE,
|
||||
WMAGENTA,
|
||||
WCYAN,
|
||||
WWHITE
|
||||
};
|
||||
|
||||
static void win_fputs(char *str, FILE *h) {
|
||||
/* state for translate */
|
||||
int acolor;
|
||||
int wcolor;
|
||||
int icolor;
|
||||
|
||||
int state;
|
||||
int place;
|
||||
|
||||
/* attributes */
|
||||
int intense = -1;
|
||||
int colors[] = {-1, -1 };
|
||||
int colorpos = 1;
|
||||
|
||||
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 == '\e')
|
||||
state = '\e';
|
||||
else if (state == '\e' && *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 (
|
||||
(h == stdout) ?
|
||||
GetStdHandle(STD_OUTPUT_HANDLE) :
|
||||
GetStdHandle(STD_ERROR_HANDLE),
|
||||
|
||||
wcolor | intense | (icolor & 0xF0)
|
||||
);
|
||||
colorpos = 1;
|
||||
state = -1;
|
||||
}
|
||||
} else {
|
||||
fputc(*str, h);
|
||||
}
|
||||
}
|
||||
/* restore */
|
||||
SetConsoleTextAttribute(
|
||||
(GMQCC_IS_STDOUT(h)) ?
|
||||
GetStdHandle(STD_OUTPUT_HANDLE) :
|
||||
GetStdHandle(STD_ERROR_HANDLE),
|
||||
icolor
|
||||
);
|
||||
}
|
||||
#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 _MSC_VER
|
||||
ln = vfprintf(handle, fmt, va);
|
||||
#else
|
||||
{
|
||||
char *data = NULL;
|
||||
ln = _vscprintf(fmt, va);
|
||||
data = malloc(ln + 1);
|
||||
data[ln] = 0;
|
||||
vsprintf(data, fmt, va);
|
||||
if (GMQCC_IS_DEFINE(handle))
|
||||
ln = win_fputs(data, handle);
|
||||
else
|
||||
ln = fputs(data, handle);
|
||||
free(data);
|
||||
}
|
||||
#endif
|
||||
return ln;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* 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 ();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (GMQCC_IS_DEFINE(out)) {
|
||||
console.handle_out = GMQCC_IS_STDOUT(out) ? stdout : stderr;
|
||||
con_enablecolor();
|
||||
} else if (!(console.handle_out = fopen(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 = fopen(err, "w"))) return 0;
|
||||
|
||||
/* no buffering */
|
||||
setvbuf(console.handle_out, NULL, _IONBF, 0);
|
||||
setvbuf(console.handle_err, NULL, _IONBF, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (OPTS_WERROR(warntype)) {
|
||||
++compile_errors;
|
||||
lvl = LVL_ERROR;
|
||||
}
|
||||
else
|
||||
++compile_warnings;
|
||||
|
||||
con_vprintmsg_c(lvl, ctx.file, ctx.line, ((lvl == LVL_ERROR) ? "error" : "warning"), fmt, ap, warn_name);
|
||||
|
||||
return OPTS_WERROR(warntype);
|
||||
}
|
||||
|
||||
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
226
conout.cpp
Normal 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;
|
||||
}
|
856
doc/gmqcc.1
856
doc/gmqcc.1
|
@ -1,318 +1,745 @@
|
|||
.\" Process with groff -man -Tascii file.3
|
||||
.TH GMQCC 1 2012-07-12 "" "gmqcc Manual"
|
||||
.SH NAME
|
||||
gmqcc \- A Quake C compiler built from the NIH realm of sarcastic wit
|
||||
.SH SYNOPSIS
|
||||
.B gmqcc
|
||||
[\fIOPTIONS\fR] [\fIfiles...\fR]
|
||||
.SH DESCRIPTION
|
||||
Traditionally, a QC compiler reads the file \fIprogs.src\fR which
|
||||
in its first line contains the output filename, and the rest is a
|
||||
.\"mdoc
|
||||
.Dd January 24, 2013
|
||||
.Dt GMQCC 1 PRM
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm gmqcc
|
||||
.Nd A Quake C compiler built from the NIH realm of sarcastic wit
|
||||
.Sh SYNOPSIS
|
||||
.Nm gmqcc
|
||||
.Op Cm options
|
||||
.Op Ar files...
|
||||
.Sh DESCRIPTION
|
||||
Traditionally, a QC compiler reads the file
|
||||
.Pa progs.src
|
||||
which in its first line contains the output filename, and the rest is a
|
||||
list of QC source files that are to be compiled in order.
|
||||
\fBgmqcc\fR optionally takes options to specify the output and
|
||||
.Nm gmqcc
|
||||
optionally takes options to specify the output and
|
||||
input files on the commandline, and also accepts assembly files.
|
||||
.SH OPTIONS
|
||||
\fBgmqcc\fR mostly tries to mimick gcc's commandline handling, though
|
||||
.Sh OPTIONS
|
||||
.Nm gmqcc
|
||||
mostly tries to mimic gcc's commandline handling, though
|
||||
there are also traditional long-options available.
|
||||
.TP
|
||||
.B "-h, --help"
|
||||
.Bl -tag -width Ds
|
||||
.It Fl h , Fl -help
|
||||
Show a usage message and exit.
|
||||
.TP
|
||||
.B "-debug"
|
||||
Turn on some compiler debugging mechanisms.
|
||||
.TP
|
||||
.B "-memchk"
|
||||
Turn on compiler mem-check. (Shows allocations and checks for leaks.)
|
||||
.TP
|
||||
.BI "-o, --output=" filename
|
||||
.It Fl o , Fl -output= Ns Ar filename
|
||||
Specify the output filename. Defaults to progs.dat. This will overwrite
|
||||
the output file listed in a \fIprogs.src\fR file in case such a file is used.
|
||||
.TP
|
||||
.BI "-O" number
|
||||
the output file listed in a
|
||||
.Pa progs.src
|
||||
file in case such a file is used.
|
||||
.Bl -tag -width indent
|
||||
.It Fl O Ns Ar number
|
||||
Specify the optimization level
|
||||
.RS
|
||||
.IP 3
|
||||
.It Ar 3
|
||||
Highest optimization level
|
||||
.IP 2
|
||||
.It Ar 2
|
||||
Default optimization level
|
||||
.IP 1
|
||||
.It Ar 1
|
||||
Minimal optimization level
|
||||
.IP 0
|
||||
.It Ar 0
|
||||
Disable optimization entirely
|
||||
.RE
|
||||
.TP
|
||||
.BI "-O" name "\fR, " "" -Ono- name
|
||||
.El
|
||||
.Pp
|
||||
.It Fl O Ns Ar name , Fl Ono- Ns Ar name
|
||||
Enable or disable a specific optimization. Note that these options
|
||||
must be used after setting the optimization level, otherwise they'll
|
||||
be overwritten.
|
||||
.TP
|
||||
.B -Ohelp
|
||||
.It Fl O Ns Cm help
|
||||
List all possible optimizations and the optimization level they're
|
||||
activated at.
|
||||
.TP
|
||||
.BI -W warning "\fR, " "" -Wno- warning
|
||||
.It Fl q , Fl -quiet
|
||||
Be less verbose. In particular removes the messages about which files
|
||||
are being processed, and which compilation mode is being used, and
|
||||
some others. Warnings and errors will of course still be displayed.
|
||||
.It Fl D Ns Ar macroname , Fl D Ns Ar macroname Ns = Ns Ar value
|
||||
Predefine a macro, optionally with a optional value.
|
||||
.It Fl E
|
||||
Run only the preprocessor as if
|
||||
.Fl f Ns Cm ftepp
|
||||
was used and print the preprocessed code to stdout.
|
||||
.It Fl W Ns Ar warning , Fl Wno- Ns Ar warning
|
||||
Enable or disable a warning.
|
||||
.TP
|
||||
.B -Wall
|
||||
Enable all warnings. Overrides preceding -W parameters.
|
||||
.TP
|
||||
.BR -Werror ", " -Wno-error
|
||||
.It Fl W Ns Cm all
|
||||
Enable almost all warnings. Overrides preceding
|
||||
.Fl W
|
||||
parameters.
|
||||
.Pp
|
||||
The following warnings will
|
||||
.Em not
|
||||
be enabled:
|
||||
.Bl -tag -width indent -offset indent
|
||||
.It Fl W Ns Cm uninitialized-global
|
||||
.El
|
||||
.It Fl W Ns Cm error , Fl Wno- Ns Cm error
|
||||
Controls whether or not all warnings should be treated as errors.
|
||||
.TP
|
||||
.BI -Werror- warning "\fR, " "" -Wno-error- warning
|
||||
.It Fl Werror- Ns Ar warning , Fl Wno-error- Ns Ar warning
|
||||
Controls whether a specific warning should be an error.
|
||||
.TP
|
||||
.B -Whelp
|
||||
.It Fl W Ns Cm help
|
||||
List all possible warn flags.
|
||||
.TP
|
||||
.BI -f flag "\fR, " "" -fno- flag
|
||||
.It Fl f Ns Ar flag , Fl fno- Ns Ar flag
|
||||
Enable or disable a specific compile flag. See the list of flags
|
||||
below.
|
||||
.TP
|
||||
.B -fhelp
|
||||
.It Fl f Ns Cm help
|
||||
List all possible compile flags.
|
||||
.TP
|
||||
.B -nocolor
|
||||
.It Fl nocolor
|
||||
Disables colored output
|
||||
.TP
|
||||
.BI -config= file
|
||||
Use an ini file to read all the -O, -W and -f flag from. See the
|
||||
CONFIG section about the file format.
|
||||
.TP
|
||||
.BI "-redirout=" file
|
||||
Redirects standard output to a \fIfile\fR
|
||||
.TP
|
||||
.BI "-redirerr=" file
|
||||
Redirects standard error to a \fIfile\fR
|
||||
.TP
|
||||
.BI "-std=" standard
|
||||
.It Fl config= Ns Ar file
|
||||
Use an ini file to read all the
|
||||
.Fl O , Fl W
|
||||
and
|
||||
.Fl f
|
||||
flag from. See the
|
||||
.It Fl "debug"
|
||||
Turn on some compiler debugging mechanisms.
|
||||
.It Fl memchk
|
||||
Turn on compiler mem-check. (Shows allocations and checks for leaks.)
|
||||
.It Fl -memdumpcols Ns Ar columns
|
||||
Changes the number of columns to use for the debug memory dump, defaults to 16.
|
||||
.Sx CONFIG
|
||||
section about the file format.
|
||||
.It Fl redirout= Ns Ar file
|
||||
Redirects standard output to a
|
||||
.Ar file
|
||||
.It Fl redirerr= Ns Ar file
|
||||
Redirects standard error to a
|
||||
.Ar file
|
||||
.It Fl std= Ns Ar standard
|
||||
Use the specified standard for parsing QC code. The following standards
|
||||
are available:
|
||||
.IR gmqcc , qcc , fteqcc
|
||||
Selecting a standard also implies some -f options and behaves as if
|
||||
those options have been written right after the -std option, meaning
|
||||
if you changed them before the -std option, you're now overwriting
|
||||
them.
|
||||
.sp
|
||||
.BR -std=gmqcc " includes:"
|
||||
.in +4
|
||||
-fadjust-vector-fields
|
||||
.in
|
||||
.BR -std=qcc " includes:"
|
||||
.in +4
|
||||
.nf
|
||||
-fassign-function-types
|
||||
-f\fIno-\fRadjust-vector-fields
|
||||
.fi
|
||||
.in
|
||||
.BR -std=fteqcc " includes:"
|
||||
.in +4
|
||||
.nf
|
||||
-fftepp
|
||||
-ftranslatable-strings
|
||||
-fassign-function-types
|
||||
-Wternary-precedence
|
||||
-f\fIno-\fRadjust-vector-fields
|
||||
-f\fIno-\fRcorrect-ternary
|
||||
.fi
|
||||
.in
|
||||
.SH Warnings
|
||||
.TP
|
||||
.B -Wunused-variable
|
||||
.Ar gmqcc , Ar qcc , Ar fteqcc
|
||||
Selecting a standard also implies some
|
||||
.Fl f
|
||||
options and behaves as if
|
||||
those options have been written right after the
|
||||
.Fl std
|
||||
option, meaning
|
||||
if you changed them before the
|
||||
.Fl -std
|
||||
option, you're now overwriting them.
|
||||
.Pp
|
||||
.Fl std= Ns Cm gmqcc No includes:
|
||||
.Bl -tag -width indent -compact -offset Ds
|
||||
.It Fl f Ns Cm adjust-vector-fields
|
||||
.It Fl f Ns Cm correct-logic
|
||||
.It Fl f Ns Cm true-empty-strings
|
||||
.It Fl f Ns Cm loop-labels
|
||||
.It Fl f Ns Cm initialized-nonconstants
|
||||
.It Fl f Ns Cm translatable-strings
|
||||
.It Fl fno- Ns Cm false-empty-strings
|
||||
.It Fl W Ns Cm invalid-parameter-count
|
||||
.It Fl W Ns Cm missing-returnvalues
|
||||
.It Fl f Ns Cm correct-ternary Li (cannot be turned off)
|
||||
.El
|
||||
.Pp
|
||||
.Fl std= Ns Cm qcc No includes:
|
||||
.Bl -tag -width indent -compact -offset Ds
|
||||
.It Fl f Ns Cm assign-function-types
|
||||
.It Fl fIno- Ns Cm adjust-vector-fields
|
||||
.El
|
||||
.Pp
|
||||
.Fl std= Ns Cm fteqcc No includes:
|
||||
.Bl -tag -width indent -compact -offset Ds
|
||||
.It Fl f Ns Cm ftepp
|
||||
.It Fl f Ns Cm translatable-strings
|
||||
.It Fl f Ns Cm assign-function-types
|
||||
.It Fl W Ns Cm ternary-precedence
|
||||
.It Fl fno- Ns Cm adjust-vector-fields
|
||||
.It Fl fno- Ns Cm correct-ternary
|
||||
.El
|
||||
.It Fl -add-info
|
||||
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
|
||||
parameter.
|
||||
.El
|
||||
.It Fl -correct , Fl -no-correct
|
||||
When enabled, errors about undefined values try to suggest an existing
|
||||
value via spell checking.
|
||||
.It Fl dump
|
||||
DEBUG OPTION. Print the code's intermediate representation before the
|
||||
optimization and finalization passes to stdout before generating the
|
||||
binary.
|
||||
.It Fl dumpfin
|
||||
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
|
||||
.It Fl W Ns Cm unused-variable
|
||||
Generate a warning about variables which are declared but never used.
|
||||
This can be avoided by adding the \fInoref\fR keyword in front of the
|
||||
This can be avoided by adding the
|
||||
.Ql noref
|
||||
keyword in front of the
|
||||
variable declaration. Additionally a complete section of unreferenced
|
||||
variables can be opened using \fI#pragma noref 1\fR, and closed via
|
||||
\fI#pragma noref 0\fR.
|
||||
.TP
|
||||
.B -Wused-uninitialized
|
||||
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
|
||||
necessarily reliable if the initialization happens only under certain
|
||||
conditions. The other way is \fInot\fR possible: that the warning is
|
||||
\fInot\fR generated when uninitialized use \fIis possible\fR.
|
||||
.TP
|
||||
.B -Wunknown-control-sequence
|
||||
conditions. The other way is
|
||||
.Em not
|
||||
possible: that the warning is
|
||||
.Em not
|
||||
generated when uninitialized use
|
||||
.Em is
|
||||
possible.
|
||||
.It Fl W Ns Cm unknown-control-sequence
|
||||
Generate an error when an unrecognized control sequence in a string is
|
||||
used. Meaning: when there's a character after a backslash in a string
|
||||
which has no known meaning.
|
||||
.TP
|
||||
.B -Wextensions
|
||||
.It Fl W Ns Cm extensions
|
||||
Warn when using special extensions which are not part of the selected
|
||||
standard.
|
||||
.TP
|
||||
.B -Wfield-redeclared
|
||||
.It Fl W Ns Cm field-redeclared
|
||||
Generally QC compilers ignore redeclaration of fields. Here you can
|
||||
optionally enable a warning.
|
||||
.TP
|
||||
.B -Wmissing-return-values
|
||||
Functions which aren't of type \fIvoid\fR will warn if it possible to
|
||||
.It Fl W Ns Cm missing-return-values
|
||||
Functions which aren't of type
|
||||
.Ft void
|
||||
will warn if it possible to
|
||||
reach the end without returning an actual value.
|
||||
.TP
|
||||
.B -Wtoo-few-parameters
|
||||
Warn about a function call with fewer parameters than the function
|
||||
expects.
|
||||
.TP
|
||||
.B -Wlocal-shadows
|
||||
.It Fl W Ns Cm invalid-parameter-count
|
||||
Warn about a function call with an invalid number of parameters.
|
||||
.It Fl W Ns Cm local-shadows
|
||||
Warn when a locally declared variable shadows variable.
|
||||
.TP
|
||||
.B -Wlocal-constants
|
||||
.It Fl W Ns Cm local-constants
|
||||
Warn when the initialization of a local variable turns the variable
|
||||
into a constant. This is default behaviour unless
|
||||
\fI-finitialized-nonconstants\fR is used.
|
||||
.TP
|
||||
.B -Wvoid-variables
|
||||
There are only 2 known global variables of type void: end_sys_globals
|
||||
and end_sys_fields. Any other void-variable will warn.
|
||||
.TP
|
||||
.B -Wimplicit-function-pointer
|
||||
A global function which is not declared with the \fIvar\fR keyword is
|
||||
.Fl f Ns Cm initialized-nonconstants
|
||||
is used.
|
||||
.It Fl W Ns Cm void-variables
|
||||
There are only 2 known global variables of type void:
|
||||
.Ql end_sys_globals
|
||||
and
|
||||
.Ql end_sys_fields Ns .
|
||||
Any other void-variable will warn.
|
||||
.It Fl W Ns Cm implicit-function-pointer
|
||||
A global function which is not declared with the
|
||||
.Ql var
|
||||
keyword is
|
||||
expected to have an implementing body, or be a builtin. If neither is
|
||||
the case, it implicitly becomes a function pointer, and a warning is
|
||||
generated.
|
||||
.TP
|
||||
.B -Wvariadic-function
|
||||
.It Fl W Ns Cm variadic-function
|
||||
Currently there's no way for an in QC implemented function to access
|
||||
variadic parameters. If a function with variadic parameters has an
|
||||
implementing body, a warning will be generated.
|
||||
.TP
|
||||
.B -Wframe-macros
|
||||
Generate warnings about \fI$frame\fR commands, for instance about
|
||||
.It Fl W Ns Cm frame-macros
|
||||
Generate warnings about
|
||||
.Ql $frame
|
||||
commands, for instance about
|
||||
duplicate frame definitions.
|
||||
.TP
|
||||
.B -Weffectless-statement
|
||||
.It Fl W Ns Cm effectless-statement
|
||||
Warn about statements which have no effect. Any expression which does
|
||||
not call a function or assigns a variable.
|
||||
.TP
|
||||
.B -Wend-sys-fields
|
||||
The \fIend_sys_fields\fR variable is supposed to be a global variable
|
||||
of type \fIvoid\fR. It is also recognized as a \fIfield\fR but this
|
||||
.It Fl W Ns Cm end-sys-fields
|
||||
The
|
||||
.Ql end_sys_fields
|
||||
variable is supposed to be a global variable
|
||||
of type
|
||||
.Ft void Ns .
|
||||
It is also recognized as a \fIfield\fR but this
|
||||
will generate a warning.
|
||||
.TP
|
||||
.B -Wassign-function-types
|
||||
.It Fl W Ns Cm assign-function-types
|
||||
Warn when assigning to a function pointer with an unmatching
|
||||
signature. This usually happens in cases like assigning the null
|
||||
function to an entity's .think function pointer.
|
||||
.TP
|
||||
.B -Wpreprocessor
|
||||
Enable warnings coming from the preprocessor. Like duplicate macro
|
||||
declarations.
|
||||
.TP
|
||||
.B -Wmultifile-if
|
||||
.It Fl W Ns Cm cpp
|
||||
Show warnings created using the preprocessor's '#warning' directive.
|
||||
.It Fl W Ns Cm multifile-if
|
||||
Warn if there's a preprocessor \fI#if\fR spanning across several
|
||||
files.
|
||||
.TP
|
||||
.B -Wdouble-declaration
|
||||
.It Fl W Ns Cm double-declaration
|
||||
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.
|
||||
.TP
|
||||
.B -Wconst-var
|
||||
.It Fl W Ns Cm const-var
|
||||
The combination of \fIconst\fR and \fIvar\fR is not illegal, however
|
||||
different compilers may handle them differently. We were told, the
|
||||
intention is to create a function-pointer which is not assignable.
|
||||
This is exactly how we interpret it. However for this interpretation
|
||||
the \fIvar\fR keyword is considered superfluous (and philosophically
|
||||
the
|
||||
.Ql var
|
||||
keyword is considered superfluous (and philosophically
|
||||
wrong), so it is possible to generate a warning about this.
|
||||
.TP
|
||||
.B -Wmultibyte-character
|
||||
.It Fl W Ns Cm multibyte-character
|
||||
Warn about multibyte character constants, they do not work right now.
|
||||
.TP
|
||||
.B -Wternary-precedence
|
||||
.It Fl W Ns Cm ternary-precedence
|
||||
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 \fI-fcorrect-ternary\fR option.
|
||||
.TP
|
||||
.B -Wunknown-pragmas
|
||||
Warn when encountering an unrecognized \fI#pragma\fR line.
|
||||
.TP
|
||||
.B -Wunreachable-code
|
||||
actually want. We recommend the
|
||||
.Fl f Ns Cm correct-ternary
|
||||
option.
|
||||
.It Fl W Ns Cm unknown-pragmas
|
||||
Warn when encountering an unrecognized
|
||||
.Ql #pragma
|
||||
line.
|
||||
.It Fl W Ns Cm unreachable-code
|
||||
Warn about unreachable code. That is: code after a return statement,
|
||||
or code after a call to a function marked as 'noreturn'.
|
||||
.TP
|
||||
.B -Wdebug
|
||||
.It Fl W Ns Cm debug
|
||||
Enable some warnings added in order to help debugging in the compiler.
|
||||
You won't need this.
|
||||
.SH Compile Flags
|
||||
.TP
|
||||
.B -foverlap-locals
|
||||
Allow local variables to overlap with each other if they don't
|
||||
interfer with each other. (Not implemented right now)
|
||||
.TP
|
||||
.B -fdarkplaces-string-table-bug
|
||||
.It Fl W Ns Cm unknown-attribute
|
||||
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.
|
||||
.It Fl W Ns Cm reserved-names
|
||||
Warn when using reserved names such as
|
||||
.Ql nil Ns .
|
||||
.It Fl W Ns Cm uninitialized-constant
|
||||
Warn about global constants (using the
|
||||
.Ql const
|
||||
keyword) with no
|
||||
assigned value.
|
||||
.It Fl W Ns Cm uninitialized-global
|
||||
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.
|
||||
.It Fl W Ns Cm different-qualifiers
|
||||
Warn when a variables is redeclared with a different qualifier. For
|
||||
example when redeclaring a variable as \'var\' which was previously
|
||||
marked \'const\'.
|
||||
.It Fl W Ns Cm different-attributes
|
||||
Similar to the above but for attributes like
|
||||
.Ql [[noreturn]] Ns .
|
||||
.It Fl W Ns Cm deprecated
|
||||
Warn when a function is marked with the attribute
|
||||
"[[deprecated]]". This flag enables a warning on calls to functions
|
||||
marked as such.
|
||||
.It Fl W Ns Cm parenthesis
|
||||
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
|
||||
.It Fl f Ns Cm darkplaces-string-table-bug
|
||||
Add some additional characters to the string table in order to
|
||||
compensate for a wrong boundcheck in some specific version of the
|
||||
darkplaces engine.
|
||||
.TP
|
||||
.B -fadjust-vector-fields
|
||||
.It Fl f Ns Cm adjust-vector-fields
|
||||
When assigning to field pointers of type \fI.vector\fR the common
|
||||
behaviour in compilers like \fIfteqcc\fR is to only assign the
|
||||
x-component 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.
|
||||
.TP
|
||||
.B -fftepp
|
||||
.It Fl f Ns Cm ftepp
|
||||
Enable a partially fteqcc-compatible preprocessor. It supports all the
|
||||
features used in the Xonotic codebase. If you need more, write a
|
||||
ticket.
|
||||
.TP
|
||||
.B -frelaxed-switch
|
||||
.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
|
||||
following macros will be added:
|
||||
.Bd -literal -offset indent
|
||||
__LINE__
|
||||
__FILE__
|
||||
__COUNTER__
|
||||
__COUNTER_LAST__
|
||||
__RANDOM__
|
||||
__RANDOM_LAST__
|
||||
__DATE__
|
||||
__TIME__
|
||||
__FUNC__
|
||||
.Ed
|
||||
.Pp
|
||||
Note that
|
||||
.Li __FUNC__
|
||||
is not actually a preprocessor macro, but is recognized by the parser
|
||||
even with the preprocessor disabled.
|
||||
.Pp
|
||||
Note that fteqcc also defines
|
||||
.Li __NULL__
|
||||
which becomes the first global. Assigning it to a vector does not
|
||||
yield the same result as in gmqcc where
|
||||
.Li __NULL__
|
||||
is defined to
|
||||
.Li nil
|
||||
(See
|
||||
.Fl f Ns Cm untyped-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 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.
|
||||
.TP
|
||||
.B -fshort-logic
|
||||
.It Fl f Ns Cm short-logic
|
||||
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 possibilities.
|
||||
.TP
|
||||
.B -fperl-logic
|
||||
.It Fl f Ns Cm perl-logic
|
||||
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 \fItrue && 5\fI evaluates to 5 rather than 1.
|
||||
.TP
|
||||
.B -ftranslatable-strings
|
||||
Enable the underscore intrinsic: Using \fI_("A string constant")\fR
|
||||
Thus
|
||||
.Ql true && 5
|
||||
evaluates to 5 rather than 1.
|
||||
.It Fl f Ns Cm translatable-strings
|
||||
Enable the underscore intrinsic: Using
|
||||
.Ql _("A string constant")
|
||||
will cause the string immediate to get a name with a "dotranslate_"
|
||||
prefix. The darkplaces engine recognizes these and translates them in
|
||||
a way similar to how gettext works.
|
||||
.TP
|
||||
.B -finitialized-nonconstants
|
||||
.It Fl f Ns Cm initialized-nonconstants
|
||||
Don't implicitly convert initialized variables to constants. With this
|
||||
flag, the \fIconst\fR keyword is required to make a constant.
|
||||
.TP
|
||||
.B -fassign-function-types
|
||||
.It Fl f Ns Cm assign-function-types
|
||||
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.
|
||||
.TP
|
||||
.B -flno
|
||||
.It Fl f Ns Cm lno
|
||||
Produce a linenumber file along with the output .dat file.
|
||||
.TP
|
||||
.B -fcorrect-ternary
|
||||
.It Fl f Ns Cm correct-ternary
|
||||
Use C's operator precedence for ternary expressions. Unless your code
|
||||
depends on fteqcc-compatible behaviour, you'll want to use thi
|
||||
soption.
|
||||
.TP
|
||||
.B -fsingle-vector-defs
|
||||
.It Fl f Ns Cm single-vector-defs
|
||||
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.
|
||||
.SH CONFIG
|
||||
.It Fl f Ns Cm correct-logic
|
||||
Most QC compilers translate
|
||||
.Ql 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.
|
||||
.Bd -literal -offset indent
|
||||
if (a_vector) // becomes
|
||||
if not(!a_vector)
|
||||
// likewise
|
||||
a = a_vector && a_float // becomes
|
||||
a = !!a_vector && a_float
|
||||
.Ed
|
||||
.It Fl f Ns Cm true-empty-strings
|
||||
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.
|
||||
.It Fl f Ns Cm false-empty-strings
|
||||
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.
|
||||
.It Fl f Ns Cm utf8
|
||||
Enable utf8 characters. This allows utf-8 encoded character constants,
|
||||
and escape sequence codepoints in the valid utf-8 range. Effectively
|
||||
enabling escape sequences like '\\{x2211}'.
|
||||
.It Fl f Ns Cm bail-on-werror
|
||||
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.
|
||||
.It Fl f Ns Cm loop-labels
|
||||
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.
|
||||
.Bd -literal -offset indent
|
||||
for :outer (i = 0; i < n; ++i) {
|
||||
while (inner) {
|
||||
...;
|
||||
if (something)
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
.Ed
|
||||
.It Fl f Ns Cm untyped-nil
|
||||
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.
|
||||
.sp
|
||||
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.
|
||||
.sp
|
||||
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.
|
||||
.It Fl f Ns Cm permissive
|
||||
Various effects, usually to weaken some conditions.
|
||||
.Bl -tag -width indent -offset indent
|
||||
.It with Fl f Ns Cm untyped-nil
|
||||
Allow local variables named
|
||||
.Ql nil Ns .
|
||||
(This will not allow declaring a global of that name.)
|
||||
.El
|
||||
.It Fl f Ns Cm variadic-args
|
||||
Allow variadic parameters to be accessed by QC code. This can be
|
||||
achieved via the '...' function, which takes a parameter index and a
|
||||
typename.
|
||||
.Pp
|
||||
Example:
|
||||
.Bd -literal -offset indent
|
||||
void vafunc(string...count) {
|
||||
float i;
|
||||
for (i = 0; i < count; ++i)
|
||||
print(...(i, string), "\\n");
|
||||
}
|
||||
.Ed
|
||||
.It Fl f Ns Cm legacy-vector-maths
|
||||
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
|
||||
.It Fl O Ns Cm peephole
|
||||
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.
|
||||
.It Fl O Ns Cm tail-recursion
|
||||
Tail recursive function calls will be turned into loops to avoid the
|
||||
overhead of the CALL and RETURN instructions.
|
||||
.It Fl O Ns Cm overlap-locals
|
||||
Make all functions which use neither local arrays nor have locals
|
||||
which are seen as possibly uninitialized use the same local section.
|
||||
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 initializing it via a loop, we assume
|
||||
functions with arrays to be too dangerous for this optimization.
|
||||
.It Fl O Ns Cm local-temps
|
||||
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.
|
||||
.It Fl O Ns Cm global-temps
|
||||
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 execute faster.
|
||||
.It Fl O Ns Cm strip-constant-names
|
||||
Don't generate defs for immediate values or even declared constants.
|
||||
Meaning variables which are implicitly constant or qualified as such
|
||||
using the 'const' keyword.
|
||||
.It Fl O Ns Cm overlap-strings
|
||||
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.
|
||||
.Pp
|
||||
For example the following code will only generate 1 string:
|
||||
.Bd -literal -offset indent
|
||||
print("Hello you!\\n");
|
||||
print("you!\\n"); // trailing substring of "Hello you!\\n"
|
||||
.Ed
|
||||
.Pp
|
||||
There's however one limitation. Strings are still processed in order,
|
||||
so if the above print statements were reversed, this optimization
|
||||
would not happen.
|
||||
.It Fl O Ns Cm call-stores
|
||||
By default, all parameters of a CALL are copied into the
|
||||
parameter-globals right before the CALL instructions. This is the
|
||||
easiest and safest way to translate calls, but also adds a lot of
|
||||
unnecessary copying and unnecessary temporary values. This
|
||||
optimization 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.
|
||||
.It Fl O Ns Cm void-return
|
||||
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.
|
||||
.It Fl O Ns Cm vector-components
|
||||
Because traditional QC code doesn't allow you to access individual
|
||||
vector components of a computed vector without storing it in a local
|
||||
first, sometimes people multiply it by a constant like
|
||||
.Ql '0 1 0'
|
||||
to get,
|
||||
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
|
||||
start with hashtags or semicolons, sections are written in square
|
||||
brackets and in each section there can be arbitrary many key-value
|
||||
pairs.
|
||||
.sp
|
||||
.Pp
|
||||
There are 3 sections currently:
|
||||
.IR flags ", " warnings ", and " 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
|
||||
corresponding -W, -f or -O flag written with only capital letters and
|
||||
.Ql flags Ns ,
|
||||
.Ql warnings Ns ,
|
||||
.Ql optimizations Ns .
|
||||
They contain a list of boolean values of the form
|
||||
.Ql VARNAME = true
|
||||
or
|
||||
.Ql VARNAME = false Ns .
|
||||
The variable names are the same as for the
|
||||
corresponding
|
||||
.Fl W , Fl f
|
||||
or
|
||||
.Fl O
|
||||
flag written with only capital letters and
|
||||
dashes replaced by underscores.
|
||||
.sp
|
||||
.Pp
|
||||
Here's an example:
|
||||
.in +4
|
||||
.nf
|
||||
.Bd -literal -offset indent
|
||||
# a GMQCC configuration file
|
||||
[flags]
|
||||
FTEPP = true
|
||||
|
@ -326,12 +753,19 @@ Here's an example:
|
|||
[optimizations]
|
||||
PEEPHOLE = true
|
||||
TAIL_RECURSION = true
|
||||
.fi
|
||||
.in
|
||||
.SH BUGS
|
||||
.Ed
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
.It gmqcc.ini.example
|
||||
A documented example for a gmqcc.ini file.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr qcvm 1
|
||||
.Sh AUTHOR
|
||||
See <http://graphitemaster.github.com/gmqcc>.
|
||||
.Sh BUGS
|
||||
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>,
|
||||
or see <http://graphitemaster.github.com/gmqcc> on how to contact us.
|
||||
.SH SEE ALSO
|
||||
.IR qcvm (1)
|
||||
.SH AUTHOR
|
||||
See <http://graphitemaster.github.com/gmqcc>.
|
||||
|
|
155
doc/qcvm.1
155
doc/qcvm.1
|
@ -1,92 +1,107 @@
|
|||
.\" Process with groff -man -Tascii file.3
|
||||
.TH QCVM 1 2012-18-12 "" "gmqcc Manual"
|
||||
.SH NAME
|
||||
qcvm \- A standalone QuakeC VM binary executor.
|
||||
.SH SYNOPSIS
|
||||
.B qcvm
|
||||
[\fIOPTIONS\fR] [\fIPARAMS\fR] [\fIfile\fR]
|
||||
.SH DESCRIPTION
|
||||
qcvm is an executor for QuakeC VM binary files created using a QC
|
||||
.\" qcvm mdoc manpage
|
||||
.Dd January 31, 2013
|
||||
.Dt QCVM 1 PRM
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm qcvm
|
||||
.Nd A standalone QuakeC VM binary executor
|
||||
.Sh SYNOPSIS
|
||||
.Nm qcvm
|
||||
.Op Cm options
|
||||
.Op Cm parameters
|
||||
.Ar program-file
|
||||
.Sh DESCRIPTION
|
||||
.Nm qcvm
|
||||
is an executor for QuakeC VM binary files created using a QC
|
||||
compiler such as gmqcc(1) or fteqcc. It provides a small set of
|
||||
builtin functions, and by default executes the \fImain\fR function if
|
||||
there is one. Some options useful for debugging are available as well.
|
||||
.SH OPTIONS
|
||||
builtin functions, and by default executes the
|
||||
.Fn main
|
||||
function if there is one. Some options useful for debugging are
|
||||
available as well.
|
||||
.Sh OPTIONS
|
||||
There are 2 types of options. Options for the executor, and parameter
|
||||
options used to add parameters which are passed to the main function
|
||||
on execution.
|
||||
.TP
|
||||
.B "-h, --help"
|
||||
.Bl -tag -width Ds
|
||||
.It Fl h , Fl -help
|
||||
Show a usage message and exit.
|
||||
.TP
|
||||
.B "-trace"
|
||||
.It Fl trace
|
||||
Trace the execution. Each instruction will be printed to stdout before
|
||||
executing it.
|
||||
.TP
|
||||
.B "-profile"
|
||||
.It Fl profile
|
||||
Perform some profiling. This is currently not really implemented, the
|
||||
option is available nonetheless.
|
||||
.TP
|
||||
.B "-info"
|
||||
.It Fl info
|
||||
Print information from the program's header instead of executing.
|
||||
.TP
|
||||
.B "-disasm"
|
||||
.It Fl disasm
|
||||
Disassemble the program by function instead of executing.
|
||||
.TP
|
||||
.B "-printdefs"
|
||||
.It Fl disasm-func Ar function
|
||||
Search for and disassemble the given function.
|
||||
.It Fl printdefs
|
||||
List all entries from the program's defs-section. Effectively
|
||||
listing all the global variables of the program.
|
||||
This option disables execution.
|
||||
.TP
|
||||
.B "-printfields"
|
||||
.It Fl printfields
|
||||
List all entries from the program's fields-section. Listing all
|
||||
entity-fields declared in the program.
|
||||
This option disables execution.
|
||||
.TP
|
||||
.B "-printfuns"
|
||||
.It Fl printfuns
|
||||
List functions and some information about their parameters.
|
||||
This option disables execution.
|
||||
.TP
|
||||
.BI "-vector """ "x y z" """"
|
||||
Append a vector parameter to be passed to \fImain\fR.
|
||||
.TP
|
||||
.BI "-float " number
|
||||
Append a float parameter to be passed to \fImain\fR.
|
||||
.TP
|
||||
.BI "-string """ "text" """"
|
||||
Append a string parameter to be passed to \fImain\fR.
|
||||
.SH BUILTINS
|
||||
This option disables execution. With a verbosity level of 1, builtin
|
||||
numbers are printed. With a verbosity of 2, the function's sizes are
|
||||
printed as well. This takes a little longer since the size is found by
|
||||
searching for a
|
||||
.Ql DONE
|
||||
instruction in the code.
|
||||
.It Fl v
|
||||
Increase verbosity level, can be used multiple times.
|
||||
.It Fl vector Ar 'x y z'
|
||||
Append a vector parameter to be passed to
|
||||
.Fn main Ns .
|
||||
.It Fl float Ar number
|
||||
Append a float parameter to be passed to
|
||||
.Fn main Ns .
|
||||
.It Fl string Ar 'text'
|
||||
Append a string parameter to be passed to
|
||||
.Fn main Ns .
|
||||
.El
|
||||
.Sh BUILTINS
|
||||
The following builtin functions are available:
|
||||
.TP
|
||||
.RI "1) " void " print(" string... ") = " "#1" ;
|
||||
.Bl -ohang
|
||||
.It Li 1) void print(string...) = #1;
|
||||
.Bd -unfilled -offset indent -compact
|
||||
Print the passed strings to stdout. At most 8 strings are allowed.
|
||||
.TP
|
||||
.RI "2) " string " ftos(" float ") = " "#2" ;
|
||||
Convert a float to a string.
|
||||
.TP
|
||||
.RI "3) " entity " spawn() = " "#3" ;
|
||||
Spawn an entity.
|
||||
.TP
|
||||
.RI "4) " void " remove(" entity ") = " "#4" ;
|
||||
Remove an entity.
|
||||
.TP
|
||||
.RI "5) " string " vtos(" vector ") = " "#5" ;
|
||||
Convert a vector to a string.
|
||||
.TP
|
||||
.RI "6) " void " error(" string... ") = " "#6" ;
|
||||
Print at most 8 strings to stdout and then exit with an error.
|
||||
.TP
|
||||
.RI "7) " float " vlen(" vector ") = " "#7" ;
|
||||
Get the length of a vector.
|
||||
.TP
|
||||
.RI "8) " string " etos(" entity ") = " "#8" ;
|
||||
Get the entity ID as string.
|
||||
.TP
|
||||
.RI "9) " float " stof(" string ") = " "#9" ;
|
||||
Convert a string to a float.
|
||||
.SH BUGS
|
||||
.Ed
|
||||
.It Li 2) string ftos(float) = #2;
|
||||
.D1 Convert a float to a string.
|
||||
.It Li 3) entity spawn() = #3;
|
||||
.D1 Spawn an entity.
|
||||
.It Li 4) void remove(entity) = #4;
|
||||
.D1 Remove an entity.
|
||||
.It Li 5) string vtos(vector) = #5;
|
||||
.D1 Convert a vector to a string.
|
||||
.It Li 6) void error(string...) = #6;
|
||||
.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;
|
||||
.D1 Get the entity ID as string.
|
||||
.It Li 9) float stof(string) = #9;
|
||||
.D1 Convert a string to a float.
|
||||
.It Li 10) string strcat(string, string) = #10;
|
||||
.D1 Concatenate two strings, returning a tempstring.
|
||||
.It Li 11) float strcmp(string, string) = #11;
|
||||
.Li 12) float strncmp(string, string, float) = #11;
|
||||
.D1 Compare two strings. Returns the same as the corresponding C functions.
|
||||
.It Li 12) vector normalize(vector) = #12;
|
||||
.D1 Normalize a vector so its length is 1.
|
||||
.It Li 13) float sqrt(float) = #13;
|
||||
.D1 Get a value's square root.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr gmqcc 1
|
||||
.Sh AUTHOR
|
||||
See <http://graphitemaster.github.com/gmqcc>.
|
||||
.Sh BUGS
|
||||
Please report bugs on <http://github.com/graphitemaster/gmqcc/issues>,
|
||||
or see <http://graphitemaster.github.com/gmqcc> on how to contact us.
|
||||
.SH SEE ALSO
|
||||
.IR gmqcc (1)
|
||||
.SH AUTHOR
|
||||
See <http://graphitemaster.github.com/gmqcc>.
|
||||
|
|
1033
exec.c → exec.cpp
1033
exec.c → exec.cpp
File diff suppressed because it is too large
Load diff
121
fold.h
Normal file
121
fold.h
Normal 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
|
File diff suppressed because it is too large
Load diff
|
@ -1,51 +1,745 @@
|
|||
# this is a template for an ini file
|
||||
# these are comments
|
||||
; so are these
|
||||
#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.
|
||||
|
||||
[flags]
|
||||
OVERLAP_LOCALS = false ; comments can exist on lines too
|
||||
DARKPLACES_STRING_TABLE_BUG = false # like this as well
|
||||
ADJUST_VECTOR_FIELDS = true
|
||||
FTEPP = true
|
||||
RELAXED_SWITCH = false
|
||||
SHORT_LOGIC = false
|
||||
PERL_LOGIC = true
|
||||
TRANSLATABLE_STRINGS = false
|
||||
INITIALIZED_NONCONSTANTS = false
|
||||
ASSIGN_FUNCTION_TYPES = false
|
||||
LNO = false
|
||||
CORRECT_TERNARY = true
|
||||
#Add some additional characters to the string table in order to
|
||||
#compensate for a wrong boundcheck in some specific version of the
|
||||
#darkplaces engine.
|
||||
|
||||
DARKPLACES_STRING_TABLE_BUG = 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.
|
||||
|
||||
ADJUST_VECTOR_FIELDS = true
|
||||
|
||||
|
||||
#Enable a partially fteqcc-compatible preprocessor. It supports
|
||||
#all the features used in the Xonotic codebase. If you need more,
|
||||
#write a ticket.
|
||||
|
||||
FTEPP = true
|
||||
|
||||
|
||||
#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.
|
||||
|
||||
FTEPP_PREDEFS = 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
|
||||
|
||||
FTEPP_MATHDEFS = 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"
|
||||
|
||||
FTEPP_INDIRECT_EXPANSION = false
|
||||
|
||||
|
||||
#Allow switch cases to use non constant variables.
|
||||
|
||||
RELAXED_SWITCH = 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.
|
||||
|
||||
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
|
||||
|
||||
# enable all warnings (minus debug)
|
||||
[warnings]
|
||||
DEBUG = false
|
||||
UNUSED_VARIABLE = true
|
||||
USED_UNINITIALIZED = true
|
||||
UNKNOWN_CONTROL_SEQUENCE = true
|
||||
EXTENSIONS = true
|
||||
FIELD_REDECLARED = true
|
||||
MISSING_RETURN_VALUES = true
|
||||
TOO_FEW_PARAMETERS = true
|
||||
LOCAL_SHADOWS = true
|
||||
LOCAL_CONSTANTS = true
|
||||
VOID_VARIABLES = true
|
||||
IMPLICIT_FUNCTION_POINTER = true
|
||||
VARIADIC_FUNCTION = true
|
||||
FRAME_MACROS = true
|
||||
EFFECTLESS_STATEMENT = true
|
||||
END_SYS_FIELDS = true
|
||||
ASSIGN_FUNCTION_TYPES = true
|
||||
PREPROCESSOR = true
|
||||
MULTIFILE_IF = true
|
||||
DOUBLE_DECLARATION = true
|
||||
CONST_VAR = true
|
||||
MULTIBYTE_CHARACTER = true
|
||||
TERNARY_PRECEDENCE = true
|
||||
UNKNOWN_PRAGMAS = true
|
||||
#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’.
|
||||
|
||||
UNUSED_VARIABLE = false
|
||||
|
||||
|
||||
#Generate a warning about vector variables which are declared but
|
||||
#components of it are never used.
|
||||
|
||||
UNUSED_COMPONENT = false
|
||||
|
||||
#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.
|
||||
|
||||
USED_UNINITIALIZED = false
|
||||
|
||||
|
||||
#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.
|
||||
|
||||
UNKNOWN_CONTROL_SEQUENCE = false
|
||||
|
||||
|
||||
#Warn when using special extensions which are not part of the
|
||||
#selected standard.
|
||||
|
||||
EXTENSIONS = false
|
||||
|
||||
|
||||
#Generally QC compilers ignore redeclaration of fields. Here you
|
||||
#can optionally enable a warning.
|
||||
|
||||
FIELD_REDECLARED = false
|
||||
|
||||
|
||||
#Functions which aren't of type void will warn if it possible to
|
||||
#reach the end without returning an actual value.
|
||||
|
||||
MISSING_RETURN_VALUES = false
|
||||
|
||||
|
||||
#Warn about a function call with an invalid number of parameters.
|
||||
|
||||
INVALID_PARAMETER_COUNT = false
|
||||
|
||||
|
||||
#Warn when a locally declared variable shadows variable.
|
||||
|
||||
LOCAL_SHADOWS = false
|
||||
|
||||
|
||||
#Warn when the initialization of a local variable turns the vari‐
|
||||
#able into a constant. This is default behaviour unless
|
||||
#-finitialized-nonconstants is used.
|
||||
|
||||
LOCAL_CONSTANTS = false
|
||||
|
||||
|
||||
#There are only 2 known global variables of type void:
|
||||
#‘end_sys_globals’ and ‘end_sys_fields’. Any other void-variable
|
||||
#will warn.
|
||||
|
||||
VOID_VARIABLES = false
|
||||
|
||||
|
||||
#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
|
||||
|
||||
|
||||
; enable all optimizations!
|
||||
[optimizations]
|
||||
PEEPHOLE = true
|
||||
LOCALTEMPS = true
|
||||
TAIL_RECURSION = true
|
||||
TAIL_CALLS = 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.
|
||||
|
||||
PEEPHOLE = true
|
||||
|
||||
|
||||
#Tail recursive function calls will be turned into loops to avoid
|
||||
#the overhead of the CALL and RETURN instructions.
|
||||
|
||||
TAIL_RECURSION = 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.
|
||||
|
||||
OVERLAP_LOCALS = 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
|
||||
|
|
131
gmqcc.vcxproj
131
gmqcc.vcxproj
|
@ -1,131 +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>{85C266A8-7938-4AE6-AB64-428DC32B1ACD}</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>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>NotSet</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 Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>.\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IntDir>.\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<TargetName>gmqcc</TargetName>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>.</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<IntDir>.</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<TargetName>gmqcc</TargetName>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>
|
||||
</PrecompiledHeaderOutputFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ManifestFile>
|
||||
</ManifestFile>
|
||||
<ProgramDatabaseFile>$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>
|
||||
</PrecompiledHeaderOutputFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<ManifestFile>
|
||||
</ManifestFile>
|
||||
<ProgramDatabaseFile>$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="asm.c" />
|
||||
<ClCompile Include="ast.c" />
|
||||
<ClCompile Include="code.c" />
|
||||
<ClCompile Include="error.c" />
|
||||
<ClCompile Include="exec.c" />
|
||||
<ClCompile Include="ir.c" />
|
||||
<ClCompile Include="lexer.c" />
|
||||
<ClCompile Include="main.c" />
|
||||
<ClCompile Include="parser.c" />
|
||||
<ClCompile Include="util.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ast.h" />
|
||||
<ClInclude Include="execloop.h" />
|
||||
<ClInclude Include="gmqcc.h" />
|
||||
<ClInclude Include="ir.h" />
|
||||
<ClInclude Include="lexer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="flags.def" />
|
||||
<None Include="warns.def" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
2048
intrin.cpp
Normal file
2048
intrin.cpp
Normal file
File diff suppressed because it is too large
Load diff
74
intrin.h
Normal file
74
intrin.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
#ifndef GMQCC_INTRIN_HDR
|
||||
#define GMQCC_INTRIN_HDR
|
||||
#include "gmqcc.h"
|
||||
|
||||
struct fold;
|
||||
struct parser_t;
|
||||
|
||||
struct ast_function;
|
||||
struct ast_expression;
|
||||
struct ast_value;
|
||||
|
||||
struct intrin;
|
||||
|
||||
struct intrin_func_t {
|
||||
ast_expression *(intrin::*function)();
|
||||
const char *name;
|
||||
const char *alias;
|
||||
size_t args;
|
||||
};
|
||||
|
||||
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
|
490
ir.h
490
ir.h
|
@ -1,336 +1,334 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* 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 */
|
||||
/*
|
||||
* 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;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
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;
|
||||
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;
|
||||
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, 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 GMQCC_WARN 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 eid;
|
||||
bool is_return;
|
||||
size_t run_id;
|
||||
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_value* ir_block_create_add(ir_block*, lex_ctx, const char *label, ir_value *l, ir_value *r);
|
||||
ir_value* ir_block_create_sub(ir_block*, lex_ctx, const char *label, ir_value *l, ir_value *r);
|
||||
ir_value* ir_block_create_mul(ir_block*, lex_ctx, const char *label, ir_value *l, ir_value *r);
|
||||
ir_value* ir_block_create_div(ir_block*, lex_ctx, const char *label, ir_value *l, ir_value *r);
|
||||
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;
|
||||
|
||||
int builtin;
|
||||
std::string m_name;
|
||||
qc_type m_outtype;
|
||||
std::vector<int> m_params;
|
||||
ir_flag_t m_flags = 0;
|
||||
int m_builtin = 0;
|
||||
|
||||
ir_value *value;
|
||||
std::vector<std::unique_ptr<ir_block>> m_blocks;
|
||||
|
||||
/* 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;
|
||||
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;
|
||||
size_t m_run_id = 0;
|
||||
|
||||
struct ir_builder_s *owner;
|
||||
} ir_function;
|
||||
/* vararg support: */
|
||||
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_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;
|
||||
|
||||
const char **filenames;
|
||||
qcint *filestrings;
|
||||
/* we cache the #IMMEDIATE string here */
|
||||
qcint str_immediate;
|
||||
} ir_builder;
|
||||
ir_value *generateExtparamProto();
|
||||
void generateExtparam();
|
||||
|
||||
ir_builder* ir_builder_new(const char *modulename);
|
||||
void ir_builder_delete(ir_builder*);
|
||||
ir_value *literalFloat(float value, bool add_to_list);
|
||||
|
||||
bool ir_builder_set_name(ir_builder *self, const char *name);
|
||||
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;
|
||||
|
||||
ir_function* ir_builder_get_function(ir_builder*, const char *fun);
|
||||
ir_function* ir_builder_create_function(ir_builder*, const char *name, int outtype);
|
||||
ht m_htfunctions;
|
||||
ht m_htglobals;
|
||||
ht m_htfields;
|
||||
|
||||
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);
|
||||
// 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;
|
||||
|
||||
bool ir_builder_generate(ir_builder *self, const char *filename);
|
||||
// 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;
|
||||
|
||||
void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...));
|
||||
std::vector<const char*> m_filenames;
|
||||
std::vector<qcint_t> m_filestrings;
|
||||
|
||||
/* This code assumes 32 bit floats while generating binary */
|
||||
extern int check_int_and_float_size
|
||||
[ (sizeof(int32_t) == sizeof(qcfloat)) ? 1 : -1 ];
|
||||
// we cache the #IMMEDIATE string here
|
||||
qcint_t m_str_immediate = 0;
|
||||
|
||||
// there should just be this one nil
|
||||
ir_value *m_nil;
|
||||
ir_value *m_reserved_va_count = nullptr;
|
||||
ir_value *m_coverage_func = nullptr;
|
||||
|
||||
/* 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
|
||||
|
|
File diff suppressed because it is too large
Load diff
380
lexer.h
380
lexer.h
|
@ -1,60 +1,19 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* 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;
|
||||
|
||||
#include "ast.h"
|
||||
|
||||
struct token_s {
|
||||
int ttype;
|
||||
|
||||
char *value;
|
||||
|
||||
union {
|
||||
vector v;
|
||||
int i;
|
||||
double f;
|
||||
int t; /* type */
|
||||
} constval;
|
||||
|
||||
#if 0
|
||||
struct token_s *next;
|
||||
struct token_s *prev;
|
||||
#endif
|
||||
|
||||
lex_ctx ctx;
|
||||
struct token {
|
||||
int ttype;
|
||||
char *value;
|
||||
union {
|
||||
vec3_t v;
|
||||
int i;
|
||||
qcfloat_t f;
|
||||
qc_type t; /* type */
|
||||
} constval;
|
||||
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
|
||||
*
|
||||
*/
|
||||
|
@ -73,6 +32,13 @@ enum {
|
|||
|
||||
TOKEN_DOTS, /* 3 dots, ... */
|
||||
|
||||
TOKEN_ATTRIBUTE_OPEN, /* [[ */
|
||||
TOKEN_ATTRIBUTE_CLOSE, /* ]] */
|
||||
|
||||
TOKEN_VA_ARGS, /* for the ftepp only */
|
||||
TOKEN_VA_ARGS_ARRAY, /* for the ftepp only */
|
||||
TOKEN_VA_COUNT, /* to get the count of vaargs */
|
||||
|
||||
TOKEN_STRINGCONST, /* not the typename but an actual "string" */
|
||||
TOKEN_CHARCONST,
|
||||
TOKEN_VECTORCONST,
|
||||
|
@ -82,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
|
||||
|
@ -91,41 +61,42 @@ enum {
|
|||
TOKEN_FATAL /* internal error, eg out of memory */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct frame_macro {
|
||||
char *name;
|
||||
int value;
|
||||
} frame_macro;
|
||||
int value;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
const char *open_string;
|
||||
size_t open_string_length;
|
||||
size_t open_string_pos;
|
||||
struct lex_file {
|
||||
FILE *file;
|
||||
const char *open_string;
|
||||
size_t open_string_length;
|
||||
size_t open_string_pos;
|
||||
|
||||
char *name;
|
||||
size_t line;
|
||||
size_t sline; /* line at the start of a token */
|
||||
char *name;
|
||||
size_t line;
|
||||
size_t sline; /* line at the start of a token */
|
||||
size_t column;
|
||||
|
||||
char peek[256];
|
||||
size_t peekpos;
|
||||
int peek[256];
|
||||
size_t peekpos;
|
||||
|
||||
bool eof;
|
||||
bool eof;
|
||||
|
||||
token tok; /* not a pointer anymore */
|
||||
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;
|
||||
struct {
|
||||
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;
|
||||
frame_macro *frames;
|
||||
char *modelname;
|
||||
|
||||
size_t push_line;
|
||||
} lex_file;
|
||||
size_t push_line;
|
||||
};
|
||||
|
||||
lex_file* lex_open (const char *file);
|
||||
lex_file* lex_open_string(const char *str, size_t len, const char *name);
|
||||
|
@ -145,179 +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, 15, OP_SUFFIX},
|
||||
{ "--", 1, opid3('S','-','-'), ASSOC_LEFT, 15, OP_SUFFIX},
|
||||
{ ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 },
|
||||
{ "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */
|
||||
{ "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */
|
||||
{ "++", 1, opid3('S','+','+'), ASSOC_LEFT, 17, OP_SUFFIX, 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, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||
{ "~", 1, opid2('~', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||
{ "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||
{ "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||
{ "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||
{ "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 14, OP_PREFIX },
|
||||
/* { "&", 1, opid2('&','P'), ASSOC_RIGHT, 14, OP_PREFIX }, */
|
||||
{ "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 16, OP_PREFIX, false},
|
||||
{ "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 16, OP_PREFIX, false},
|
||||
|
||||
{ "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 },
|
||||
{ "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 },
|
||||
{ "%", 2, opid1('%'), ASSOC_LEFT, 13, 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}, */
|
||||
|
||||
{ "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 },
|
||||
{ "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 },
|
||||
{ "*", 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, opid2('<','<'), ASSOC_LEFT, 11, 0 },
|
||||
{ ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 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, 11, 0, true},
|
||||
{ ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0, true},
|
||||
|
||||
{ "==", 2, opid2('=','='), ASSOC_LEFT, 9, 0 },
|
||||
{ "!=", 2, opid2('!','='), ASSOC_LEFT, 9, 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, 8, 0 },
|
||||
{ "==", 2, opid2('=','='), ASSOC_LEFT, 9, 0, true},
|
||||
{ "!=", 2, opid2('!','='), ASSOC_LEFT, 9, 0, true},
|
||||
|
||||
{ "^", 2, opid1('^'), ASSOC_LEFT, 7, 0 },
|
||||
{ "&", 2, opid1('&'), ASSOC_LEFT, 8, 0, true},
|
||||
|
||||
{ "|", 2, opid1('|'), ASSOC_LEFT, 6, 0 },
|
||||
{ "^", 2, opid1('^'), ASSOC_LEFT, 7, 0, true},
|
||||
|
||||
{ "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 },
|
||||
{ "|", 2, opid1('|'), ASSOC_LEFT, 6, 0, true},
|
||||
|
||||
{ "||", 2, opid2('|','|'), ASSOC_LEFT, 4, 0 },
|
||||
{ "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0, true},
|
||||
|
||||
{ "?", 3, opid2('?',':'), ASSOC_RIGHT, 3, 0 },
|
||||
{ "||", 2, opid2('|','|'), ASSOC_LEFT, 4, 0, true},
|
||||
|
||||
{ "=", 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 },
|
||||
{ "?", 3, opid2('?',':'), ASSOC_RIGHT, 3, 0, true},
|
||||
|
||||
{ ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 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_LEFT, 0, 0 }
|
||||
{ ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0, false},
|
||||
|
||||
{ ",", 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, 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, opid2('<','<'), ASSOC_LEFT, 11, 0, true},
|
||||
{ ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0, true},
|
||||
|
||||
{ "?", 3, opid2('?',':'), ASSOC_RIGHT, 9, 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, opid3('&','~','='), ASSOC_RIGHT, 8, 0 },
|
||||
{ "?", 3, opid2('?',':'), ASSOC_RIGHT, 9, 0, true},
|
||||
|
||||
{ "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 },
|
||||
{ "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 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, 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
|
||||
|
|
|
@ -1,40 +1,20 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Wolfgang Bumiller
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gmqcc.h"
|
||||
#include "lexer.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
|
||||
|
@ -42,8 +22,8 @@ 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,
|
||||
|
@ -52,15 +32,15 @@ static void version() {
|
|||
);
|
||||
}
|
||||
|
||||
static int usage() {
|
||||
static int usage(void) {
|
||||
con_out("usage: %s [options] [files...]", app_name);
|
||||
con_out("options:\n"
|
||||
" -h, --help show this help message\n"
|
||||
" -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");
|
||||
con_out(" -q, --quiet be less verbose\n");
|
||||
con_out(" -config file use the specified ini file\n");
|
||||
con_out(" -std=standard select one of the following standards\n"
|
||||
" -std=qcc original QuakeC\n"
|
||||
|
@ -81,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;
|
||||
}
|
||||
|
||||
|
@ -135,18 +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 = (char*)stdout;
|
||||
char *redirerr = (char*)stderr;
|
||||
char *config = NULL;
|
||||
char buffer[1024];
|
||||
char *config = nullptr;
|
||||
|
||||
while (!argend && argc > 1) {
|
||||
char *argarg;
|
||||
argitem item;
|
||||
ppitem macro;
|
||||
ppitem macro;
|
||||
|
||||
++argv;
|
||||
--argc;
|
||||
|
@ -156,14 +136,31 @@ static bool options_parse(int argc, char **argv) {
|
|||
if (options_long_gcc("std", &argc, &argv, &argarg)) {
|
||||
if (!strcmp(argarg, "gmqcc") || !strcmp(argarg, "default")) {
|
||||
|
||||
opts_set(opts.flags, ADJUST_VECTOR_FIELDS, true);
|
||||
opts.standard = COMPILER_GMQCC;
|
||||
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);
|
||||
opts_set(opts.flags, TRANSLATABLE_STRINGS, true);
|
||||
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;
|
||||
|
||||
} else if (!strcmp(argarg, "qcc")) {
|
||||
|
||||
opts_set(opts.flags, ADJUST_VECTOR_FIELDS, false);
|
||||
opts_set(opts.flags, ASSIGN_FUNCTION_TYPES, true);
|
||||
opts.standard = COMPILER_QCC;
|
||||
|
||||
OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_QCC;
|
||||
|
||||
} else if (!strcmp(argarg, "fte") || !strcmp(argarg, "fteqcc")) {
|
||||
|
||||
|
@ -171,14 +168,16 @@ static bool options_parse(int argc, char **argv) {
|
|||
opts_set(opts.flags, TRANSLATABLE_STRINGS, true);
|
||||
opts_set(opts.flags, ADJUST_VECTOR_FIELDS, false);
|
||||
opts_set(opts.flags, ASSIGN_FUNCTION_TYPES, true);
|
||||
opts_set(opts.warn, WARN_TERNARY_PRECEDENCE, true);
|
||||
opts_set(opts.flags, CORRECT_TERNARY, false);
|
||||
opts.standard = COMPILER_FTEQCC;
|
||||
opts_set(opts.warn, WARN_TERNARY_PRECEDENCE, true);
|
||||
opts_set(opts.warn, WARN_BREAKDEF, true);
|
||||
|
||||
OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_FTEQCC;
|
||||
|
||||
} else if (!strcmp(argarg, "qccx")) {
|
||||
|
||||
opts_set(opts.flags, ADJUST_VECTOR_FIELDS, false);
|
||||
opts.standard = COMPILER_QCCX;
|
||||
OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_QCCX;
|
||||
|
||||
} else {
|
||||
con_out("Unknown standard: %s\n", argarg);
|
||||
|
@ -187,27 +186,28 @@ static bool options_parse(int argc, char **argv) {
|
|||
continue;
|
||||
}
|
||||
if (options_long_gcc("force-crc", &argc, &argv, &argarg)) {
|
||||
opts.forcecrc = true;
|
||||
opts.forced_crc = strtol(argarg, NULL, 0);
|
||||
|
||||
OPTS_OPTION_BOOL(OPTION_FORCECRC) = true;
|
||||
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("progsrc", &argc, &argv, &argarg)) {
|
||||
OPTS_OPTION_STR(OPTION_PROGSRC) = argarg;
|
||||
*has_progs_src = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* show defaults (like pathscale) */
|
||||
if (!strcmp(argv[0]+1, "show-defaults")) {
|
||||
size_t itr;
|
||||
char buffer[1024];
|
||||
for (itr = 0; itr < COUNT_FLAGS; ++itr) {
|
||||
if (!OPTS_FLAG(itr))
|
||||
continue;
|
||||
|
@ -230,25 +230,25 @@ static bool options_parse(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (!strcmp(argv[0]+1, "debug")) {
|
||||
opts.debug = true;
|
||||
OPTS_OPTION_BOOL(OPTION_DEBUG) = true;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[0]+1, "dump")) {
|
||||
opts.dump = true;
|
||||
OPTS_OPTION_BOOL(OPTION_DUMP) = true;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[0]+1, "dumpfin")) {
|
||||
opts.dumpfin = true;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[0]+1, "memchk")) {
|
||||
opts.memchk = true;
|
||||
OPTS_OPTION_BOOL(OPTION_DUMPFIN) = 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 */
|
||||
|
@ -262,13 +262,18 @@ static bool options_parse(int argc, char **argv) {
|
|||
exit(0);
|
||||
|
||||
case 'E':
|
||||
opts.pp_only = true;
|
||||
OPTS_OPTION_BOOL(OPTION_PP_ONLY) = true;
|
||||
opts_set(opts.flags, FTEPP_PREDEFS, true); /* predefs on for -E */
|
||||
break;
|
||||
|
||||
/* debug turns on -flno */
|
||||
case 'g':
|
||||
opts_setflag("LNO", true);
|
||||
opts.g = true;
|
||||
OPTS_OPTION_BOOL(OPTION_G) = true;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
OPTS_OPTION_BOOL(OPTION_QUIET) = true;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
|
@ -279,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);
|
||||
|
@ -292,7 +297,7 @@ static bool options_parse(int argc, char **argv) {
|
|||
case 'f':
|
||||
util_strtocmd(argv[0]+2, argv[0]+2, strlen(argv[0]+2)+1);
|
||||
if (!strcmp(argv[0]+2, "HELP") || *(argv[0]+2) == '?') {
|
||||
con_out("Possible flags:\n");
|
||||
con_out("Possible flags:\n\n");
|
||||
for (itr = 0; itr < COUNT_FLAGS; ++itr) {
|
||||
util_strtononcmd(opts_flag_list[itr].name, buffer, sizeof(buffer));
|
||||
con_out(" -f%s\n", buffer);
|
||||
|
@ -317,31 +322,37 @@ static bool options_parse(int argc, char **argv) {
|
|||
for (itr = 0; itr < COUNT_WARNINGS; ++itr) {
|
||||
util_strtononcmd(opts_warn_list[itr].name, buffer, sizeof(buffer));
|
||||
con_out(" -W%s\n", buffer);
|
||||
if (itr == WARN_DEBUG)
|
||||
con_out(" Warnings included by -Wall:\n");
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
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;
|
||||
}
|
||||
else if (!strcmp(argv[0]+2, "ERROR") ||
|
||||
!strcmp(argv[0]+2, "ERROR_ALL"))
|
||||
{
|
||||
for (itr = 0; itr < sizeof(opts.werror)/sizeof(opts.werror[0]); ++itr)
|
||||
opts_backup_non_Werror_all();
|
||||
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")) {
|
||||
for (itr = 0; itr < sizeof(opts.warn)/sizeof(opts.warn[0]); ++itr)
|
||||
opts_backup_non_Wall();
|
||||
for (itr = 0; itr < GMQCC_ARRAY_COUNT(opts.warn); ++itr)
|
||||
opts.warn[itr] = 0xFFFFFFFFL;
|
||||
opts_restore_non_Wall();
|
||||
break;
|
||||
}
|
||||
else if (!strncmp(argv[0]+2, "ERROR_", 6)) {
|
||||
|
@ -373,9 +384,10 @@ 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])) {
|
||||
opts.O = atoi(argarg);
|
||||
opts_setoptimlevel(opts.O);
|
||||
if (util_isdigit(argarg[0])) {
|
||||
uint32_t val = (uint32_t)strtol(argarg, nullptr, 10);
|
||||
OPTS_OPTION_U32(OPTION_O) = val;
|
||||
opts_setoptimlevel(val);
|
||||
} else {
|
||||
util_strtocmd(argarg, argarg, strlen(argarg)+1);
|
||||
if (!strcmp(argarg, "HELP")) {
|
||||
|
@ -387,9 +399,10 @@ static bool options_parse(int argc, char **argv) {
|
|||
exit(0);
|
||||
}
|
||||
else if (!strcmp(argarg, "ALL"))
|
||||
opts_setoptimlevel(opts.O = 9999);
|
||||
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;
|
||||
}
|
||||
|
@ -408,7 +421,7 @@ static bool options_parse(int argc, char **argv) {
|
|||
con_out("option -o requires an argument: the output file name\n");
|
||||
return false;
|
||||
}
|
||||
opts.output = argarg;
|
||||
OPTS_OPTION_STR(OPTION_OUTPUT) = argarg;
|
||||
opts_output_wasset = true;
|
||||
break;
|
||||
|
||||
|
@ -422,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 '-':
|
||||
|
@ -439,10 +455,18 @@ static bool options_parse(int argc, char **argv) {
|
|||
version();
|
||||
exit(0);
|
||||
}
|
||||
else if (!strcmp(argv[0]+2, "quiet")) {
|
||||
OPTS_OPTION_BOOL(OPTION_QUIET) = true;
|
||||
break;
|
||||
}
|
||||
else if (!strcmp(argv[0]+2, "add-info")) {
|
||||
OPTS_OPTION_BOOL(OPTION_ADD_INFO) = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
/* All long options with arguments */
|
||||
if (options_long_witharg("output", &argc, &argv, &argarg)) {
|
||||
opts.output = argarg;
|
||||
OPTS_OPTION_STR(OPTION_OUTPUT) = argarg;
|
||||
opts_output_wasset = true;
|
||||
} else {
|
||||
con_out("Unknown parameter: %s\n", argv[0]);
|
||||
|
@ -469,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 = util_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 */
|
||||
|
@ -496,30 +520,38 @@ 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;
|
||||
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));
|
||||
|
||||
if (!options_parse(argc, argv)) {
|
||||
util_seed(time(0));
|
||||
|
||||
if (!options_parse(argc, argv, &has_progs_src)) {
|
||||
return usage();
|
||||
}
|
||||
|
||||
if (OPTS_FLAG(TRUE_EMPTY_STRINGS) && OPTS_FLAG(FALSE_EMPTY_STRINGS)) {
|
||||
con_err("-ftrue-empty-strings and -ffalse-empty-strings are mutually exclusive");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* the standard decides which set of operators to use */
|
||||
if (opts.standard == COMPILER_GMQCC) {
|
||||
if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
|
||||
operators = c_operators;
|
||||
operator_count = c_operator_count;
|
||||
} else if (opts.standard == COMPILER_FTEQCC) {
|
||||
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) {
|
||||
|
@ -530,10 +562,10 @@ int main(int argc, char **argv) {
|
|||
operators[operator_count-1].id != opid2(':','?'))
|
||||
{
|
||||
con_err("internal error: operator precedence table wasn't updated correctly!\n");
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
operators_free = true;
|
||||
newops = mem_a(sizeof(operators[0]) * operator_count);
|
||||
newops = (oper_info*)mem_a(sizeof(operators[0]) * operator_count);
|
||||
memcpy(newops, operators, sizeof(operators[0]) * operator_count);
|
||||
memcpy(&newops[operator_count-2], &operators[operator_count-1], sizeof(newops[0]));
|
||||
memcpy(&newops[operator_count-1], &operators[operator_count-2], sizeof(newops[0]));
|
||||
|
@ -542,52 +574,51 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
if (opts.dump) {
|
||||
if (OPTS_OPTION_BOOL(OPTION_DUMP)) {
|
||||
for (itr = 0; itr < COUNT_FLAGS; ++itr)
|
||||
con_out("Flag %s = %i\n", opts_flag_list[itr].name, OPTS_FLAG(itr));
|
||||
for (itr = 0; itr < COUNT_WARNINGS; ++itr)
|
||||
con_out("Warning %s = %i\n", opts_warn_list[itr].name, OPTS_WARN(itr));
|
||||
|
||||
con_out("output = %s\n", opts.output);
|
||||
con_out("optimization level = %d\n", opts.O);
|
||||
con_out("standard = %i\n", opts.standard);
|
||||
|
||||
con_out("output = %s\n", OPTS_OPTION_STR(OPTION_OUTPUT));
|
||||
con_out("optimization level = %u\n", OPTS_OPTION_U32(OPTION_O));
|
||||
con_out("standard = %u\n", OPTS_OPTION_U32(OPTION_STANDARD));
|
||||
}
|
||||
|
||||
if (opts.pp_only) {
|
||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
||||
if (opts_output_wasset) {
|
||||
outfile = util_fopen(opts.output, "wb");
|
||||
outfile = fopen(OPTS_OPTION_STR(OPTION_OUTPUT), "wb");
|
||||
if (!outfile) {
|
||||
con_err("failed to open `%s` for writing\n", opts.output);
|
||||
con_err("failed to open `%s` for writing\n", OPTS_OPTION_STR(OPTION_OUTPUT));
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else
|
||||
outfile = stdout;
|
||||
else {
|
||||
outfile = con_default_out();
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.pp_only) {
|
||||
if (!parser_init()) {
|
||||
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
||||
if (!(parser = parser_create())) {
|
||||
con_err("failed to initialize parser\n");
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.pp_only || OPTS_FLAG(FTEPP)) {
|
||||
if (!ftepp_init()) {
|
||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
|
||||
if (!(ftepp = ftepp_create())) {
|
||||
con_err("failed to initialize parser\n");
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
util_debug("COM", "starting ...\n");
|
||||
|
||||
/* add macros */
|
||||
if (opts.pp_only || OPTS_FLAG(FTEPP)) {
|
||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
|
||||
for (itr = 0; itr < vec_size(ppems); itr++) {
|
||||
ftepp_add_macro(ppems[itr].name, ppems[itr].value);
|
||||
ftepp_add_macro(ftepp, ppems[itr].name, ppems[itr].value);
|
||||
mem_d(ppems[itr].name);
|
||||
|
||||
/* can be null */
|
||||
|
@ -596,56 +627,62 @@ 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 = util_fopen("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.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:
|
||||
fclose(src);
|
||||
mem_d(line);
|
||||
}
|
||||
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
if (vec_size(items)) {
|
||||
if (!opts.pp_only) {
|
||||
con_out("Mode: %s\n", (progs_src ? "progs.src" : "manual"));
|
||||
if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
|
||||
!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
for (itr = 0; itr < vec_size(items); ++itr) {
|
||||
if (!opts.pp_only) {
|
||||
if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
|
||||
!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
|
||||
{
|
||||
con_out(" item: %s (%s)\n",
|
||||
items[itr].filename,
|
||||
( (items[itr].type == TYPE_QC ? "qc" :
|
||||
|
@ -654,80 +691,82 @@ srcdone:
|
|||
("unknown"))))));
|
||||
}
|
||||
|
||||
if (opts.pp_only) {
|
||||
if (items[itr].type == TYPE_SRC) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
||||
const char *out;
|
||||
if (!ftepp_preprocess_file(items[itr].filename)) {
|
||||
if (!ftepp_preprocess_file(ftepp, items[itr].filename)) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
out = ftepp_get();
|
||||
out = ftepp_get(ftepp);
|
||||
if (out)
|
||||
fprintf(outfile, "%s", out);
|
||||
ftepp_flush();
|
||||
ftepp_flush(ftepp);
|
||||
}
|
||||
else {
|
||||
if (OPTS_FLAG(FTEPP)) {
|
||||
const char *data;
|
||||
if (!ftepp_preprocess_file(items[itr].filename)) {
|
||||
if (!ftepp_preprocess_file(ftepp, items[itr].filename)) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
data = ftepp_get();
|
||||
data = ftepp_get(ftepp);
|
||||
if (vec_size(data)) {
|
||||
if (!parser_compile_string_len(items[itr].filename, data, vec_size(data))) {
|
||||
if (!parser_compile_string(parser, items[itr].filename, data, vec_size(data))) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
ftepp_flush();
|
||||
ftepp_flush(ftepp);
|
||||
}
|
||||
else {
|
||||
if (!parser_compile_file(items[itr].filename)) {
|
||||
if (!parser_compile_file(parser, items[itr].filename)) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (progs_src) {
|
||||
if (has_progs_src) {
|
||||
mem_d(items[itr].filename);
|
||||
items[itr].filename = NULL;
|
||||
items[itr].filename = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ftepp_finish();
|
||||
if (!opts.pp_only) {
|
||||
if (!parser_finish(opts.output)) {
|
||||
ftepp_finish(ftepp);
|
||||
ftepp = nullptr;
|
||||
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
||||
if (!parser_finish(parser, OPTS_OPTION_STR(OPTION_OUTPUT))) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* stuff */
|
||||
if (!opts.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");
|
||||
ftepp_finish();
|
||||
if (ftepp)
|
||||
ftepp_finish(ftepp);
|
||||
con_close();
|
||||
vec_free(items);
|
||||
vec_free(ppems);
|
||||
|
||||
if (!opts.pp_only)
|
||||
parser_cleanup();
|
||||
if (opts_output_free)
|
||||
mem_d((char*)opts.output);
|
||||
if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
|
||||
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;
|
||||
}
|
51
misc/check-doc.sh
Executable file
51
misc/check-doc.sh
Executable file
|
@ -0,0 +1,51 @@
|
|||
#!/bin/sh
|
||||
prog=$0
|
||||
|
||||
die() {
|
||||
echo "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
want() {
|
||||
test -e "$1" && return
|
||||
echo "$prog: missing $1"
|
||||
echo "$prog: run this script from the top of a gmqcc source tree"
|
||||
exit 1
|
||||
}
|
||||
|
||||
for i in opts.def \
|
||||
doc/gmqcc.1 \
|
||||
gmqcc.ini.example
|
||||
do want "$i"; done
|
||||
|
||||
# y/_ABCDEFGHIJKLMNOPQRSTUVWXYZ/-abcdefghijklmnopqrstuvwxyz/;
|
||||
check_opt() {
|
||||
opt_def_name=$1
|
||||
arg_char=$2
|
||||
|
||||
for i in $(sed -ne \
|
||||
'/^#ifdef GMQCC_TYPE_'${opt_def_name}'$/,/^#endif/{
|
||||
/GMQCC_DEFINE_FLAG/{
|
||||
s/^.*GMQCC_DEFINE_FLAG(\([^,)]*\)[),].*$/\1/;p;
|
||||
}
|
||||
}' opts.def)
|
||||
do
|
||||
opt=$(echo "$i" | tr -- '_A-Z' '-a-z')
|
||||
grep -qF -- ".It Fl "${arg_char}" Ns Cm $opt" \
|
||||
doc/gmqcc.1 || echo "doc/gmqcc.1: missing: -${arg_char}$opt"
|
||||
grep -q -- "[^a-zA-Z_]$i[^a-zA-Z_]" \
|
||||
gmqcc.ini.example || echo "gmqcc.ini.example: missing: $i"
|
||||
done
|
||||
}
|
||||
|
||||
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
|
|
@ -1,33 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* 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_STR(OPTION_PROGSRC) = "progs.src";
|
||||
|
||||
/* warnings */
|
||||
opts_set(opts.warn, WARN_UNUSED_VARIABLE, true);
|
||||
opts_set(opts.warn, WARN_USED_UNINITIALIZED, true);
|
||||
|
@ -35,8 +45,7 @@ static void opts_setdefault() {
|
|||
opts_set(opts.warn, WARN_EXTENSIONS, true);
|
||||
opts_set(opts.warn, WARN_FIELD_REDECLARED, true);
|
||||
opts_set(opts.warn, WARN_MISSING_RETURN_VALUES, true);
|
||||
opts_set(opts.warn, WARN_TOO_FEW_PARAMETERS, true);
|
||||
opts_set(opts.warn, WARN_LOCAL_SHADOWS, false);
|
||||
opts_set(opts.warn, WARN_INVALID_PARAMETER_COUNT, true);
|
||||
opts_set(opts.warn, WARN_LOCAL_CONSTANTS, true);
|
||||
opts_set(opts.warn, WARN_VOID_VARIABLES, true);
|
||||
opts_set(opts.warn, WARN_IMPLICIT_FUNCTION_POINTER, true);
|
||||
|
@ -45,44 +54,78 @@ static void opts_setdefault() {
|
|||
opts_set(opts.warn, WARN_EFFECTLESS_STATEMENT, true);
|
||||
opts_set(opts.warn, WARN_END_SYS_FIELDS, true);
|
||||
opts_set(opts.warn, WARN_ASSIGN_FUNCTION_TYPES, true);
|
||||
opts_set(opts.warn, WARN_PREPROCESSOR, true);
|
||||
opts_set(opts.warn, WARN_CPP, true);
|
||||
opts_set(opts.warn, WARN_MULTIFILE_IF, true);
|
||||
opts_set(opts.warn, WARN_DOUBLE_DECLARATION, true);
|
||||
opts_set(opts.warn, WARN_CONST_VAR, true);
|
||||
opts_set(opts.warn, WARN_MULTIBYTE_CHARACTER, true);
|
||||
opts_set(opts.warn, WARN_UNKNOWN_PRAGMAS, true);
|
||||
opts_set(opts.warn, WARN_UNREACHABLE_CODE, true);
|
||||
opts_set(opts.warn, WARN_UNKNOWN_ATTRIBUTE, true);
|
||||
opts_set(opts.warn, WARN_RESERVED_NAMES, true);
|
||||
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);
|
||||
opts_set(opts.flags, FTEPP, false);
|
||||
opts_set(opts.flags, CORRECT_TERNARY, true);
|
||||
opts_set(opts.flags, BAIL_ON_WERROR, true);
|
||||
opts_set(opts.flags, LEGACY_VECTOR_MATHS, true);
|
||||
opts_set(opts.flags, DARKPLACES_STRING_TABLE_BUG, true);
|
||||
|
||||
/* options */
|
||||
OPTS_OPTION_U32(OPTION_STATE_FPS) = 10;
|
||||
}
|
||||
|
||||
void opts_backup_non_Wall() {
|
||||
size_t i;
|
||||
for (i = 0; i <= WARN_DEBUG; ++i)
|
||||
opts_set(opts.warn_backup, i, OPTS_WARN(i));
|
||||
}
|
||||
|
||||
void opts_restore_non_Wall() {
|
||||
size_t i;
|
||||
for (i = 0; i <= WARN_DEBUG; ++i)
|
||||
opts_set(opts.warn, i, OPTS_GENERIC(opts.warn_backup, i));
|
||||
}
|
||||
|
||||
void opts_backup_non_Werror_all() {
|
||||
size_t i;
|
||||
for (i = 0; i <= WARN_DEBUG; ++i)
|
||||
opts_set(opts.werror_backup, i, OPTS_WERROR(i));
|
||||
}
|
||||
|
||||
void opts_restore_non_Werror_all() {
|
||||
size_t i;
|
||||
for (i = 0; i <= WARN_DEBUG; ++i)
|
||||
opts_set(opts.werror, i, OPTS_GENERIC(opts.werror_backup, i));
|
||||
}
|
||||
|
||||
void opts_init(const char *output, int standard, size_t arraysize) {
|
||||
opts_setdefault();
|
||||
|
||||
opts.output = output;
|
||||
opts.standard = standard;
|
||||
opts.max_array_size = arraysize;
|
||||
|
||||
OPTS_OPTION_STR(OPTION_OUTPUT) = output;
|
||||
OPTS_OPTION_U32(OPTION_STANDARD) = standard;
|
||||
OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE) = arraysize;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!strcmp(name, list[i].name)) {
|
||||
longbit lb = list[i].bit;
|
||||
#if 0
|
||||
|
||||
if (on)
|
||||
flags[lb.idx] |= (1<<(lb.bit));
|
||||
else
|
||||
flags[lb.idx] &= ~(1<<(lb.bit));
|
||||
#else
|
||||
if (on)
|
||||
flags[0] |= (1<<lb);
|
||||
else
|
||||
flags[0] &= ~(1<<(lb));
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -102,24 +145,22 @@ bool opts_setoptim (const char *name, bool on) {
|
|||
}
|
||||
|
||||
void opts_set(uint32_t *flags, size_t idx, bool on) {
|
||||
longbit lb = LONGBIT(idx);
|
||||
#if 0
|
||||
longbit lb;
|
||||
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));
|
||||
#else
|
||||
if (on)
|
||||
flags[0] |= (1<<(lb));
|
||||
else
|
||||
flags[0] &= ~(1<<(lb));
|
||||
#endif
|
||||
flags[lb.idx] &= ~(1u<<(lb.bit));
|
||||
}
|
||||
|
||||
void opts_setoptimlevel(unsigned int level) {
|
||||
size_t i;
|
||||
for (i = 0; i < COUNT_OPTIMIZATIONS; ++i)
|
||||
opts_set(opts.optimization, i, level >= opts_opt_oflag[i]);
|
||||
|
||||
if (!level)
|
||||
opts.optimizeoff = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -130,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;
|
||||
}
|
||||
|
@ -145,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] = "";
|
||||
|
||||
|
@ -189,7 +231,7 @@ static size_t opts_ini_parse (
|
|||
/* section found */
|
||||
if (*(parse_end = opts_ini_next(parse_beg + 1, ']')) == ']') {
|
||||
* parse_end = '\0'; /* terminate bro */
|
||||
strncpy(section_data, parse_beg + 1, sizeof(section_data));
|
||||
util_strncpy(section_data, parse_beg + 1, sizeof(section_data));
|
||||
section_data[sizeof(section_data) - 1] = '\0';
|
||||
*oldname_data = '\0';
|
||||
} else if (!error) {
|
||||
|
@ -199,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 */
|
||||
|
@ -210,11 +252,23 @@ static size_t opts_ini_parse (
|
|||
opts_ini_rstrip(read_value);
|
||||
|
||||
/* valid name value pair, lets call down to handler */
|
||||
strncpy(oldname_data, read_name, sizeof(oldname_data));
|
||||
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;
|
||||
|
@ -224,6 +278,7 @@ static size_t opts_ini_parse (
|
|||
}
|
||||
mem_d(line);
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -232,21 +287,41 @@ static size_t opts_ini_parse (
|
|||
static bool opts_ini_bool(const char *value) {
|
||||
if (!strcmp(value, "true")) return true;
|
||||
if (!strcmp(value, "false")) return false;
|
||||
return !!atoi(value);
|
||||
return !!strtol(value, 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;
|
||||
|
||||
/*
|
||||
* undef all of these because they may still be defined like in my
|
||||
* case they where.
|
||||
*/
|
||||
*/
|
||||
#undef GMQCC_TYPE_FLAGS
|
||||
#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) \
|
||||
|
@ -265,6 +340,15 @@ static char *opts_ini_load(const char *section, const char *name, const char *va
|
|||
}
|
||||
#include "opts.def"
|
||||
|
||||
/* Werror-individuals */
|
||||
#define GMQCC_TYPE_WARNS
|
||||
#define GMQCC_DEFINE_FLAG(X) \
|
||||
if (!strcmp(section, "errors") && !strcmp(name, #X)) { \
|
||||
opts_set(opts.werror, WARN_##X, opts_ini_bool(value)); \
|
||||
found = true; \
|
||||
}
|
||||
#include "opts.def"
|
||||
|
||||
/* optimizations */
|
||||
#define GMQCC_TYPE_OPTIMIZATIONS
|
||||
#define GMQCC_DEFINE_FLAG(X,Y) \
|
||||
|
@ -276,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;
|
||||
}
|
||||
|
||||
|
@ -307,11 +396,11 @@ 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 = fopen((file = "gmqcc.ini"), "r")))
|
||||
|
@ -323,11 +412,13 @@ void opts_ini_init(const char *file) {
|
|||
|
||||
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);
|
||||
|
||||
fclose(ini);
|
||||
}
|
||||
}
|
104
opts.def
104
opts.def
|
@ -1,36 +1,15 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* 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
|
||||
# define GMQCC_DEFINE_FLAG(x)
|
||||
# error "bad opts.def usage"
|
||||
#endif
|
||||
|
||||
/* codegen flags */
|
||||
#ifdef GMQCC_TYPE_FLAGS
|
||||
GMQCC_DEFINE_FLAG(OVERLAP_LOCALS)
|
||||
GMQCC_DEFINE_FLAG(DARKPLACES_STRING_TABLE_BUG)
|
||||
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)
|
||||
|
@ -40,18 +19,39 @@
|
|||
GMQCC_DEFINE_FLAG(LNO)
|
||||
GMQCC_DEFINE_FLAG(CORRECT_TERNARY)
|
||||
GMQCC_DEFINE_FLAG(SINGLE_VECTOR_DEFS)
|
||||
GMQCC_DEFINE_FLAG(CORRECT_LOGIC)
|
||||
GMQCC_DEFINE_FLAG(TRUE_EMPTY_STRINGS)
|
||||
GMQCC_DEFINE_FLAG(FALSE_EMPTY_STRINGS)
|
||||
GMQCC_DEFINE_FLAG(UTF8)
|
||||
GMQCC_DEFINE_FLAG(BAIL_ON_WERROR)
|
||||
GMQCC_DEFINE_FLAG(LOOP_LABELS)
|
||||
GMQCC_DEFINE_FLAG(UNTYPED_NIL)
|
||||
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 */
|
||||
#ifdef GMQCC_TYPE_WARNS
|
||||
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)
|
||||
GMQCC_DEFINE_FLAG(FIELD_REDECLARED)
|
||||
GMQCC_DEFINE_FLAG(MISSING_RETURN_VALUES)
|
||||
GMQCC_DEFINE_FLAG(TOO_FEW_PARAMETERS)
|
||||
GMQCC_DEFINE_FLAG(INVALID_PARAMETER_COUNT)
|
||||
GMQCC_DEFINE_FLAG(LOCAL_SHADOWS)
|
||||
GMQCC_DEFINE_FLAG(LOCAL_CONSTANTS)
|
||||
GMQCC_DEFINE_FLAG(VOID_VARIABLES)
|
||||
|
@ -61,7 +61,7 @@
|
|||
GMQCC_DEFINE_FLAG(EFFECTLESS_STATEMENT)
|
||||
GMQCC_DEFINE_FLAG(END_SYS_FIELDS)
|
||||
GMQCC_DEFINE_FLAG(ASSIGN_FUNCTION_TYPES)
|
||||
GMQCC_DEFINE_FLAG(PREPROCESSOR)
|
||||
GMQCC_DEFINE_FLAG(CPP)
|
||||
GMQCC_DEFINE_FLAG(MULTIFILE_IF)
|
||||
GMQCC_DEFINE_FLAG(DOUBLE_DECLARATION)
|
||||
GMQCC_DEFINE_FLAG(CONST_VAR)
|
||||
|
@ -69,16 +69,58 @@
|
|||
GMQCC_DEFINE_FLAG(TERNARY_PRECEDENCE)
|
||||
GMQCC_DEFINE_FLAG(UNKNOWN_PRAGMAS)
|
||||
GMQCC_DEFINE_FLAG(UNREACHABLE_CODE)
|
||||
GMQCC_DEFINE_FLAG(UNKNOWN_ATTRIBUTE)
|
||||
GMQCC_DEFINE_FLAG(RESERVED_NAMES)
|
||||
GMQCC_DEFINE_FLAG(UNINITIALIZED_CONSTANT)
|
||||
GMQCC_DEFINE_FLAG(DIFFERENT_QUALIFIERS)
|
||||
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
|
||||
GMQCC_DEFINE_FLAG(PEEPHOLE, 1)
|
||||
GMQCC_DEFINE_FLAG(LOCALTEMPS, 1)
|
||||
GMQCC_DEFINE_FLAG(TAIL_RECURSION, 1)
|
||||
GMQCC_DEFINE_FLAG(TAIL_CALLS, 2)
|
||||
GMQCC_DEFINE_FLAG(PEEPHOLE, 1)
|
||||
GMQCC_DEFINE_FLAG(TAIL_RECURSION, 1)
|
||||
GMQCC_DEFINE_FLAG(OVERLAP_LOCALS, 3)
|
||||
GMQCC_DEFINE_FLAG(LOCAL_TEMPS, 3)
|
||||
GMQCC_DEFINE_FLAG(GLOBAL_TEMPS, 3)
|
||||
GMQCC_DEFINE_FLAG(STRIP_CONSTANT_NAMES, 1)
|
||||
GMQCC_DEFINE_FLAG(OVERLAP_STRINGS, 2)
|
||||
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
|
||||
GMQCC_DEFINE_FLAG(O)
|
||||
GMQCC_DEFINE_FLAG(OUTPUT)
|
||||
GMQCC_DEFINE_FLAG(QUIET)
|
||||
GMQCC_DEFINE_FLAG(G)
|
||||
GMQCC_DEFINE_FLAG(STANDARD)
|
||||
GMQCC_DEFINE_FLAG(DEBUG)
|
||||
GMQCC_DEFINE_FLAG(DUMPFIN)
|
||||
GMQCC_DEFINE_FLAG(DUMP)
|
||||
GMQCC_DEFINE_FLAG(FORCECRC)
|
||||
GMQCC_DEFINE_FLAG(FORCED_CRC)
|
||||
GMQCC_DEFINE_FLAG(PP_ONLY)
|
||||
GMQCC_DEFINE_FLAG(MAX_ARRAY_SIZE)
|
||||
GMQCC_DEFINE_FLAG(ADD_INFO)
|
||||
GMQCC_DEFINE_FLAG(PROGSRC)
|
||||
GMQCC_DEFINE_FLAG(COVERAGE)
|
||||
GMQCC_DEFINE_FLAG(STATE_FPS)
|
||||
#endif
|
||||
|
||||
/* some cleanup so we don't have to */
|
||||
#undef GMQCC_TYPE_FLAGS
|
||||
#undef GMQCC_TYPE_WARNS
|
||||
#undef GMQCC_TYPE_OPTIONS
|
||||
#undef GMQCC_TYPE_OPTIMIZATIONS
|
||||
#undef GMQCC_DEFINE_FLAG
|
||||
|
|
6416
parser.cpp
Normal file
6416
parser.cpp
Normal file
File diff suppressed because it is too large
Load diff
84
parser.h
Normal file
84
parser.h
Normal 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
250
stat.cpp
Normal 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);
|
||||
}
|
18
tests/accumulate.qc
Normal file
18
tests/accumulate.qc
Normal 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
5
tests/accumulate.tmpl
Normal file
|
@ -0,0 +1,5 @@
|
|||
I: accumulate.qc
|
||||
D: test function accumulation
|
||||
T: -execute
|
||||
C: -std=gmqcc -fftepp
|
||||
M: hello accumulation world
|
34
tests/aliases.qc
Normal file
34
tests/aliases.qc
Normal file
|
@ -0,0 +1,34 @@
|
|||
float alias_1 = 3.14;
|
||||
void alias_2() {
|
||||
print("alias_2\n");
|
||||
}
|
||||
|
||||
[[alias("alias_2")]] void alias_2_aliased();
|
||||
[[alias("alias_1")]] float alias_1_aliased;
|
||||
|
||||
|
||||
// alias to an alias?
|
||||
vector alias_3;
|
||||
[[alias("alias_3")]] vector alias_3_aliased;
|
||||
|
||||
// expected output
|
||||
// alias_2
|
||||
// 3.14
|
||||
void main() {
|
||||
alias_2_aliased();
|
||||
|
||||
alias_3_aliased= '1 2 3';
|
||||
|
||||
print(
|
||||
ftos(
|
||||
alias_1_aliased
|
||||
),
|
||||
"\n"
|
||||
);
|
||||
|
||||
print(
|
||||
"x ", ftos(alias_3_aliased_x), "\n",
|
||||
"y ", ftos(alias_3_aliased_y), "\n",
|
||||
"z ", ftos(alias_3_aliased_z), "\n"
|
||||
);
|
||||
}
|
9
tests/aliases.tmpl
Normal file
9
tests/aliases.tmpl
Normal file
|
@ -0,0 +1,9 @@
|
|||
I: aliases.qc
|
||||
D: test aliases
|
||||
T: -execute
|
||||
C: -std=gmqcc
|
||||
M: alias_2
|
||||
M: 3.14
|
||||
M: x 1
|
||||
M: y 2
|
||||
M: z 3
|
13
tests/arithexcept.qc
Normal file
13
tests/arithexcept.qc
Normal 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
4
tests/arithexcept.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: arithexcept.qc
|
||||
D: arithmetic exceptions (divide by zero)
|
||||
T: -fail
|
||||
C: -std=fteqcc -farithmetic-exceptions -DDIVBYZERO
|
4
tests/arithexcept_of.tmpl
Normal file
4
tests/arithexcept_of.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: arithexcept.qc
|
||||
D: arithmetic exceptions (overflow)
|
||||
T: -fail
|
||||
C: -std=fteqcc -farithmetic-exceptions -DOVERFLOW
|
4
tests/arithexcept_uf.tmpl
Normal file
4
tests/arithexcept_uf.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: arithexcept.qc
|
||||
D: arithmetic exceptions (underflow)
|
||||
T: -fail
|
||||
C: -std=fteqcc -farithmetic-exceptions -DUNDERFLOW
|
|
@ -1,7 +1,3 @@
|
|||
void print(...) = #1;
|
||||
string ftos (float) = #2;
|
||||
entity() spawn = #3;
|
||||
|
||||
float glob[7];
|
||||
|
||||
.float above;
|
||||
|
|
|
@ -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
18
tests/arrays2.qc
Normal 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
7
tests/arrays2.tmpl
Normal 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
|
37
tests/bitnot.qc
Normal file
37
tests/bitnot.qc
Normal file
|
@ -0,0 +1,37 @@
|
|||
void main() {
|
||||
float a; a = 1;
|
||||
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");
|
||||
}
|
11
tests/bitnot.tmpl
Normal file
11
tests/bitnot.tmpl
Normal file
|
@ -0,0 +1,11 @@
|
|||
# used to test the builtins
|
||||
I: bitnot.qc
|
||||
D: test bitwise not operators (fteqcc operators)
|
||||
T: -execute
|
||||
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
11
tests/bitnotgmqcc.tmpl
Normal 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'
|
|
@ -1,6 +1,3 @@
|
|||
void print(...) = #1;
|
||||
string ftos (float) = #2;
|
||||
|
||||
void test(float brkat, float contat) {
|
||||
float i;
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
void(string) print = #1;
|
||||
|
||||
void() main = {
|
||||
print("hello world");
|
||||
}
|
||||
|
|
|
@ -4,6 +4,4 @@ D: test builtin functions
|
|||
T: -execute
|
||||
C: -std=gmqcc
|
||||
E: $null
|
||||
F: builtins failed
|
||||
S: builtins worked
|
||||
M: hello world
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
void(string, ...) print = #1;
|
||||
string(float) ftos = #2;
|
||||
|
||||
float(float x, float y, float z) sum = {
|
||||
return x + y + z;
|
||||
};
|
||||
|
@ -11,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");
|
||||
|
||||
|
||||
};
|
||||
|
|
|
@ -3,6 +3,4 @@ D: test calls
|
|||
T: -execute
|
||||
C: -std=gmqcc
|
||||
E: -float 100 -float 200 -float 300
|
||||
F: calls failed
|
||||
S: calls worked
|
||||
M: 4600
|
||||
|
|
12
tests/correct-logic-1-s.tmpl
Normal file
12
tests/correct-logic-1-s.tmpl
Normal file
|
@ -0,0 +1,12 @@
|
|||
I: correct-logic.qc
|
||||
D: vector logic flags
|
||||
T: -execute
|
||||
C: -std=fteqcc -fshort-logic
|
||||
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
|
||||
M: x, x -> 0 1 1 1 0
|
||||
M: 0, y -> 1 0 0 0 1
|
||||
M: y, 0 -> 0 0 0 0 1
|
||||
M: y, y -> 0 0 0 0 1
|
12
tests/correct-logic-1.tmpl
Normal file
12
tests/correct-logic-1.tmpl
Normal file
|
@ -0,0 +1,12 @@
|
|||
I: correct-logic.qc
|
||||
D: vector logic flags
|
||||
T: -execute
|
||||
C: -std=fteqcc
|
||||
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
|
||||
M: x, x -> 0 1 1 1 0
|
||||
M: 0, y -> 1 0 0 0 1
|
||||
M: y, 0 -> 0 0 0 0 1
|
||||
M: y, y -> 0 0 0 0 1
|
12
tests/correct-logic-2-s.tmpl
Normal file
12
tests/correct-logic-2-s.tmpl
Normal file
|
@ -0,0 +1,12 @@
|
|||
I: correct-logic.qc
|
||||
D: vector logic flags
|
||||
T: -execute
|
||||
C: -std=fteqcc -fcorrect-logic -fshort-logic
|
||||
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
|
||||
M: x, x -> 0 1 1 1 0
|
||||
M: 0, y -> 1 0 1 0 1
|
||||
M: y, 0 -> 0 0 1 1 0
|
||||
M: y, y -> 0 1 1 1 0
|
12
tests/correct-logic-2.tmpl
Normal file
12
tests/correct-logic-2.tmpl
Normal file
|
@ -0,0 +1,12 @@
|
|||
I: correct-logic.qc
|
||||
D: vector logic flags
|
||||
T: -execute
|
||||
C: -std=fteqcc -fcorrect-logic
|
||||
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
|
||||
M: x, x -> 0 1 1 1 0
|
||||
M: 0, y -> 1 0 1 0 1
|
||||
M: y, 0 -> 0 0 1 1 0
|
||||
M: y, y -> 0 1 1 1 0
|
24
tests/correct-logic.qc
Normal file
24
tests/correct-logic.qc
Normal file
|
@ -0,0 +1,24 @@
|
|||
float test_s_not (vector s) { return !s; }
|
||||
float test_s_and (vector s, vector t) { return s && t; }
|
||||
float test_s_or (vector s, vector t) { return s || t; }
|
||||
float test_s_if (vector s) { if (s) return 1; return 0; }
|
||||
float test_s_ifnot(vector s) { if not (s) return 1; return 0; }
|
||||
|
||||
void test(vector s, vector t) {
|
||||
print(ftos(!!test_s_not (s)), " ");
|
||||
print(ftos(!!test_s_and (s, t)), " ");
|
||||
print(ftos(!!test_s_or (s, t)), " ");
|
||||
print(ftos(!!test_s_if (s)), " ");
|
||||
print(ftos(!!test_s_ifnot(s)), "\n");
|
||||
}
|
||||
|
||||
void main() {
|
||||
print(" ! & | i N\n");
|
||||
print("0, 0 -> "); test('0 0 0', '0 0 0');
|
||||
print("0, x -> "); test('0 0 0', '1 0 0');
|
||||
print("x, 0 -> "); test('1 0 0', '0 0 0');
|
||||
print("x, x -> "); test('1 0 0', '1 0 0');
|
||||
print("0, y -> "); test('0 0 0', '0 1 0');
|
||||
print("y, 0 -> "); test('0 1 0', '0 0 0');
|
||||
print("y, y -> "); test('0 1 0', '0 1 0');
|
||||
}
|
14
tests/correct-vs-short-1.tmpl
Normal file
14
tests/correct-vs-short-1.tmpl
Normal file
|
@ -0,0 +1,14 @@
|
|||
I: correct-vs-short.qc
|
||||
D: correct-logic vs short-logic without perl-logic
|
||||
T: -execute
|
||||
C: -std=fteqcc
|
||||
M: X & | B
|
||||
M: 0 0 0, 0 0 0 :: 0 0 0
|
||||
M: 0 0 0, 5 0 0 :: 0 2 1
|
||||
M: 5 0 0, 0 0 0 :: 0 2 1
|
||||
M: 5 0 0, 5 0 0 :: 2 2 2
|
||||
M: Y & | B
|
||||
M: 0 0 0, 0 0 0 :: 0 0 0
|
||||
M: 0 0 0, 0 5 0 :: 0 0 0
|
||||
M: 0 5 0, 0 0 0 :: 0 0 0
|
||||
M: 0 5 0, 0 5 0 :: 0 0 0
|
14
tests/correct-vs-short-2.tmpl
Normal file
14
tests/correct-vs-short-2.tmpl
Normal file
|
@ -0,0 +1,14 @@
|
|||
I: correct-vs-short.qc
|
||||
D: correct-logic vs short-logic without perl-logic
|
||||
T: -execute
|
||||
C: -std=fteqcc -fcorrect-logic
|
||||
M: X & | B
|
||||
M: 0 0 0, 0 0 0 :: 0 0 0
|
||||
M: 0 0 0, 5 0 0 :: 0 2 1
|
||||
M: 5 0 0, 0 0 0 :: 0 2 1
|
||||
M: 5 0 0, 5 0 0 :: 2 2 2
|
||||
M: Y & | B
|
||||
M: 0 0 0, 0 0 0 :: 0 0 0
|
||||
M: 0 0 0, 0 5 0 :: 0 2 1
|
||||
M: 0 5 0, 0 0 0 :: 0 2 1
|
||||
M: 0 5 0, 0 5 0 :: 2 2 2
|
14
tests/correct-vs-short-3.tmpl
Normal file
14
tests/correct-vs-short-3.tmpl
Normal file
|
@ -0,0 +1,14 @@
|
|||
I: correct-vs-short.qc
|
||||
D: correct-logic vs short-logic without perl-logic
|
||||
T: -execute
|
||||
C: -std=fteqcc -fcorrect-logic -fshort-logic
|
||||
M: X & | B
|
||||
M: 0 0 0, 0 0 0 :: 0 0 0
|
||||
M: 0 0 0, 5 0 0 :: 0 2 1
|
||||
M: 5 0 0, 0 0 0 :: 0 2 1
|
||||
M: 5 0 0, 5 0 0 :: 2 2 2
|
||||
M: Y & | B
|
||||
M: 0 0 0, 0 0 0 :: 0 0 0
|
||||
M: 0 0 0, 0 5 0 :: 0 2 1
|
||||
M: 0 5 0, 0 0 0 :: 0 2 1
|
||||
M: 0 5 0, 0 5 0 :: 2 2 2
|
18
tests/correct-vs-short.qc
Normal file
18
tests/correct-vs-short.qc
Normal file
|
@ -0,0 +1,18 @@
|
|||
void test(vector a, vector b) {
|
||||
print(ftos((a && b) + (a && b)), " ");
|
||||
print(ftos((a || b) + (a || b)), " ");
|
||||
print(ftos((a && b) + (a || b)), "\n");
|
||||
}
|
||||
|
||||
void main() {
|
||||
print("X & | B\n");
|
||||
print("0 0 0, 0 0 0 :: "); test('0 0 0', '0 0 0');
|
||||
print("0 0 0, 5 0 0 :: "); test('0 0 0', '5 0 0');
|
||||
print("5 0 0, 0 0 0 :: "); test('5 0 0', '0 0 0');
|
||||
print("5 0 0, 5 0 0 :: "); test('5 0 0', '5 0 0');
|
||||
print("Y & | B\n");
|
||||
print("0 0 0, 0 0 0 :: "); test('0 0 0', '0 0 0');
|
||||
print("0 0 0, 0 5 0 :: "); test('0 0 0', '0 5 0');
|
||||
print("0 5 0, 0 0 0 :: "); test('0 5 0', '0 0 0');
|
||||
print("0 5 0, 0 5 0 :: "); test('0 5 0', '0 5 0');
|
||||
}
|
21
tests/defs.qh
Normal file
21
tests/defs.qh
Normal file
|
@ -0,0 +1,21 @@
|
|||
// builtins for the standalone qcvm included with gmqcc
|
||||
// in exec.c These should be updated to reflect the new
|
||||
// builtins. I no event shall you even consider adding
|
||||
// these individually per test.
|
||||
|
||||
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
27
tests/dots.qc
Normal 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
8
tests/dots.tmpl
Normal 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
|
68
tests/enum.qc
Normal file
68
tests/enum.qc
Normal file
|
@ -0,0 +1,68 @@
|
|||
enum {
|
||||
// this behaviour is confusing, but I like that
|
||||
// we support it.
|
||||
__ = (__ - 1),
|
||||
A = (__ + 1),
|
||||
|
||||
B,
|
||||
C
|
||||
};
|
||||
|
||||
enum {
|
||||
D = C + B,
|
||||
E = C + C,
|
||||
F = C + D,
|
||||
};
|
||||
|
||||
enum {
|
||||
G = (B + F), H = (C + F),
|
||||
I = (D + F), J = (B + I)
|
||||
};
|
||||
enum {
|
||||
K = A + B - C + D - E + F *
|
||||
G - H + I - J + A - B -
|
||||
J + A,
|
||||
L,
|
||||
M,
|
||||
N
|
||||
};
|
||||
|
||||
enum : flag {
|
||||
F1, /* = 1 << 1 */
|
||||
F2, /* = 1 << 2 */
|
||||
F3 /* = 1 << 3 */
|
||||
};
|
||||
|
||||
/* reversed enumeration */
|
||||
enum : reverse {
|
||||
R1, // 3
|
||||
R2, // 2
|
||||
R3, // 1
|
||||
R4 // 0
|
||||
};
|
||||
|
||||
void main() {
|
||||
print(ftos(A), "\n");
|
||||
print(ftos(B), "\n");
|
||||
print(ftos(C), "\n");
|
||||
print(ftos(D), "\n");
|
||||
print(ftos(E), "\n");
|
||||
print(ftos(F), "\n");
|
||||
print(ftos(G), "\n");
|
||||
print(ftos(H), "\n");
|
||||
print(ftos(I), "\n");
|
||||
print(ftos(J), "\n");
|
||||
print(ftos(K), "\n");
|
||||
print(ftos(L), "\n");
|
||||
print(ftos(M), "\n");
|
||||
print(ftos(N), "\n");
|
||||
|
||||
print(ftos(F1), "\n");
|
||||
print(ftos(F2), "\n");
|
||||
print(ftos(F3), "\n");
|
||||
|
||||
print(ftos(R1), "\n");
|
||||
print(ftos(R2), "\n");
|
||||
print(ftos(R3), "\n");
|
||||
print(ftos(R4), "\n");
|
||||
};
|
25
tests/enum.tmpl
Normal file
25
tests/enum.tmpl
Normal file
|
@ -0,0 +1,25 @@
|
|||
I: enum.qc
|
||||
D: enumerations
|
||||
T: -execute
|
||||
C: -std=fteqcc
|
||||
M: 0
|
||||
M: 1
|
||||
M: 2
|
||||
M: 3
|
||||
M: 4
|
||||
M: 5
|
||||
M: 6
|
||||
M: 7
|
||||
M: 8
|
||||
M: 9
|
||||
M: 10
|
||||
M: 11
|
||||
M: 12
|
||||
M: 13
|
||||
M: 2
|
||||
M: 4
|
||||
M: 8
|
||||
M: 3
|
||||
M: 2
|
||||
M: 1
|
||||
M: 0
|
|
@ -1,6 +1,3 @@
|
|||
void(string, ...) print = #1;
|
||||
string(float) ftos = #2;
|
||||
|
||||
void(float a, float b) main = {
|
||||
if (a == b) print("eq,");
|
||||
if (a != b) print("ne,");
|
||||
|
|
|
@ -3,6 +3,4 @@ D: test equality
|
|||
T: -execute
|
||||
C: -std=gmqcc
|
||||
E: -float 100 -float 200
|
||||
F: equality failed
|
||||
S: equality worked
|
||||
M: ne,lt,le,
|
||||
|
|
14
tests/exponentiation.qc
Normal file
14
tests/exponentiation.qc
Normal file
|
@ -0,0 +1,14 @@
|
|||
void main() {
|
||||
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
|
||||
}
|
11
tests/exponentiation.tmpl
Normal file
11
tests/exponentiation.tmpl
Normal file
|
@ -0,0 +1,11 @@
|
|||
# used to test the builtins
|
||||
I: exponentiation.qc
|
||||
D: test exponentiation operator and __builtin_pow
|
||||
T: -execute
|
||||
C: -std=gmqcc
|
||||
E: $null
|
||||
M: 100
|
||||
M: 100
|
||||
M: 100
|
||||
M: 100
|
||||
M: 22026.5
|
7
tests/exprforbuiltins.qc
Normal file
7
tests/exprforbuiltins.qc
Normal file
|
@ -0,0 +1,7 @@
|
|||
/* empty line required */
|
||||
void print(string, ...) = #__LINE__ - 1;
|
||||
|
||||
|
||||
void main(string input) {
|
||||
print(input, "\n");
|
||||
}
|
7
tests/exprforbuiltins.tmpl
Normal file
7
tests/exprforbuiltins.tmpl
Normal 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
|
13
tests/fieldfuncs.qc
Normal file
13
tests/fieldfuncs.qc
Normal file
|
@ -0,0 +1,13 @@
|
|||
.float field;
|
||||
|
||||
.float getfield() {
|
||||
return field;
|
||||
}
|
||||
|
||||
void() main = {
|
||||
entity e = spawn();
|
||||
e.field = 42;
|
||||
print(ftos(e.(getfield())), "\n");
|
||||
.float memptr = getfield();
|
||||
print(ftos(e.memptr), "\n");
|
||||
}
|
6
tests/fieldfuncs.tmpl
Normal file
6
tests/fieldfuncs.tmpl
Normal file
|
@ -0,0 +1,6 @@
|
|||
I: fieldfuncs.qc
|
||||
D: test fields with functions
|
||||
T: -execute
|
||||
C: -std=fte
|
||||
M: 42
|
||||
M: 42
|
|
@ -1,6 +1,3 @@
|
|||
void(string, string) print = #1;
|
||||
entity() spawn = #3;
|
||||
|
||||
.string a;
|
||||
.string b;
|
||||
..string ps;
|
||||
|
|
|
@ -3,7 +3,5 @@ D: test field paramaters
|
|||
T: -execute
|
||||
C: -std=qcc
|
||||
E: $null
|
||||
F: field paramaters fail
|
||||
S: field paramaters work
|
||||
M: bar
|
||||
M: foo
|
||||
|
|
13
tests/forloop.qc
Normal file
13
tests/forloop.qc
Normal file
|
@ -0,0 +1,13 @@
|
|||
void main() {
|
||||
float j;
|
||||
for (j = 0; j < 2; ++j)
|
||||
print("+");
|
||||
|
||||
for (float i = 0; i < 5; ++i)
|
||||
print("*");
|
||||
|
||||
for (;;) {
|
||||
print("\n");
|
||||
break;
|
||||
}
|
||||
}
|
5
tests/forloop.tmpl
Normal file
5
tests/forloop.tmpl
Normal file
|
@ -0,0 +1,5 @@
|
|||
I: forloop.qc
|
||||
D: test for loops
|
||||
T: -execute
|
||||
C: -std=gmqcc
|
||||
M: ++*****
|
20
tests/framemacro.qc
Normal file
20
tests/framemacro.qc
Normal file
|
@ -0,0 +1,20 @@
|
|||
$frame frame1 frame2
|
||||
|
||||
float time;
|
||||
entity self;
|
||||
.float frame;
|
||||
.float nextthink;
|
||||
.void() think;
|
||||
|
||||
// Mixing syntax, = is optional.
|
||||
void frame1_func_mixed_no_assign() [$frame1, frame2_func_mixed_no_assign] {}
|
||||
void frame2_func_mixed_no_assign() [$frame2, frame2_func_mixed_no_assign] {}
|
||||
|
||||
void frame1_func_mixed() =[$frame1, frame2_func_mixed] {}
|
||||
void frame2_func_mixed() =[$frame2, frame2_func_mixed] {}
|
||||
|
||||
void() frame1_func_old =[$frame1, frame2_func_old] {}
|
||||
void() frame2_func_old =[$frame2, frame2_func_old] {}
|
||||
|
||||
|
||||
|
4
tests/framemacro.tmpl
Normal file
4
tests/framemacro.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: framemacro.qc
|
||||
D: test frame macros
|
||||
T: -compile
|
||||
C: -std=gmqcc
|
|
@ -1,5 +1,3 @@
|
|||
void(string, string) print = #1;
|
||||
|
||||
string() getter = {
|
||||
return "correct";
|
||||
};
|
||||
|
|
|
@ -3,6 +3,4 @@ D: test functions as paramaters
|
|||
T: -execute
|
||||
C: -std=gmqcc
|
||||
E: $null
|
||||
F: functions as paramaters failed
|
||||
S: functions as paramaters passed
|
||||
M: correct
|
||||
|
|
32
tests/goto.qc
Normal file
32
tests/goto.qc
Normal file
|
@ -0,0 +1,32 @@
|
|||
// correct execution order:
|
||||
// label_3
|
||||
// label_2
|
||||
// label_4
|
||||
// label_3
|
||||
// label_1
|
||||
// label_5
|
||||
void main() {
|
||||
float x = 1;
|
||||
float y = 2;
|
||||
|
||||
goto label_3;
|
||||
|
||||
:label_1; print("label_1", "\n"); goto label_5;
|
||||
:label_2; print("label_2", "\n"); goto label_4;
|
||||
:label_3; print("label_3", "\n");
|
||||
|
||||
// will goto label_2
|
||||
goto (x == y) ? label_1 : label_2;
|
||||
|
||||
:label_4; print("label_4", "\n");
|
||||
{
|
||||
x = 1;
|
||||
y = 1;
|
||||
|
||||
// will goto label_1
|
||||
// then goes label_5
|
||||
goto label_3;
|
||||
}
|
||||
|
||||
:label_5; print("label_5", "\n");
|
||||
}
|
10
tests/goto.tmpl
Normal file
10
tests/goto.tmpl
Normal file
|
@ -0,0 +1,10 @@
|
|||
I: goto.qc
|
||||
D: test goto (both normal and computed)
|
||||
T: -execute
|
||||
C: -std=gmqcc
|
||||
M: label_3
|
||||
M: label_2
|
||||
M: label_4
|
||||
M: label_3
|
||||
M: label_1
|
||||
M: label_5
|
|
@ -1,5 +1,3 @@
|
|||
void(string, ...) print = #1;
|
||||
|
||||
void(float c) main = {
|
||||
if (c == 1)
|
||||
print("One\n");
|
||||
|
|
|
@ -3,6 +3,4 @@ D: test if statement
|
|||
T: -execute
|
||||
C: -std=gmqcc
|
||||
E: -float 2
|
||||
F: if statement failed
|
||||
S: if statement passed
|
||||
M: Two
|
||||
|
|
7
tests/inexact-local.qc
Normal file
7
tests/inexact-local.qc
Normal file
|
@ -0,0 +1,7 @@
|
|||
void main() {
|
||||
const float a = 1.0 / 3.0;
|
||||
const float b = 0.33333333333;
|
||||
if (a == b) {
|
||||
// Should trigger warning
|
||||
}
|
||||
}
|
4
tests/inexact-local.tmpl
Normal file
4
tests/inexact-local.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: inexact-local.qc
|
||||
D: inexact comparisons
|
||||
T: -fail
|
||||
C: -std=gmqcc -Winexact-compares -Wall -Werror
|
8
tests/inexact.qc
Normal file
8
tests/inexact.qc
Normal file
|
@ -0,0 +1,8 @@
|
|||
const float a = 1.0 / 3.0;
|
||||
const float b = 0.33333333333;
|
||||
|
||||
void main() {
|
||||
if (a == b) {
|
||||
// Should trigger warning
|
||||
}
|
||||
}
|
4
tests/inexact.tmpl
Normal file
4
tests/inexact.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: inexact.qc
|
||||
D: inexact comparisons
|
||||
T: -fail
|
||||
C: -std=gmqcc -Winexact-compares -Wall -Werror
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue