mirror of
https://github.com/irmen/prog8.git
synced 2025-06-15 02:23:36 +00:00
Compare commits
1760 Commits
Author | SHA1 | Date | |
---|---|---|---|
7657edcb7d | |||
580e786952 | |||
c0ae35b3a3 | |||
c3dc74788a | |||
379d241a0d | |||
1f49e8fe75 | |||
d70cfbb661 | |||
5482ac0302 | |||
131d5ceb4f | |||
512ddd1694 | |||
14a213bff9 | |||
d586846bc5 | |||
ef4efcb112 | |||
b01555d75e | |||
3804fba0f1 | |||
f93b7e3303 | |||
73baaeff1f | |||
7c79cdbd2f | |||
8ea032ed66 | |||
e7a0cb636c | |||
02f3f5d0f5 | |||
1e9bbd662b | |||
8644a4ae91 | |||
1e85f7812f | |||
80d88b3c61 | |||
d2827a7431 | |||
28c721fa7d | |||
8f799567cf | |||
9e8cc8b54d | |||
cc59069876 | |||
697d54e10a | |||
1679ca79b4 | |||
124ec77b58 | |||
3675d7961b | |||
f8aaa2d13c | |||
b7afda781a | |||
535ec13072 | |||
26d0a174db | |||
b2e821755c | |||
2e303041c1 | |||
96bed8f57f | |||
86d4a4309f | |||
1a1ab0dac6 | |||
ba8c3d14f7 | |||
617ea15c3a | |||
ef192a5778 | |||
565973c520 | |||
25b1043572 | |||
1ebfff7c7b | |||
8341f9c066 | |||
28cac291de | |||
8fa14a10e2 | |||
55dbd095ed | |||
31ad8bdd8d | |||
181f3e9eb1 | |||
50c3d809dc | |||
58f696d00a | |||
f603c543d3 | |||
6aaa0f928e | |||
feb8aa435e | |||
310e8f15cd | |||
da03941582 | |||
dcbb36a3bd | |||
53558f5c1d | |||
189399d5f8 | |||
5406a992f5 | |||
bc9683cc54 | |||
2eed75f602 | |||
d58f9f56c4 | |||
2e35f3c3a3 | |||
5c6bd9c091 | |||
857d2eefca | |||
90f1e7fd6a | |||
18e37accf9 | |||
cc53d698bf | |||
cb86206698 | |||
d77b1944fb | |||
a58cb43c4a | |||
88574c87c4 | |||
3a7a7091c0 | |||
906b137a7c | |||
42e2c5f605 | |||
cc13a51493 | |||
f569ce6141 | |||
4958463e75 | |||
2360625927 | |||
8badc40883 | |||
844c97930f | |||
5c09dc10ae | |||
9fd9e9ab5f | |||
35c477b5a6 | |||
ae0cadb383 | |||
984230e8fa | |||
a874aec6a1 | |||
ea1daa97d3 | |||
fb0d9b46b0 | |||
9da70bdf05 | |||
d640cfbe13 | |||
51a05ec4b7 | |||
1f5706bbeb | |||
25c9b2fea4 | |||
154f9b300f | |||
d78ce77536 | |||
b4fb43bc80 | |||
e0e01f794e | |||
08865dbb4e | |||
b9ad7e0e55 | |||
07158a6f1a | |||
957c42bc1d | |||
f784da2da6 | |||
c080fbe59a | |||
d70b8303b1 | |||
1d38c3582a | |||
9438e996d7 | |||
3b4a5e27f7 | |||
648d9fc269 | |||
54fccec7d7 | |||
4f9693055e | |||
555c50ee10 | |||
bf98ceca2c | |||
573cecb087 | |||
1b528491c2 | |||
4bdabe1961 | |||
a3fa527378 | |||
84f5ffa426 | |||
25d2b42283 | |||
300d1a871c | |||
2fcb83a39f | |||
3ba1d00a7c | |||
64164c1c72 | |||
3ee6058524 | |||
93a0a41e73 | |||
e7ab7b6d7a | |||
7d4dc3c063 | |||
a50400b7d1 | |||
f89f1a84d0 | |||
688dce6145 | |||
b88f550c5b | |||
9864abd393 | |||
c702c4a6df | |||
77e376f6bf | |||
491e5dbcfb | |||
a5c7393561 | |||
7fd3e9bb7d | |||
459e9f8f3b | |||
5b1143bcb3 | |||
fddd390d31 | |||
e514eeba17 | |||
c11a52b278 | |||
85e87dfe2e | |||
cb47e2c149 | |||
0fc9aa6b2d | |||
155896c4c7 | |||
178e60bba0 | |||
9f84aa5fb2 | |||
66fc109ce5 | |||
a231872821 | |||
7cfb33a448 | |||
3b798097b9 | |||
6fb05bdefc | |||
64ea72ed4d | |||
89425088ce | |||
925b9d845d | |||
ad074076c2 | |||
a2194c43a6 | |||
4b23b1dc86 | |||
9005c7994a | |||
4a47e15b1c | |||
09cbdf410a | |||
df6a43c7f0 | |||
4ce130dc8b | |||
94d76aa82c | |||
73609636c5 | |||
66b06d6c40 | |||
eeeb8d81f4 | |||
6f727aff88 | |||
518e5a30c2 | |||
bbba4b3d60 | |||
967adb9a87 | |||
040a6c62de | |||
483d193ced | |||
62458216c9 | |||
76b05cb5fd | |||
570b574b93 | |||
a82f211f9a | |||
504c80cddf | |||
4b4af9b527 | |||
28b383f888 | |||
40ce7725a1 | |||
1f2d46628e | |||
c9535049c8 | |||
9317cf8a35 | |||
1cd754f05d | |||
97b8cb748d | |||
84d9040b57 | |||
fdd18c615c | |||
c14f6cfc2b | |||
326eab3dd1 | |||
6da1f7eb4c | |||
1e82483152 | |||
6e2fd41a8b | |||
9927af1095 | |||
7585b6ef6f | |||
a6159702da | |||
0247fb0d84 | |||
6de760885f | |||
9851d14fb9 | |||
d5fc69d3e4 | |||
a40d120f2a | |||
fcdd9414d9 | |||
272a1001a8 | |||
2a52241f1c | |||
d8f1822c12 | |||
ce7d094adb | |||
a0cf1889a3 | |||
38ef394e15 | |||
abbf7c7cb0 | |||
ca5f7ae32f | |||
cbc4b75e50 | |||
65ddcf91d0 | |||
5280e1b449 | |||
b6ffb81909 | |||
e9edffa9f0 | |||
0dd1c17ff4 | |||
aef211e5f3 | |||
66829203d8 | |||
7a0eaf3148 | |||
fa5479ee5f | |||
03412cacba | |||
01a38a0b11 | |||
f43c14bd78 | |||
fb23452383 | |||
ab7dde1450 | |||
8d9bc2f5ff | |||
7651ccc84e | |||
1a6b95b388 | |||
78ec1e7512 | |||
7e38d26c33 | |||
ed09dd4e9e | |||
5731b79554 | |||
eaa22a9d13 | |||
b2bdfe8482 | |||
fea531be9a | |||
7c69d38588 | |||
a088ee56b0 | |||
ae669af904 | |||
d1ddf05e38 | |||
51279a98b3 | |||
bf33a4f82d | |||
fff0d741c3 | |||
e83d0ee820 | |||
09f3eecf56 | |||
2bd4326ff6 | |||
c13168b60c | |||
ea3871d0c4 | |||
70a2b11271 | |||
3cf39e072e | |||
413b86cc4a | |||
a6107fcfdf | |||
a064ade1e0 | |||
df35aa7942 | |||
cd49c5f88d | |||
1541ad2160 | |||
c78b7b1a24 | |||
9c7a645e18 | |||
4acf38031a | |||
4cd7271e30 | |||
3f630ab1b0 | |||
04cb684fd4 | |||
4c843571ea | |||
1326498802 | |||
b7ebd8c4a6 | |||
24e0a69480 | |||
4bcb2bdede | |||
d27f3eb8a4 | |||
d3e4481112 | |||
1d1d6b3d98 | |||
90b8a22a71 | |||
8dbfb8ab76 | |||
e29ff1c848 | |||
585f6ffc9b | |||
46b94c17d6 | |||
7af8007447 | |||
16a2b2f566 | |||
ea2a90c3c5 | |||
5cda750e5e | |||
4e143d45c8 | |||
4c50980d81 | |||
2954f5f04d | |||
cac4c1eb1e | |||
0b1f30d98c | |||
c7b1e8d772 | |||
a4f7512d44 | |||
0d3ad80659 | |||
aba1a73e28 | |||
dca31b2ca3 | |||
0cb378ca31 | |||
cf551d2cc7 | |||
ac0c8a68f6 | |||
5986dcdd2f | |||
6be6eb2227 | |||
d34015eec5 | |||
255c5bfaca | |||
01c6754928 | |||
8eaf884f69 | |||
699a2bb7ab | |||
4a2dcd20d1 | |||
4e98fb75d6 | |||
64e66e732f | |||
7aec627f6b | |||
59a2fec176 | |||
edc5a5a94f | |||
c5b7edad82 | |||
124ffac4e4 | |||
6d2a36fb2b | |||
28b43b3e1d | |||
f7feaf158d | |||
2396f707c6 | |||
d4d8e1b1ba | |||
44fec2c729 | |||
a80a6913e3 | |||
0eac04c220 | |||
29dd758302 | |||
5c45adc7f0 | |||
ad22cf08cd | |||
2c2ae64194 | |||
97c2dadd16 | |||
b36e1e3baf | |||
2da35fec17 | |||
bdeac74cfc | |||
6516d7cb15 | |||
31cf76042d | |||
c4c4dcf2b3 | |||
03145630f8 | |||
e2fcac322f | |||
beaff4d650 | |||
79af96ddde | |||
e439720c9d | |||
48d0185ea4 | |||
e2592b4e0b | |||
2967866e3d | |||
b566ea5c3f | |||
8f6eaeac2c | |||
b4facaeb3c | |||
d12b7ccc6b | |||
453e8bd0a0 | |||
9204d390ae | |||
b70ce0015c | |||
d113827753 | |||
c67f877857 | |||
0ec719e429 | |||
17f7b11148 | |||
966b017670 | |||
4c98070b3c | |||
3681d6ee1c | |||
0af17cdc33 | |||
2aae1f5e30 | |||
d18f2a7bfd | |||
9046fe8d3a | |||
78c7ee247a | |||
d5adb85e5b | |||
69f953fd9b | |||
484677b4b1 | |||
b10a8e728f | |||
25f25a8767 | |||
0c053e4a2c | |||
3f6521cc9b | |||
a074491d5b | |||
a291164953 | |||
43c55b58d2 | |||
e7298f8162 | |||
ddf990296b | |||
ead8aa7800 | |||
7a9dd1ac9b | |||
1c97c22eff | |||
bbf621a8c4 | |||
8efa89165c | |||
4f8aaf9244 | |||
a97edef380 | |||
eefae24aa3 | |||
54bffc91ae | |||
63f5ef9e14 | |||
034f27a8dd | |||
c2f6311367 | |||
6f00a48772 | |||
b3dba67405 | |||
c9a4235669 | |||
ae0d52274c | |||
8973763866 | |||
3d799ae7fe | |||
8b10115390 | |||
d2e010c439 | |||
15867ab423 | |||
22c9e99fa3 | |||
ee262f6aad | |||
af64af2397 | |||
1feead2260 | |||
d3dcd24b4d | |||
fd1e6796ef | |||
3ea0f0cbaa | |||
f3e3311598 | |||
0dc50a93a4 | |||
fda8e61be4 | |||
ac1d4b4a7a | |||
c719e274d5 | |||
e4990f8ec5 | |||
62afd3342e | |||
6e8a89e6f1 | |||
aa2437cfb8 | |||
4a710ecdfc | |||
3ef5bdfeda | |||
7915dda35f | |||
9120e16683 | |||
a1ebc7090d | |||
054b4636e0 | |||
e3e7b060b7 | |||
5ac9c75521 | |||
07710e0995 | |||
d6a67f5f2b | |||
2675623aea | |||
94263c43d0 | |||
d8ec03874f | |||
a7247f5b8b | |||
4d37581694 | |||
5d7ddebcad | |||
53df0eb707 | |||
8babad9c7c | |||
8db7aa07bd | |||
42f4b06ac8 | |||
f4b50368ba | |||
db80417bd7 | |||
7a6f2ecc8c | |||
f5d556a7f9 | |||
2aae46d632 | |||
19ebc6d6b3 | |||
f88c29e083 | |||
6ed9899dc7 | |||
9de7698a5c | |||
112d2d6058 | |||
ddb8346711 | |||
8dd3faf395 | |||
35f3e8708b | |||
cfe3fcc9e7 | |||
66a6659a6e | |||
88ae3daa42 | |||
08b8fe01ab | |||
731132d4b3 | |||
98acff802f | |||
5f11f485a2 | |||
34f3169dda | |||
a3ef8f814b | |||
385dd6fc23 | |||
9af4168ae2 | |||
a5e0e31b74 | |||
b385dc8c26 | |||
92c012b55a | |||
641f6c05d8 | |||
788f6b44a6 | |||
63a4525f06 | |||
3e34a3ef72 | |||
0c5e8ca199 | |||
ff23fb0086 | |||
56f41d5e34 | |||
4700a239b9 | |||
bd5abfb969 | |||
b93fa75377 | |||
681ce9c60c | |||
dd0f0fe415 | |||
119040fc50 | |||
551e5688da | |||
56c1035581 | |||
ba1e907c79 | |||
2a3a27c56d | |||
647af34f5b | |||
993be6394e | |||
9a27505315 | |||
2e37f5dee3 | |||
03e486c082 | |||
edc83305a4 | |||
66e7c51064 | |||
60244aaf16 | |||
443391c700 | |||
47dbafacd4 | |||
5b6811d073 | |||
7516116bb7 | |||
e6014ea4dd | |||
362abfe284 | |||
ad4880997a | |||
592becc126 | |||
c38765301e | |||
5f27426f59 | |||
d924f8bff8 | |||
d14c61b160 | |||
fe2b67998c | |||
04df3c9f7f | |||
de3d0b40dc | |||
4db4a5f1b2 | |||
5a0524ff4d | |||
5b7801eea1 | |||
fbe231793b | |||
6a9269111e | |||
a94cfd34f5 | |||
28eae5a0fd | |||
1818738fc8 | |||
7e1e7a0780 | |||
1fc79ff6dd | |||
3535c1acda | |||
33c8caac8f | |||
51d708bbdd | |||
a5a918df84 | |||
820541e427 | |||
e63a8f0c01 | |||
c11a9b8709 | |||
80f39e8097 | |||
2a8b65e29c | |||
4bdf50145e | |||
3a9919a377 | |||
eef8ae00b8 | |||
ed15fac691 | |||
f739e679e4 | |||
fc0fae8caf | |||
f46896fd74 | |||
52649a8e4f | |||
bdfb01f6a0 | |||
1137e57393 | |||
267ea13e8c | |||
04f7b772a3 | |||
42c7569791 | |||
6d29b00a80 | |||
9f1bd2d7d6 | |||
9826d7c494 | |||
c6bf57b390 | |||
bfcf07c1a2 | |||
4d7e96d423 | |||
449461e412 | |||
607275ec66 | |||
e55cde2a81 | |||
84afb374e6 | |||
da1620807f | |||
f39ef8f565 | |||
fe8b6e820c | |||
f29d24e96a | |||
620ffe54ec | |||
ceaa4cd07d | |||
af17f903ee | |||
c532e28841 | |||
dba0846866 | |||
bed629998a | |||
bc2ede76bf | |||
2a1fec2ed2 | |||
004048e5a7 | |||
b941d6f1e4 | |||
37b346740b | |||
f5e332daf7 | |||
fe9a9fc5cb | |||
cc57477b99 | |||
a1574a7187 | |||
a5110b1f96 | |||
006713fe13 | |||
7868e672e0 | |||
e1a133c2c0 | |||
c77cd0da39 | |||
577333f2c4 | |||
7d8cdcbfea | |||
c5c4c6f111 | |||
73be754680 | |||
acd841dbb6 | |||
6b52ba9397 | |||
10d12f73d6 | |||
cd9119655c | |||
41afeccd51 | |||
6b87cbb703 | |||
32afcbfe42 | |||
bc2b38daf4 | |||
f40b7b62bb | |||
1ca3f64bf0 | |||
92527b4c1d | |||
c48012c385 | |||
a282b17286 | |||
58d9463f16 | |||
047decd552 | |||
82e0877e64 | |||
040d75dafa | |||
4e1686f6e3 | |||
b5e691f367 | |||
325f55f22d | |||
9724f2db7d | |||
5f20f321f0 | |||
d4b087ea3f | |||
8ff10724d1 | |||
1581381467 | |||
96b5a30f60 | |||
0e17a0474a | |||
b27368175d | |||
aba36f7c92 | |||
a3fa946300 | |||
01bbc2234e | |||
58e1864144 | |||
88458f5355 | |||
a4f697bae1 | |||
8201408f16 | |||
8b8caa1c2e | |||
4dc50cb551 | |||
5522a305ab | |||
d7f72056fc | |||
64c9c9b7fe | |||
98e1c843e4 | |||
906d9d858c | |||
16c1309df1 | |||
6eacf1bddd | |||
6c8c8e11cc | |||
e941d2665a | |||
68669dbef0 | |||
6a48de9a9f | |||
9d6d98930b | |||
3cc858db12 | |||
386a391fd9 | |||
d33aed4ed5 | |||
73ec8c31ad | |||
24944ad49e | |||
26ed231f61 | |||
8485b8429f | |||
358215e4dd | |||
f874942075 | |||
2cadb546d5 | |||
344a1b9eb8 | |||
3c77f8a020 | |||
8e00408e3e | |||
abcdfd8e28 | |||
b0f5b6925d | |||
ef79d0c43e | |||
78b4288005 | |||
680f5d21ee | |||
c71aa0895f | |||
9f8e61789a | |||
932035cdc5 | |||
ef198f1493 | |||
48ef856c0b | |||
9aea2b22c4 | |||
e0055bc431 | |||
9553248ed6 | |||
39d2194d8f | |||
0800033b47 | |||
64d8943b7d | |||
444e97b00b | |||
1816bda7ea | |||
d4a2031c07 | |||
8cf0b6cf51 | |||
f2010bf7a5 | |||
8f56a7fe69 | |||
64c132ee0a | |||
84a7e86fe3 | |||
a8c09d6144 | |||
87c46ba730 | |||
0f83dc6491 | |||
cc22861719 | |||
a14c192ea3 | |||
b3d98be862 | |||
43027a4728 | |||
03831a7394 | |||
fdbbd181ea | |||
69075376dc | |||
504d1440cc | |||
9e33b8b8da | |||
0cfcc5cd29 | |||
e0de662f8e | |||
66a836d094 | |||
80095f4962 | |||
828d83dbef | |||
7de665d1e4 | |||
0a356ba73a | |||
41de8caa13 | |||
968609d06d | |||
3b199a2a87 | |||
0c1018ec61 | |||
bc3f2db3de | |||
06bedb7adb | |||
45a9751217 | |||
e8da62aa29 | |||
ddb2ff4216 | |||
f27e3478b9 | |||
38dc7fb7bd | |||
aa4cd13c31 | |||
4a4b6c04a1 | |||
37fa3b34a2 | |||
f8084e7955 | |||
4d5119ce3e | |||
d85c347a6c | |||
7dd758a753 | |||
806654fc44 | |||
8e6b91cb9e | |||
334e6dca28 | |||
f2daa17b92 | |||
6d9fccacb1 | |||
37638e7ed0 | |||
8a0e650511 | |||
8ba5a0d90c | |||
bfd3edb617 | |||
56ba24962c | |||
19a2110ba2 | |||
242a3eec63 | |||
fee46f2e54 | |||
6aed7e429a | |||
517ea82b99 | |||
99c29343de | |||
892fa76883 | |||
d446b57d05 | |||
0e086d788b | |||
498841d45d | |||
d1f8ee1e56 | |||
07feb5c925 | |||
75fd263e85 | |||
1e1f444cab | |||
89cc7e5fa9 | |||
265e7aefbf | |||
1c55a6c6dc | |||
8f18b5b8a7 | |||
f790182f0b | |||
813007a5d8 | |||
d03ff1e4d0 | |||
932bbd0381 | |||
01bd648cb2 | |||
779a5606a7 | |||
ccc11e49d2 | |||
d28c994ecd | |||
5d88717f32 | |||
e35cfd4971 | |||
bcc4bf5c2b | |||
a0594cbce3 | |||
078bfefe41 | |||
9c1b11d605 | |||
44d82f9190 | |||
37fcde30d6 | |||
09c6cb4d6b | |||
b428343c2a | |||
dfce292294 | |||
2b8f613a00 | |||
2eb137618e | |||
4bb2b8ca9b | |||
5179562fb2 | |||
0a4de45453 | |||
ffdc658dc8 | |||
7530f4407b | |||
73864c8101 | |||
f948917124 | |||
0d44492086 | |||
38a22fbc99 | |||
8ae435549d | |||
9b113c0cbb | |||
0e0fac8c4b | |||
4cd9bb8f99 | |||
ad9eaeafeb | |||
6cd392909c | |||
49ec430592 | |||
09f3fbeb38 | |||
e7698686fa | |||
66d939df0d | |||
6bc079c7b7 | |||
299419917e | |||
69f6afe420 | |||
b7279a3d9e | |||
e14b854d7b | |||
8bd7c601c0 | |||
997288fa03 | |||
0f26b39997 | |||
ae66fcac1e | |||
43944a94eb | |||
eba0bde6f3 | |||
4544af441b | |||
a8be94de6b | |||
b24df31c2b | |||
332ba8ed7e | |||
58400f53bc | |||
01c2112881 | |||
a546c2247d | |||
0da9142009 | |||
796add0ee2 | |||
00b32f64e6 | |||
f97b3f23e2 | |||
08a079a96e | |||
e98e951834 | |||
2668bf8519 | |||
dd4c073e18 | |||
c7c72f00c7 | |||
ef1c665b9a | |||
d56565be25 | |||
e076b3aedc | |||
ae3b2ddf5f | |||
1bdc427d73 | |||
6a639ce533 | |||
d91ca8b197 | |||
a01c0a283d | |||
5c393091a0 | |||
01b680504b | |||
8e4319cd5a | |||
5a776dd690 | |||
cce08d95db | |||
28c1b208c1 | |||
3844bf1f72 | |||
745d192563 | |||
ee782e92ac | |||
afbc91d1fc | |||
f998888d6d | |||
7d8b42d63e | |||
6ebd4e821f | |||
d1806bfdc3 | |||
1d2d7155da | |||
b09e0a05bf | |||
c609e982fe | |||
2b227b43fe | |||
48f09f71ab | |||
ead8c59bda | |||
db52a9466c | |||
1509de390e | |||
88a1aa4f3d | |||
172e78e8f2 | |||
36bfef567d | |||
e40ebd75a2 | |||
992732f2cb | |||
b58a3ba1bb | |||
afe521b0c9 | |||
5d9caef45f | |||
278e2f5605 | |||
1e299bf360 | |||
8dfa0bc38c | |||
fde136fb7b | |||
ee4da1a757 | |||
ae2d96c455 | |||
6d8fbe0877 | |||
2fa1d8f2e8 | |||
533090a68e | |||
1dff59e1d6 | |||
44d232f52a | |||
5f6cff739a | |||
2764d235a9 | |||
45debff89f | |||
c45fbe6310 | |||
9ef9c24388 | |||
6a40f23578 | |||
6a0a6b4751 | |||
0bee6f6b41 | |||
82a15b5a16 | |||
11b7c4459e | |||
98570ac456 | |||
1b2296ad5b | |||
16851746d6 | |||
935450a45f | |||
ba67fd318b | |||
08ac459a41 | |||
a83e9d9a0a | |||
62d3f01948 | |||
af5ca2d0b8 | |||
ab4bcdf12d | |||
a6756d2cea | |||
f81061dd42 | |||
8e2c304b3c | |||
f21adaa3ef | |||
2637939e62 | |||
faf05582f8 | |||
161c02ced3 | |||
ff8de8e42d | |||
09d506194f | |||
42db3085df | |||
ad14c88fde | |||
0c9daf6eaf | |||
86c6530e46 | |||
159f80d629 | |||
aa949165c7 | |||
d22359b6e7 | |||
d73709653d | |||
405926e811 | |||
36758f41a4 | |||
7ebc9c79cf | |||
e0668b55b9 | |||
76c09da961 | |||
7e3b8c2c59 | |||
ecca854c7c | |||
3b0d7ea960 | |||
f70fa42eac | |||
5698de6cf4 | |||
c5a333a904 | |||
ff324955dd | |||
70436f5dca | |||
31177a2b1b | |||
4de012fc49 | |||
ee2888e744 | |||
efe4df92dc | |||
723ab54f97 | |||
d9389afc66 | |||
e7178ee496 | |||
d5f35bb3fb | |||
72f1a779f2 | |||
3277544295 | |||
98d2c64d5d | |||
f68b46fc60 | |||
d54ab856e7 | |||
16b24fadea | |||
b3803cbdf1 | |||
2ceaa25181 | |||
513611c5a6 | |||
7ec4ba40ad | |||
92374e122b | |||
94f12732ab | |||
0904712a00 | |||
32becdbced | |||
34aa21f7d9 | |||
cc81dd7d3e | |||
335213b55f | |||
13ab4166c0 | |||
3dc5a0e7f8 | |||
e15c5cde53 | |||
d88c09b098 | |||
893b383bdf | |||
dd7c9d62e6 | |||
97c5c90eff | |||
1fb94e7a7b | |||
daca87c6d0 | |||
203ec5fa46 | |||
9ea69c07b8 | |||
68539d6cc9 | |||
f75fd0811e | |||
836bc9d456 | |||
a37769aafe | |||
68e62e4bd2 | |||
a5cd3728c9 | |||
a48ce35f0b | |||
e1835b5775 | |||
433832b329 | |||
ee81da14d6 | |||
6395d1908e | |||
989a5a2f8a | |||
b7a622c68e | |||
a8507b437d | |||
e505bf9ccf | |||
a289b32053 | |||
c3f1f09ad1 | |||
70ee2026ff | |||
690782bf60 | |||
755cc4835e | |||
a684ea46e4 | |||
8fbe13f99d | |||
452e9e275f | |||
cd40088636 | |||
9b9e6f4af5 | |||
ae6eeadf54 | |||
5268b05060 | |||
390263a34e | |||
55646edc3e | |||
8d177beb78 | |||
1da0c59182 | |||
36e8f10d2b | |||
cdf5a8f20f | |||
eb64d92333 | |||
eb55da63ef | |||
918302f79b | |||
9d7131d9f6 | |||
229c1114dd | |||
885df9156f | |||
c319233ddc | |||
958b5c0780 | |||
880c0a5da8 | |||
237c6dc856 | |||
ccf6e32bf9 | |||
a1874f6f00 | |||
95e4490a8a | |||
31c132c2eb | |||
00b0ec58b4 | |||
a1d0e5bb65 | |||
03e0d4b2e8 | |||
6afdd4e6fd | |||
b500a0d477 | |||
dd2463a440 | |||
23a8bebd9e | |||
3caf9108ad | |||
bde4be8231 | |||
0bbbb12ed2 | |||
b570bdaed7 | |||
8c0843cc87 | |||
31458ffd81 | |||
c15c10a94e | |||
9fca978725 | |||
b125901717 | |||
eb018ae660 | |||
7e5a9474fe | |||
525a9b5036 | |||
c3fbdf34ca | |||
48bd51e1a5 | |||
10d0b03a90 | |||
e1b3582f08 | |||
95be1c9e22 | |||
1ce8fe06d5 | |||
15c649024e | |||
e97303c226 | |||
3b786c819d | |||
04959dbd8b | |||
5cd4b874ea | |||
f14ea1b3de | |||
9cc0cda0fb | |||
09a7a4bbe5 | |||
cfea8b3745 | |||
28bf0b61ce | |||
2dc2429735 | |||
83d4592526 | |||
2d528c26ae | |||
66b3dce794 | |||
93f77a1045 | |||
aa4d23a3d5 | |||
2d7ebff8e9 | |||
bad9dd3b3b | |||
2f4e517857 | |||
ff35ba3696 | |||
72768e7fad | |||
77f3852cdc | |||
66857ca477 | |||
75514fc7af | |||
be06d871b6 | |||
f98ee326b4 | |||
bc8126eb16 | |||
4c8beefdcb | |||
bbb6c53457 | |||
d8991894e3 | |||
c7b7dcfd03 | |||
2c9e50873c | |||
923367296d | |||
151a206617 | |||
e403c4cf99 | |||
e3fbe37f9f | |||
dc870cd5ea | |||
584be44743 | |||
5fffd35ec1 | |||
b92e22e4a6 | |||
3e6d16a7a8 | |||
ecbcc277b8 | |||
dff1d9e4dd | |||
7c0bde7310 | |||
a82d21ac05 | |||
0bf8378fcb | |||
017ef8a837 | |||
0d63cdcb96 | |||
68a6f99c9f | |||
60781bcfc4 | |||
77fa2e2722 | |||
c36afd872e | |||
7e58a4c130 | |||
19a4bf1088 | |||
9678bbae4b | |||
a4d093afa1 | |||
ba788bcf0f | |||
f2c62bee7e | |||
548721e306 | |||
1ae950a638 | |||
c9385e93fe | |||
9bb16e293c | |||
c223702ea0 | |||
9167ba499d | |||
2d7e95e1b6 | |||
0cba736446 | |||
0816a57032 | |||
a0ab0bd3e2 | |||
b89ad4b328 | |||
6cda76a116 | |||
c112b327ab | |||
46c12a8899 | |||
c5219dfb3f | |||
4a8ee6815a | |||
e1b6bb154a | |||
b19c282269 | |||
e520921746 | |||
970642244b | |||
3b90be2d9e | |||
2f756f1e3a | |||
78e84182f0 | |||
65a7a8caf8 | |||
4c6a2f5df9 | |||
fea297e409 | |||
7cf6aba625 | |||
3bbc00cc8c | |||
70ed2b4203 | |||
0adce9b9c6 | |||
0e781d18fa | |||
4575a8fffe | |||
10d0ff252b | |||
c7d54570cc | |||
7136b33f2e | |||
70a78e74f6 | |||
d5707b7bf3 | |||
9f247901d4 | |||
5659742d97 | |||
450eaf7c4a | |||
47485e4b49 | |||
64254e758d | |||
c1aa5d4e47 | |||
ab8173637a | |||
3841cef497 | |||
b717f1c7eb | |||
da57f76de3 | |||
4784f1c65a | |||
41af63b333 | |||
e2bb0de24d | |||
b791fae9ce | |||
6033a9e20c | |||
9e8c8973d8 | |||
3933bf5c1a | |||
708e296774 | |||
84925ab69c | |||
b3cb9b7fe2 | |||
9cb61fa34d | |||
7c219d235c | |||
6938c79f88 | |||
b8284a147d | |||
15ee90e99c | |||
795f80b4ec | |||
6b6427492d | |||
6055b8c3dc | |||
a98cb50d55 | |||
e98bbc1c52 | |||
7245aece4f | |||
60cbb02822 | |||
4e863ecdac | |||
5037033fcf | |||
e6b158bc97 | |||
4cc0dfa10b | |||
4ced8889d3 | |||
d26967a87d | |||
fc8955941b | |||
071a80360f | |||
d2154f5f2e | |||
334d382bfa | |||
90c4b00f74 | |||
71261525e8 | |||
3126959576 | |||
02e51d8282 | |||
ffb2027a19 | |||
70c9ab9074 | |||
6d1fdf1ba6 | |||
1f7180d9a8 | |||
b4e94ae4dd | |||
07c606bfc9 | |||
e705a8bd89 | |||
b3bdfb7f1f | |||
5af1aeb092 | |||
be64fa674a | |||
204f5591a9 | |||
ee3e3a3a40 | |||
f9200a2b75 | |||
f570b70827 | |||
0db141eeac | |||
acb2ee53bb | |||
c544b7f5ba | |||
c0024e97e5 | |||
bdf8aa9168 | |||
de5ce0f515 | |||
bb95484c8a | |||
cad18b8a3a | |||
0f6a98751a | |||
aac5a4c27f | |||
d3f6415387 | |||
04da44eb98 | |||
7649be97b1 | |||
c9ef777e0f | |||
c0cb2438d5 | |||
30c531b39e | |||
bf703a8a66 | |||
e7b631b087 | |||
a9f5dc036c | |||
0a83b51e00 | |||
eab63ecc6c | |||
b0794cf35e | |||
5b9e71a27d | |||
eae41de27d | |||
e9163aa3a7 | |||
8c617515ba | |||
04e4e71f2e | |||
a587482edf | |||
0aac9350d5 | |||
f56c12ee4e | |||
4bb9ae61f2 | |||
ff7f3484e4 | |||
5da3abe6b4 | |||
c0b398e0ce | |||
3de10adac2 | |||
1b573d6552 | |||
2a96f93919 | |||
c6b2639ca4 | |||
b9abf37a7e | |||
373cbb4144 | |||
a521982576 | |||
a77fde577c | |||
ea6926e57d | |||
ba25b7fee6 | |||
7ee162d98b | |||
380f557c45 | |||
1bdae53f4e | |||
9314c346da | |||
bfaad1388c | |||
0b580ad05d | |||
bb35a80177 | |||
24fc95ac81 | |||
8f864417c4 | |||
bb9d29b061 | |||
b9d8ec1463 | |||
1842a7660d | |||
5caa2f5536 | |||
d6078be8b7 | |||
cf60723f14 | |||
f7ff0a2b1d | |||
cc49664b2f | |||
99fe74f026 | |||
b021869eeb | |||
b8806d163b | |||
1116aae1de | |||
5e5f60253b | |||
bbc02752c9 | |||
9896bc110e | |||
ca60f8ecdd | |||
544acd1e35 | |||
6e07602d77 | |||
82898f7bba | |||
d61283a8bc | |||
1ee3f826cc | |||
4a00a5ba9e | |||
39eda67867 | |||
a99d38fdaa | |||
0eb2d437e2 | |||
3ac9036c79 | |||
c94e292176 | |||
91d87c2d9b | |||
ff472f69c0 | |||
e18119e24c | |||
4a592dc64c | |||
d9e13201dd | |||
5c75b19c5d | |||
52a77db60f | |||
0513c250fb | |||
48864ad6cf | |||
cdbccad21e | |||
e15bc68c9b | |||
8bffd7672d | |||
61df5b3060 | |||
b5255444cd | |||
0c94e377fc | |||
8e5c67b4b2 | |||
b24f2f1756 | |||
c69c17de42 | |||
061617122a | |||
125ce3240f | |||
7215efe167 | |||
06d1570142 | |||
093c370faa | |||
aec9574737 | |||
7ceb76cff5 | |||
300e2fe9f8 | |||
91e1643627 | |||
91421b0c62 | |||
40f611664f | |||
dcba4f4098 | |||
c098ad2b3b | |||
b43223cb7a | |||
e243531dab | |||
1af38e62bc | |||
f37f062cdc | |||
7e734214dc | |||
05d152746f | |||
dea7f37553 | |||
415c599310 | |||
70cd4fedbe | |||
1e6d7673bc | |||
b4963b725b | |||
0371ffa4ce | |||
6a664a7e15 | |||
88ce9300bc | |||
85cf0e311c | |||
0e3d75cfeb | |||
630c8a5faa | |||
905921a684 | |||
1e469b3b0f | |||
bff3c4f95c | |||
bd2bcb6994 | |||
4c8898a639 | |||
97df33ab1a | |||
ef46fb2685 | |||
d5d6dd3614 | |||
6c233c6a0a | |||
6db715d879 | |||
ab02e8a546 | |||
8cbfe64f19 | |||
fd1e9971e4 | |||
68336a76c5 | |||
393e914a86 | |||
ffb54110e9 | |||
533d825f1a | |||
c65279b672 | |||
f9926beeef | |||
add8a777d8 | |||
21bc505d85 | |||
3fc49c001e | |||
3d69a95c49 | |||
d81fdf6d6b | |||
87d3109ffb | |||
180dbbb521 | |||
24aac7cee5 | |||
53e18a5387 | |||
92062d056d | |||
06368ab0a1 | |||
38efe25c68 | |||
319079de7a | |||
025bf900a5 | |||
2885f4f7b1 | |||
c07eda15b1 | |||
4274296cf3 | |||
76a203d4df | |||
24f37e2062 | |||
f465b2e2a0 | |||
ce00e49a89 | |||
d494f9d66b | |||
c35a183a64 | |||
9cdd5fe7f2 | |||
c21428215e | |||
64d5af46f5 | |||
25846ea18a | |||
798383596d | |||
9ca71bc937 | |||
5407429ec0 | |||
ee5c94f6db | |||
91045afbee | |||
3f64782023 | |||
f8d35f9502 | |||
ea78d3ec9a | |||
e056a28316 | |||
0bea721c2e | |||
e1b89494d0 | |||
cd8e7f3912 | |||
50604c25c2 | |||
aa6b2357d8 | |||
5b2d29bef6 | |||
a296d26328 | |||
d01a26ec61 | |||
efd7d6f0c0 | |||
b55be093be | |||
7c1d5cadd7 | |||
dd1592b03b | |||
9b37ac483f | |||
090820958e | |||
ac21e1be5c | |||
5196443b26 | |||
c8531cbeb1 | |||
c560abedba | |||
9b952fbc44 | |||
ccdf05e922 | |||
c3d74f2ae9 | |||
f47498888c | |||
5665a7f0cb | |||
b8178c6c8d | |||
4a0f15eb88 | |||
c4f53fe525 | |||
8c93ec52de | |||
befe0fff2a | |||
b6a837cbea | |||
4861973899 | |||
c593e4b500 | |||
5bf78c20d4 | |||
5c672130e6 | |||
d8214d4f12 | |||
64d1f09ce0 | |||
47d0f0ea40 | |||
2d85fd093e | |||
d936568b76 | |||
4598a83e8e | |||
f4bf00ad31 | |||
07fde7f6cc | |||
729209574e | |||
f28206d989 | |||
0c81b32cac | |||
11216017cb | |||
a7b9f53967 | |||
1fa2e2e37d | |||
f67d5faeb7 | |||
5cbf859458 | |||
629ed74d09 | |||
ca2af2ca63 | |||
52ab089615 | |||
01461a196d | |||
04832f052a | |||
c8b2c8ae50 | |||
1b81c7fb22 | |||
9ccda0247e | |||
a7df4dcf25 | |||
d91f47c791 | |||
a9ac4e7f44 | |||
fc3ec57437 | |||
266f6ab919 | |||
6218c1c00b | |||
cc81d6fe82 | |||
69f9102f2d | |||
beb9275982 | |||
abe48713f2 | |||
82cfaf2fbb | |||
3d3bc4738f | |||
2d0746f5a4 | |||
9c71e2f1c8 | |||
134fd62da8 | |||
2afd283582 | |||
c66734bab0 | |||
8e56a61f95 | |||
d265271148 | |||
b40e397b28 | |||
35ff1d996a | |||
deea0b05cb | |||
c50c9ca545 | |||
a819b4a5a5 | |||
df2d7d4734 | |||
79ce4098cf | |||
374464a1f8 | |||
c8d0bf27af | |||
6e4ae034b2 | |||
52b560e72d | |||
9b971ad222 | |||
3613162d09 | |||
3a272e998d | |||
d4c750beb4 | |||
84b31e65e1 | |||
7b802bfd3d | |||
f9c4632b8d | |||
e4764cd8a6 | |||
dd78a3a686 | |||
94c06e13f4 | |||
e8bebe5a75 | |||
5b0e1b4f9e | |||
8c0a93779b | |||
9241479da4 | |||
8ffca93cd5 | |||
7fea0c124a | |||
20dbdb20d2 | |||
e6b8e2e8be | |||
7c5b7f77cc | |||
de84547a21 | |||
44676756ae | |||
b399b0f182 | |||
1152191f48 | |||
af1b07ad44 | |||
b8113fff1e | |||
ff6948cf2d | |||
fd25e85d59 | |||
c07cd72e85 | |||
e2c101206c | |||
92276b5769 | |||
a2133f61a8 | |||
199adbbcf0 | |||
dc316fd7b4 | |||
025183602f | |||
db4619a9d9 | |||
451e527b7c | |||
54dd3a00df | |||
03c5dab79d | |||
1fdee861e8 | |||
c12bf991b3 | |||
78a097585d | |||
39132327cc | |||
dc32318cec | |||
592f74124c | |||
e5e63cc5ac | |||
f40e0f786d | |||
ebd9f1471b | |||
d76547ead4 | |||
4600772e05 | |||
ed597423cd | |||
f20ca06f85 | |||
a636d3f394 | |||
043df18daa | |||
96996bf18e | |||
f350137a14 | |||
b7a6f3ec75 | |||
6c34672549 | |||
e779a07bce | |||
9a36e8ba3b | |||
c968bacb01 | |||
25199dfb43 | |||
48fed4e6fb | |||
fc253237c9 | |||
589948c7f4 | |||
7e69690605 | |||
95f498ba9b | |||
fd07ae5225 | |||
8acd94fc89 | |||
1436480eab | |||
448d176c24 | |||
fd269453a4 | |||
b3b380964c | |||
6e9025ebf2 | |||
3922691b3c | |||
0545b77cf4 | |||
6b3f39fa1a | |||
3114ab87dc | |||
00bc99cc7b | |||
540b3ae2f4 | |||
dbfe4140e1 | |||
d3675ec254 | |||
ded2483fc0 | |||
e62ea388e0 | |||
f20356e9be | |||
d282a2d846 | |||
4641ac46e7 | |||
ba9268a09e | |||
fb9902c536 | |||
5318ba6c6e | |||
fd5ebef488 | |||
d9e4f39ddc | |||
435b9d8973 | |||
0ea70ba656 | |||
92a07b87d2 | |||
c3c82282ba | |||
adc15c24ef | |||
dddf9a9396 | |||
9ca6860ffa | |||
f7dd388954 | |||
6012839f0e | |||
8e9cbab053 | |||
aaf375a57b | |||
3cce985f03 | |||
c59df6ec20 | |||
5c3f41f64d | |||
cf3523f49f | |||
db794752cb | |||
bceaebe856 | |||
3916de2921 | |||
9e0f8c1a97 | |||
0cbc56b82e | |||
b95608f68a | |||
b6e5dbd06c | |||
914f19be86 | |||
f09bcf3fcf | |||
d0b18dec8e | |||
75d486b124 | |||
4914609485 | |||
75bd66326a | |||
8f904f75bb | |||
549c598f51 | |||
ed68d604d6 | |||
f83752f43b | |||
86c22636eb | |||
30d20a453b | |||
fe29d8a23f | |||
694d088160 | |||
6aabbffc62 | |||
7b59bc8d12 | |||
79d0fb0b52 | |||
edf56d34f8 | |||
623329fb33 | |||
9f0074eef9 | |||
6733253826 | |||
f117805129 | |||
c75b1581d2 | |||
109e118aba | |||
201b77d5b6 | |||
a5ca08f33d | |||
86210c4513 | |||
988a3e4446 | |||
0f5cd22bb7 | |||
2f5bed36b3 | |||
5b6534bb28 | |||
e31e5b2477 | |||
07d5fafe2e | |||
e08da659e5 | |||
8a4979f44c | |||
e67464325f | |||
94c9b0d23b | |||
e9ec310d8a | |||
c78d1e3c39 | |||
e94319145f | |||
3f3b01b5f6 | |||
19a2791c65 | |||
4e8ccf0ef3 | |||
f1a7d5ecf7 | |||
8b05abb80d | |||
48c9349ce9 | |||
117d848466 | |||
9a2df072cc | |||
99c62aab36 | |||
224278e07a | |||
74b69e191e | |||
8cda8a727c | |||
a3c0c7c96f | |||
4403e4ed62 | |||
9b209823f6 | |||
b2cb125bd4 | |||
5e8f767642 | |||
6ee270d9d8 | |||
44fa309d20 | |||
58d88f3dd4 | |||
e980c23177 | |||
75224321bb | |||
801af05b20 | |||
7611dbbddc | |||
6d40ca15bc | |||
32c1c19224 | |||
bbf6357222 | |||
dc16629c24 | |||
3718b9d768 | |||
c25eb088ec | |||
3feb3e52f8 | |||
8e730ef93d | |||
e0913a39ab | |||
7a27fbc001 | |||
ee0dbdad35 | |||
9225f88f89 | |||
a04839dd6b | |||
002006517a | |||
f5b202d438 | |||
a7df094ff4 | |||
1e6fa77633 | |||
eb4cff202c | |||
7ee777f405 | |||
81bd5c784e | |||
b526e132a7 | |||
1860f66de5 | |||
ded9ada9bc | |||
d0e6a2eb8b | |||
4e103a1963 | |||
475e927178 | |||
ca7932c4f0 | |||
8ab47d3321 | |||
def7e87151 | |||
27568c2bef | |||
0694a187d7 | |||
832601b36b | |||
578969c34c | |||
d1d0115aed | |||
c89e6ebfab | |||
ca1089b881 | |||
a1d04f2aad | |||
bf0604133c | |||
a82b2da16e | |||
f2273c0acc | |||
17bedac96c | |||
4831fad27a | |||
5e896cf582 | |||
add3491c57 | |||
f470576822 | |||
10760a53a8 | |||
eee805183c | |||
b8fb391022 | |||
3c698f1584 | |||
2fad52d684 | |||
ec64a68a71 | |||
db55562f6a | |||
d8409a9d2b | |||
0d0ce6eec1 | |||
483f313eda | |||
7b6c742178 | |||
d4a35ba6ff | |||
68b112837a | |||
e2f20ebf94 | |||
f870e4965a | |||
7ebcb219d6 | |||
c21913a66b | |||
77e956a29f | |||
08275c406a | |||
2931e1b87b | |||
153b422496 | |||
0f6a6d6fea | |||
91fdb3e2d4 | |||
d8e87bd881 | |||
922033c1b2 | |||
df1793efbf | |||
836a2700f2 | |||
8f3aaf77a1 | |||
00c059e5b1 | |||
f4f355c74a | |||
b465fc5aaf | |||
2d78eaa48d | |||
d08451bccc | |||
d8e785aed0 | |||
267b6f49b5 | |||
e6688f4b9d | |||
9d7b9771c2 | |||
136a9a39de | |||
3dcf628fdb | |||
e614e9787a | |||
e426fc0922 | |||
5d4bfffc7e | |||
207cdaf7a4 | |||
7315b581ce | |||
38efaae7b2 | |||
469e042216 | |||
0f1a4b9d8f | |||
7303c00296 | |||
fc55b34d84 | |||
6f67fc0e02 | |||
562d722ad5 | |||
144c1ba3a6 | |||
06b032af91 | |||
3603140114 | |||
e094785cbd | |||
e7408224ac | |||
e67c05c274 | |||
b22804efaf | |||
890f55f91a | |||
cc5fc0b892 | |||
5efe2b027a | |||
5b6569d0f9 | |||
0eda7ac498 | |||
a5ef353484 | |||
67a36d8d31 | |||
7cc3cc3990 | |||
dc0edc4c2b | |||
71d2f091e5 | |||
c2f062a391 | |||
224f490455 | |||
5b35232ab4 | |||
6d6db70e42 | |||
6830e15b4e | |||
3f07cad35d | |||
e951340033 | |||
db8912a735 | |||
0e297731a3 | |||
f20c4f98ac | |||
05e60cc7c0 | |||
55b4469767 | |||
f15516e478 | |||
17ceadbadf | |||
8c25b2b316 | |||
8b1ae404a3 | |||
13534cd4a9 | |||
abfb345503 | |||
42ae935496 | |||
434515d957 | |||
094f7803b7 | |||
b0c7bad391 | |||
e9a4a905ef | |||
7b6cd0cfbe | |||
b718b12083 | |||
cfa7258ff4 | |||
b70e0a0870 | |||
da8eb464b8 | |||
8f9d1cfa30 | |||
585009ac5c | |||
30ee65fd14 | |||
76428b16f0 | |||
0d7b14e2d8 | |||
a9d19d02b3 | |||
adcbe55307 | |||
aa99a7df64 | |||
00afa1ce52 | |||
e94bf4c63c | |||
ec5adffdc2 | |||
733c17ad3a | |||
53b0b562e6 | |||
fabae6e970 | |||
a9f9c40d8a | |||
6fc89607d3 | |||
2340760f53 | |||
39d6d2857e | |||
7b722a0001 | |||
e7682119e0 | |||
af6be44676 | |||
5a8f97a0b6 | |||
0d4dd385b8 | |||
94f0f3e966 | |||
43e31765e5 | |||
7c1bdfe713 |
13
.github/FUNDING.yml
vendored
Normal file
13
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
#patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: irmen
|
||||||
|
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
#liberapay: # Replace with a single Liberapay username
|
||||||
|
#issuehunt: # Replace with a single IssueHunt username
|
||||||
|
#otechie: # Replace with a single Otechie username
|
||||||
|
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||||
|
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
41
.github/workflows/all-ci.yml
vendored
Normal file
41
.github/workflows/all-ci.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
name: Build and Test the Prog8 compiler
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: build and install recent 64tass
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y make build-essential
|
||||||
|
git clone --depth=1 https://github.com/irmen/64tass
|
||||||
|
cd 64tass
|
||||||
|
make -j4
|
||||||
|
sudo make install
|
||||||
|
|
||||||
|
- name: Set up JDK 11
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: 11
|
||||||
|
distribution: temurin
|
||||||
|
|
||||||
|
- name: Build and test with Gradle
|
||||||
|
run: |
|
||||||
|
./gradlew build shadowJar --no-daemon
|
||||||
|
sha256sum -b compiler/build/libs/*-all.jar > compiler/build/libs/hash.txt
|
||||||
|
|
||||||
|
- name: Create compiler shadowJar artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: prog8-compiler-jar-zipped
|
||||||
|
path: |
|
||||||
|
compiler/build/libs/*-all.jar
|
||||||
|
compiler/build/libs/hash.txt
|
||||||
|
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,8 +1,12 @@
|
|||||||
.idea/workspace.xml
|
.idea/workspace.xml
|
||||||
.idea/discord.xml
|
.idea/discord.xml
|
||||||
|
.idea/developer-tools.xml
|
||||||
|
.idea/usage.statistics.xml
|
||||||
|
.idea/shelf/
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
output/
|
output/
|
||||||
|
out/
|
||||||
.*cache/
|
.*cache/
|
||||||
*.directory
|
*.directory
|
||||||
*.prg
|
*.prg
|
||||||
@ -11,16 +15,17 @@ output/
|
|||||||
*.vm.txt
|
*.vm.txt
|
||||||
*.vice-mon-list
|
*.vice-mon-list
|
||||||
docs/build
|
docs/build
|
||||||
out/
|
|
||||||
parser/**/*.interp
|
parser/**/*.interp
|
||||||
parser/**/*.tokens
|
parser/**/*.tokens
|
||||||
parser/**/*.java
|
parser/**/*.java
|
||||||
|
compiler/src/prog8/buildversion/*
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*.egg
|
*.egg
|
||||||
*.egg-info
|
*.egg-info
|
||||||
.eggs/
|
.eggs/
|
||||||
/MANIFEST
|
/MANIFEST
|
||||||
.tox/
|
.tox/
|
||||||
|
.kotlin/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
parser.out
|
parser.out
|
||||||
parsetab.py
|
parsetab.py
|
||||||
@ -29,6 +34,6 @@ parsetab.py
|
|||||||
compiler/lib/
|
compiler/lib/
|
||||||
|
|
||||||
.gradle
|
.gradle
|
||||||
/prog8compiler.jar
|
|
||||||
sd*.img
|
sd*.img
|
||||||
*.d64
|
*.d64
|
||||||
|
|
||||||
|
9
.idea/inspectionProfiles/Project_Default.xml
generated
9
.idea/inspectionProfiles/Project_Default.xml
generated
@ -9,6 +9,15 @@
|
|||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
<inspection_tool class="IncompleteDestructuring" enabled="true" level="WARNING" enabled_by_default="true" />
|
<inspection_tool class="IncompleteDestructuring" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
<inspection_tool class="PyInterpreterInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="PyInterpreterInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredPackages">
|
||||||
|
<value>
|
||||||
|
<list size="1">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="sphinx_rtd_theme" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
<inspection_tool class="SpellCheckingInspection" enabled="true" level="TYPO" enabled_by_default="true">
|
<inspection_tool class="SpellCheckingInspection" enabled="true" level="TYPO" enabled_by_default="true">
|
||||||
<option name="processCode" value="false" />
|
<option name="processCode" value="false" />
|
||||||
<option name="processLiterals" value="true" />
|
<option name="processLiterals" value="true" />
|
||||||
|
19
.idea/kotlinc.xml
generated
Normal file
19
.idea/kotlinc.xml
generated
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Kotlin2JsCompilerArguments">
|
||||||
|
<option name="moduleKind" value="plain" />
|
||||||
|
</component>
|
||||||
|
<component name="Kotlin2JvmCompilerArguments">
|
||||||
|
<option name="jvmTarget" value="11" />
|
||||||
|
</component>
|
||||||
|
<component name="KotlinCommonCompilerArguments">
|
||||||
|
<option name="apiVersion" value="2.1" />
|
||||||
|
<option name="languageVersion" value="2.1" />
|
||||||
|
</component>
|
||||||
|
<component name="KotlinCompilerSettings">
|
||||||
|
<option name="additionalArguments" value="-Xwhen-guards" />
|
||||||
|
</component>
|
||||||
|
<component name="KotlinJpsPluginSettings">
|
||||||
|
<option name="version" value="2.1.0" />
|
||||||
|
</component>
|
||||||
|
</project>
|
28
.idea/libraries/KotlinJavaRuntime.xml
generated
28
.idea/libraries/KotlinJavaRuntime.xml
generated
@ -1,19 +1,23 @@
|
|||||||
<component name="libraryTable">
|
<component name="libraryTable">
|
||||||
<library name="KotlinJavaRuntime">
|
<library name="KotlinJavaRuntime" type="repository">
|
||||||
|
<properties maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.0" />
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.1.0/kotlin-stdlib-jdk8-2.1.0.jar!/" />
|
||||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-reflect.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0.jar!/" />
|
||||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-test.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk7.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.1.0/kotlin-stdlib-jdk7-2.1.0.jar!/" />
|
||||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk8.jar!/" />
|
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC />
|
<JAVADOC>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.1.0/kotlin-stdlib-jdk8-2.1.0-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.1.0/kotlin-stdlib-jdk7-2.1.0-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
<SOURCES>
|
<SOURCES>
|
||||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-sources.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.1.0/kotlin-stdlib-jdk8-2.1.0-sources.jar!/" />
|
||||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-reflect-sources.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0-sources.jar!/" />
|
||||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-test-sources.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
|
||||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk7-sources.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.1.0/kotlin-stdlib-jdk7-2.1.0-sources.jar!/" />
|
||||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk8-sources.jar!/" />
|
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
</component>
|
</component>
|
9
.idea/libraries/antlr_antlr4.xml
generated
9
.idea/libraries/antlr_antlr4.xml
generated
@ -1,17 +1,16 @@
|
|||||||
<component name="libraryTable">
|
<component name="libraryTable">
|
||||||
<library name="antlr.antlr4" type="repository">
|
<library name="antlr.antlr4" type="repository">
|
||||||
<properties maven-id="org.antlr:antlr4:4.10.1">
|
<properties maven-id="org.antlr:antlr4:4.13.2">
|
||||||
<exclude>
|
<exclude>
|
||||||
<dependency maven-id="com.ibm.icu:icu4j" />
|
<dependency maven-id="com.ibm.icu:icu4j" />
|
||||||
</exclude>
|
</exclude>
|
||||||
</properties>
|
</properties>
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4/4.10.1/antlr4-4.10.1.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4/4.13.2/antlr4-4.13.2.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4-runtime/4.10.1/antlr4-runtime-4.10.1.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4-runtime/4.13.2/antlr4-runtime-4.13.2.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr-runtime/3.5.3/antlr-runtime-3.5.3.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr-runtime/3.5.3/antlr-runtime-3.5.3.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/ST4/4.3.3/ST4-4.3.3.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/ST4/4.3.4/ST4-4.3.4.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/abego/treelayout/org.abego.treelayout.core/1.0.3/org.abego.treelayout.core-1.0.3.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/abego/treelayout/org.abego.treelayout.core/1.0.3/org.abego.treelayout.core-1.0.3.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/glassfish/javax.json/1.0.4/javax.json-1.0.4.jar!/" />
|
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC />
|
<JAVADOC />
|
||||||
<SOURCES />
|
<SOURCES />
|
||||||
|
13
.idea/libraries/eclipse_lsp4j.xml
generated
Normal file
13
.idea/libraries/eclipse_lsp4j.xml
generated
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="eclipse.lsp4j" type="repository">
|
||||||
|
<properties maven-id="org.eclipse.lsp4j:org.eclipse.lsp4j:0.23.1" />
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/lsp4j/org.eclipse.lsp4j/0.23.1/org.eclipse.lsp4j-0.23.1.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/lsp4j/org.eclipse.lsp4j.jsonrpc/0.23.1/org.eclipse.lsp4j.jsonrpc-0.23.1.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/com/google/errorprone/error_prone_annotations/2.27.0/error_prone_annotations-2.27.0.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
25
.idea/libraries/github_hypfvieh_dbus_java.xml
generated
25
.idea/libraries/github_hypfvieh_dbus_java.xml
generated
@ -1,25 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="github.hypfvieh.dbus.java" type="repository">
|
|
||||||
<properties maven-id="com.github.hypfvieh:dbus-java:3.3.1" />
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/hypfvieh/dbus-java/3.3.1/dbus-java-3.3.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/jnr/jnr-unixsocket/0.38.6/jnr-unixsocket-0.38.6.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/jnr/jnr-ffi/2.2.2/jnr-ffi-2.2.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/jnr/jffi/1.3.1/jffi-1.3.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/jnr/jffi/1.3.1/jffi-1.3.1-native.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/ow2/asm/asm/9.1/asm-9.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/ow2/asm/asm-commons/9.1/asm-commons-9.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/ow2/asm/asm-analysis/9.1/asm-analysis-9.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/ow2/asm/asm-tree/9.1/asm-tree-9.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/ow2/asm/asm-util/9.1/asm-util-9.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/jnr/jnr-a64asm/1.0.0/jnr-a64asm-1.0.0.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/jnr/jnr-constants/0.10.1/jnr-constants-0.10.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/jnr/jnr-enxio/0.32.4/jnr-enxio-0.32.4.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/jnr/jnr-posix/3.1.5/jnr-posix-3.1.5.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
10
.idea/libraries/glassfish_javax_json.xml
generated
10
.idea/libraries/glassfish_javax_json.xml
generated
@ -1,10 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="glassfish.javax.json" type="repository">
|
|
||||||
<properties include-transitive-deps="false" maven-id="org.glassfish:javax.json:1.1.4" />
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/glassfish/javax.json/1.1.4/javax.json-1.1.4.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
25
.idea/libraries/io_kotest_assertions_core_jvm.xml
generated
25
.idea/libraries/io_kotest_assertions_core_jvm.xml
generated
@ -1,21 +1,18 @@
|
|||||||
<component name="libraryTable">
|
<component name="libraryTable">
|
||||||
<library name="io.kotest.assertions.core.jvm" type="repository">
|
<library name="io.kotest.assertions.core.jvm" type="repository">
|
||||||
<properties maven-id="io.kotest:kotest-assertions-core-jvm:5.3.2" />
|
<properties maven-id="io.kotest:kotest-assertions-core-jvm:5.9.1" />
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-core-jvm/5.3.2/kotest-assertions-core-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-core-jvm/5.9.1/kotest-assertions-core-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.6.21/kotlin-stdlib-jdk8-1.6.21.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.9.1/kotest-assertions-shared-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.6.21/kotlin-stdlib-1.6.21.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.23/kotlin-stdlib-1.9.23.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.6.21/kotlin-stdlib-jdk7-1.6.21.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.8.0/kotlinx-coroutines-jdk8-1.8.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.3.2/kotest-assertions-shared-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.9.23/kotlin-reflect-1.9.23.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.11/java-diff-utils-4.11.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.9.1/kotest-common-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.9.1/kotest-assertions-api-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.6.1/kotlinx-coroutines-jdk8-1.6.1.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.8.0/kotlinx-coroutines-core-jvm-1.8.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.6.21/kotlin-reflect-1.6.21.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.6.1/kotlinx-coroutines-core-jvm-1.6.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.0/kotlin-stdlib-common-1.6.0.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.3.2/kotest-common-jvm-5.3.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.3.2/kotest-assertions-api-jvm-5.3.2.jar!/" />
|
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC />
|
<JAVADOC />
|
||||||
<SOURCES />
|
<SOURCES />
|
||||||
|
23
.idea/libraries/io_kotest_framework_datatest.xml
generated
Normal file
23
.idea/libraries/io_kotest_framework_datatest.xml
generated
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="io.kotest.framework.datatest" type="repository">
|
||||||
|
<properties maven-id="io.kotest:kotest-framework-datatest:5.9.1" />
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-datatest/5.9.1/kotest-framework-datatest-5.9.1.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-datatest-jvm/5.9.1/kotest-framework-datatest-jvm-5.9.1.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.23/kotlin-stdlib-1.9.23.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.8.0/kotlinx-coroutines-core-jvm-1.8.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.9.1/kotest-common-jvm-5.9.1.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.9.23/kotlin-reflect-1.9.23.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-api-jvm/5.9.1/kotest-framework-api-jvm-5.9.1.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.9.1/kotest-assertions-shared-jvm-5.9.1.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.9.1/kotest-assertions-api-jvm-5.9.1.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.8.0/kotlinx-coroutines-jdk8-1.8.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-test-jvm/1.8.0/kotlinx-coroutines-test-jvm-1.8.0.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
24
.idea/libraries/io_kotest_property_jvm.xml
generated
24
.idea/libraries/io_kotest_property_jvm.xml
generated
@ -1,24 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="io.kotest.property.jvm" type="repository">
|
|
||||||
<properties maven-id="io.kotest:kotest-property-jvm:5.3.2" />
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-property-jvm/5.3.2/kotest-property-jvm-5.3.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/curious-odd-man/rgxgen/1.3/rgxgen-1.3.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.6.21/kotlin-stdlib-jdk8-1.6.21.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.6.21/kotlin-stdlib-1.6.21.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.6.21/kotlin-stdlib-jdk7-1.6.21.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.3.2/kotest-common-jvm-5.3.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.3.2/kotest-assertions-shared-jvm-5.3.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.3.2/kotest-assertions-api-jvm-5.3.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.6.1/kotlinx-coroutines-jdk8-1.6.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.11/java-diff-utils-4.11.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.6.21/kotlin-reflect-1.6.21.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.6.1/kotlinx-coroutines-core-jvm-1.6.1.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.0/kotlin-stdlib-common-1.6.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
70
.idea/libraries/io_kotest_runner_junit5_jvm.xml
generated
70
.idea/libraries/io_kotest_runner_junit5_jvm.xml
generated
@ -1,51 +1,39 @@
|
|||||||
<component name="libraryTable">
|
<component name="libraryTable">
|
||||||
<library name="io.kotest.runner.junit5.jvm" type="repository">
|
<library name="io.kotest.runner.junit5.jvm" type="repository">
|
||||||
<properties maven-id="io.kotest:kotest-runner-junit5-jvm:5.3.2" />
|
<properties maven-id="io.kotest:kotest-runner-junit5-jvm:5.9.1" />
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-runner-junit5-jvm/5.3.2/kotest-runner-junit5-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-runner-junit5-jvm/5.9.1/kotest-runner-junit5-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-api-jvm/5.3.2/kotest-framework-api-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-api-jvm/5.9.1/kotest-framework-api-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.3.2/kotest-assertions-shared-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.9.1/kotest-assertions-shared-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.11/java-diff-utils-4.11.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-test-jvm/1.6.1/kotlinx-coroutines-test-jvm-1.6.1.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-test-jvm/1.8.0/kotlinx-coroutines-test-jvm-1.8.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.3.2/kotest-common-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.9.1/kotest-common-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-engine-jvm/5.3.2/kotest-framework-engine-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-engine-jvm/5.9.1/kotest-framework-engine-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/github/classgraph/classgraph/4.8.146/classgraph-4.8.146.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/github/classgraph/classgraph/4.8.172/classgraph-4.8.172.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/ajalt/mordant/1.2.1/mordant-1.2.1.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/com/github/ajalt/mordant/1.2.1/mordant-1.2.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/ajalt/colormath/1.2.0/colormath-1.2.0.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/com/github/ajalt/colormath/1.2.0/colormath-1.2.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-debug/1.6.1/kotlinx-coroutines-debug-1.6.1.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-debug/1.8.0/kotlinx-coroutines-debug-1.8.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna/5.9.0/jna-5.9.0.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna/5.9.0/jna-5.9.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna-platform/5.9.0/jna-platform-5.9.0.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna-platform/5.9.0/jna-platform-5.9.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-discovery-jvm/5.3.2/kotest-framework-discovery-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy/1.10.9/byte-buddy-1.10.9.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-core-jvm/5.3.2/kotest-assertions-core-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy-agent/1.10.9/byte-buddy-agent-1.10.9.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.6.1/kotlinx-coroutines-jdk8-1.6.1.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-discovery-jvm/5.9.1/kotest-framework-discovery-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.3.2/kotest-assertions-api-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-core-jvm/5.9.1/kotest-assertions-core-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-extensions-jvm/5.3.2/kotest-extensions-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.8.0/kotlinx-coroutines-jdk8-1.8.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/2.11.0/commons-io-2.11.0.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.9.1/kotest-assertions-api-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/mockk/mockk/1.12.3/mockk-1.12.3.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-extensions-jvm/5.9.1/kotest-extensions-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/mockk/mockk-common/1.12.3/mockk-common-1.12.3.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-concurrency-jvm/5.9.1/kotest-framework-concurrency-jvm-5.9.1.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/mockk/mockk-dsl/1.12.3/mockk-dsl-1.12.3.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.8.0/kotlinx-coroutines-core-jvm-1.8.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/mockk/mockk-dsl-jvm/1.12.3/mockk-dsl-jvm-1.12.3.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/23.0.0/annotations-23.0.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/mockk/mockk-agent-jvm/1.12.3/mockk-agent-jvm-1.12.3.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.8.2/junit-platform-engine-1.8.2.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/mockk/mockk-agent-api/1.12.3/mockk-agent-api-1.12.3.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.8.2/junit-platform-commons-1.8.2.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/mockk/mockk-agent-common/1.12.3/mockk-agent-common-1.12.3.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/objenesis/objenesis/3.1/objenesis-3.1.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-suite-api/1.8.2/junit-platform-suite-api-1.8.2.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy/1.12.6/byte-buddy-1.12.6.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-launcher/1.8.2/junit-platform-launcher-1.8.2.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy-agent/1.12.6/byte-buddy-agent-1.12.6.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.8.2/junit-jupiter-api-5.8.2.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-concurrency-jvm/5.3.2/kotest-framework-concurrency-jvm-5.3.2.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.23/kotlin-stdlib-1.9.23.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.6.1/kotlinx-coroutines-core-jvm-1.6.1.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.9.23/kotlin-reflect-1.9.23.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.0/kotlin-stdlib-common-1.6.0.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.7.2/junit-platform-engine-1.7.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.7.2/junit-platform-commons-1.7.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-suite-api/1.7.2/junit-platform-suite-api-1.7.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-launcher/1.7.2/junit-platform-launcher-1.7.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.7.2/junit-jupiter-api-5.7.2.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.6.21/kotlin-stdlib-jdk8-1.6.21.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.6.21/kotlin-stdlib-1.6.21.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.6.21/kotlin-stdlib-jdk7-1.6.21.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.6.21/kotlin-reflect-1.6.21.jar!/" />
|
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC />
|
<JAVADOC />
|
||||||
<SOURCES />
|
<SOURCES />
|
||||||
|
4
.idea/libraries/jetbrains_kotlinx_cli_jvm.xml
generated
4
.idea/libraries/jetbrains_kotlinx_cli_jvm.xml
generated
@ -1,8 +1,8 @@
|
|||||||
<component name="libraryTable">
|
<component name="libraryTable">
|
||||||
<library name="jetbrains.kotlinx.cli.jvm" type="repository">
|
<library name="jetbrains.kotlinx.cli.jvm" type="repository">
|
||||||
<properties include-transitive-deps="false" maven-id="org.jetbrains.kotlinx:kotlinx-cli-jvm:0.3.4" />
|
<properties include-transitive-deps="false" maven-id="org.jetbrains.kotlinx:kotlinx-cli-jvm:0.3.6" />
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-cli-jvm/0.3.4/kotlinx-cli-jvm-0.3.4.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-cli-jvm/0.3.6/kotlinx-cli-jvm-0.3.6.jar!/" />
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC />
|
<JAVADOC />
|
||||||
<SOURCES />
|
<SOURCES />
|
||||||
|
21
.idea/libraries/michael_bull_kotlin_result_jvm.xml
generated
21
.idea/libraries/michael_bull_kotlin_result_jvm.xml
generated
@ -1,15 +1,20 @@
|
|||||||
<component name="libraryTable">
|
<component name="libraryTable">
|
||||||
<library name="michael.bull.kotlin.result.jvm" type="repository">
|
<library name="michael.bull.kotlin.result.jvm" type="repository">
|
||||||
<properties maven-id="com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16" />
|
<properties maven-id="com.michael-bull.kotlin-result:kotlin-result-jvm:2.0.0" />
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/1.1.16/kotlin-result-jvm-1.1.16.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20/kotlin-stdlib-common-1.6.20.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.6.20/kotlin-stdlib-jdk8-1.6.20.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.6.20/kotlin-stdlib-1.6.20.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.6.20/kotlin-stdlib-jdk7-1.6.20.jar!/" />
|
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC />
|
<JAVADOC>
|
||||||
<SOURCES />
|
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0-sources.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22-sources.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
</component>
|
</component>
|
11
.idea/libraries/slf4j_simple.xml
generated
11
.idea/libraries/slf4j_simple.xml
generated
@ -1,11 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="slf4j.simple" type="repository">
|
|
||||||
<properties maven-id="org.slf4j:slf4j-simple:1.7.36" />
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-simple/1.7.36/slf4j-simple-1.7.36.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
17
.idea/libraries/takes.xml
generated
17
.idea/libraries/takes.xml
generated
@ -1,17 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="takes" type="repository">
|
|
||||||
<properties maven-id="org.takes:takes:1.20" />
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/takes/takes/1.20/takes-1.20.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/cactoos/cactoos/0.50/cactoos-0.50.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/javax/xml/bind/jaxb-api/2.3.0/jaxb-api-2.3.0.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/apache/commons/commons-text/1.4/commons-text-1.4.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/sun/xml/bind/jaxb-core/2.3.0/jaxb-core-2.3.0.jar!/" />
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/sun/xml/bind/jaxb-impl/2.3.0/jaxb-impl-2.3.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
9
.idea/misc.xml
generated
9
.idea/misc.xml
generated
@ -4,22 +4,25 @@
|
|||||||
<option name="perGrammarGenerationSettings">
|
<option name="perGrammarGenerationSettings">
|
||||||
<list>
|
<list>
|
||||||
<PerGrammarGenerationSettings>
|
<PerGrammarGenerationSettings>
|
||||||
<option name="fileName" value="$PROJECT_DIR$/parser/antlr/Prog8ANTLR.g4" />
|
<option name="fileName" value="$PROJECT_DIR$/parser/src/main/antlr/Prog8ANTLR.g4" />
|
||||||
<option name="autoGen" value="true" />
|
<option name="autoGen" value="true" />
|
||||||
<option name="outputDir" value="$PROJECT_DIR$/parser/src/prog8/parser" />
|
<option name="outputDir" value="$PROJECT_DIR$/parser/src/prog8/parser" />
|
||||||
<option name="libDir" value="" />
|
<option name="libDir" value="" />
|
||||||
<option name="encoding" value="" />
|
<option name="encoding" value="" />
|
||||||
<option name="pkg" value="" />
|
<option name="pkg" value="" />
|
||||||
<option name="language" value="" />
|
<option name="language" value="Java" />
|
||||||
<option name="generateListener" value="false" />
|
<option name="generateListener" value="false" />
|
||||||
</PerGrammarGenerationSettings>
|
</PerGrammarGenerationSettings>
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.11" />
|
||||||
|
</component>
|
||||||
<component name="FrameworkDetectionExcludesConfiguration">
|
<component name="FrameworkDetectionExcludesConfiguration">
|
||||||
<type id="Python" />
|
<type id="Python" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="openjdk-17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
5
.idea/modules.xml
generated
5
.idea/modules.xml
generated
@ -2,6 +2,8 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/beanshell/beanshell.iml" filepath="$PROJECT_DIR$/beanshell/beanshell.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/benchmark-program/benchmark-program.iml" filepath="$PROJECT_DIR$/benchmark-program/benchmark-program.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/codeCore/codeCore.iml" filepath="$PROJECT_DIR$/codeCore/codeCore.iml" />
|
<module fileurl="file://$PROJECT_DIR$/codeCore/codeCore.iml" filepath="$PROJECT_DIR$/codeCore/codeCore.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" filepath="$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" />
|
<module fileurl="file://$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" filepath="$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" filepath="$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" />
|
<module fileurl="file://$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" filepath="$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" />
|
||||||
@ -10,12 +12,11 @@
|
|||||||
<module fileurl="file://$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" filepath="$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" />
|
<module fileurl="file://$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" filepath="$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/compiler/compiler.iml" filepath="$PROJECT_DIR$/compiler/compiler.iml" />
|
<module fileurl="file://$PROJECT_DIR$/compiler/compiler.iml" filepath="$PROJECT_DIR$/compiler/compiler.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/compilerAst/compilerAst.iml" filepath="$PROJECT_DIR$/compilerAst/compilerAst.iml" />
|
<module fileurl="file://$PROJECT_DIR$/compilerAst/compilerAst.iml" filepath="$PROJECT_DIR$/compilerAst/compilerAst.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/dbusCompilerService/dbusCompilerService.iml" filepath="$PROJECT_DIR$/dbusCompilerService/dbusCompilerService.iml" />
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
|
<module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
|
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/httpCompilerService/httpCompilerService.iml" filepath="$PROJECT_DIR$/httpCompilerService/httpCompilerService.iml" />
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" />
|
<module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
|
<module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/prog8.iml" filepath="$PROJECT_DIR$/.idea/modules/prog8.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/virtualmachine/virtualmachine.iml" filepath="$PROJECT_DIR$/virtualmachine/virtualmachine.iml" />
|
<module fileurl="file://$PROJECT_DIR$/virtualmachine/virtualmachine.iml" filepath="$PROJECT_DIR$/virtualmachine/virtualmachine.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
|
@ -7,23 +7,21 @@ version: 2
|
|||||||
|
|
||||||
# Set the version of Python and other tools you might need
|
# Set the version of Python and other tools you might need
|
||||||
build:
|
build:
|
||||||
os: ubuntu-20.04
|
os: ubuntu-22.04
|
||||||
tools:
|
tools:
|
||||||
python: "3.9"
|
python: "3.12"
|
||||||
# You can also specify other tool versions:
|
|
||||||
# nodejs: "16"
|
|
||||||
# rust: "1.55"
|
|
||||||
# golang: "1.17"
|
|
||||||
|
|
||||||
# Build documentation in the docs/ directory with Sphinx
|
|
||||||
sphinx:
|
|
||||||
configuration: docs/source/conf.py
|
|
||||||
|
|
||||||
# If using Sphinx, optionally build your docs in additional formats such as PDF
|
|
||||||
formats:
|
|
||||||
- pdf
|
|
||||||
|
|
||||||
# Optionally declare the Python requirements required to build your docs
|
# Optionally declare the Python requirements required to build your docs
|
||||||
python:
|
python:
|
||||||
install:
|
install:
|
||||||
- requirements: docs/requirements.txt
|
- requirements: docs/requirements.txt
|
||||||
|
|
||||||
|
# Build documentation in the docs/ directory with Sphinx
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/source/conf.py
|
||||||
|
fail_on_warning: true
|
||||||
|
|
||||||
|
# If using Sphinx, optionally build your docs in additional formats such as PDF
|
||||||
|
formats:
|
||||||
|
- pdf
|
||||||
|
- epub
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
#### Just a few remarks upfront:
|
|
||||||
* There is the (gradle/IDEA) module `parser`: that's the parser generated by ANTLR4, in Java. The only file to be edited here is the grammar, `prog8.g4`.
|
|
||||||
* Then we have the module `compilerAst` - in Kotlin - which uses `parser` and adds AST nodes. Here we put our additions to the generated thing, *including any tests of the parsing stage*.
|
|
||||||
- the name is a bit misleading, as this module isn't (or, resp. shouldn't be; see below) about *compiling*, only the parsing stage
|
|
||||||
- also, the tree that comes out isn't much of an *abstraction*, but rather still more or less a parse tree (this might very well change).
|
|
||||||
- **However, let's not *yet* rename the module.** We'll find a good name during refactoring.
|
|
||||||
|
|
||||||
#### Problems with `compilerAst`:
|
|
||||||
* `ModuleImporter.kt`, doing (Prog8-) module resolution. That's not the parser's job.
|
|
||||||
* `ParsingFailedError` (in `ModuleParsing.kt`): this exception (it is actually *not* a `java.lang.Error`...) is thrown in a number of places, where other exceptions would make more sense. For example: not finding a file should just yield a `NoSuchFileException`, not this one. The other problem with it is that it does not provide any additional information about the source of parsing error, in particular a `Position`.
|
|
||||||
* During parsing, character literals are turned into UBYTEs (since there is no basic type e.g. CHAR). That's bad because it depends on a specific character encoding (`IStringEncoding` in `compilerAst/src/prog8/ast/AstToplevel.kt`) of/for some target platform. Note that *strings* are indeed encoded later, in the `compiler` module.
|
|
||||||
* The same argument applies to `IMemSizer`, and - not entirely sure about that - `IBuiltinFunctions`.
|
|
||||||
|
|
||||||
#### Steps to take, in conceptual (!) order:
|
|
||||||
|
|
||||||
(note: all these steps have been implemented, rejected or otherwise solved now.)
|
|
||||||
|
|
||||||
1. introduce an abstraction `SourceCode` that encapsulates the origin and actual loading of Prog8 source code
|
|
||||||
- from the local file system (use case: user programs)
|
|
||||||
- from resources (prog8lib)
|
|
||||||
- from plain strings (for testing)
|
|
||||||
2. add subclass `ParseError : ParsingFailedError` which adds information about the *source of parsing error* (`SourceCode` and `Position`). We cannot just replace `ParsingFailedError` right away because it is so widely used (even in the `compiler` module). Therefore we'll just subclass for the time being, add more and more tests requiring the new one to be thrown (or, resp., NOT to be thrown), and gradually transition.
|
|
||||||
3. introduce a minimal interface to the outside, input: `SourceCode`, output: a tree with a `Module` node as the root
|
|
||||||
- this will be the Kotlin singleton `Prog8Parser` with the main method `parseModule`
|
|
||||||
- plus, optionally, method's for registering/unregistering a listener with the parser
|
|
||||||
- the *only* exception ever thrown / reported to listeners (TBD) will be `ParseError`
|
|
||||||
- anything related to the lexer, error strategies, character/token streams is hidden from the outside
|
|
||||||
- to make a clear distinction between the *generated* parser (and lexer) vs. `Prog8Parser`, and to discourage directly using the generated stuff, we'll rename the existing `prog8Parser`/`prog8Lexer` to `Prog8ANTLRParser` and `Prog8ANTLRLexer` and move them to package `prog8.parser.generated`
|
|
||||||
4. introduce AST node `CharLiteral` and keep them until after identifier resolution and type checking; insert there an AST transformation step that turns them in UBYTE constants (literals)
|
|
||||||
5. remove uses of `IStringEncoding` from module `compilerAst` - none should be necessary anymore
|
|
||||||
6. move `IStringEncoding` to module `compiler`
|
|
||||||
7. same with `ModuleImporter`, then rewrite that (addressing #46)
|
|
||||||
8. refactor AST nodes and grammar: less generated parse tree nodes (`XyzContext`), less intermediary stuff (private classes in `Antrl2Kotlin.kt`), more compact code. Also: nicer names such as simply `StringLiteral` instead of `StringLiteralValue`
|
|
||||||
9. re-think `IStringEncoding` to address #38
|
|
||||||
|
|
12
Makefile
Normal file
12
Makefile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# super simple Makefile to lauch the main gradle targets to build and/or test the prog8 compiler
|
||||||
|
|
||||||
|
.PHONY: all test
|
||||||
|
|
||||||
|
all:
|
||||||
|
gradle installdist installshadowdist
|
||||||
|
@echo "compiler launch script can be found here: compiler/build/install/compiler-shadow/bin/prog8c"
|
||||||
|
|
||||||
|
test:
|
||||||
|
gradle build
|
||||||
|
@echo "compiler launch script can be found here: compiler/build/install/compiler-shadow/bin/prog8c"
|
||||||
|
|
72
README.md
72
README.md
@ -1,3 +1,4 @@
|
|||||||
|
[](https://ko-fi.com/H2H6S0FFF)
|
||||||
[](https://prog8.readthedocs.io/)
|
[](https://prog8.readthedocs.io/)
|
||||||
|
|
||||||
Prog8 - Structured Programming Language for 8-bit 6502/65c02 microprocessors
|
Prog8 - Structured Programming Language for 8-bit 6502/65c02 microprocessors
|
||||||
@ -9,11 +10,37 @@ This is a structured programming language for the 8-bit 6502/6510/65c02 micropro
|
|||||||
as used in many home computers from that era. It is a medium to low level programming language,
|
as used in many home computers from that era. It is a medium to low level programming language,
|
||||||
which aims to provide many conveniences over raw assembly code (even when using a macro assembler).
|
which aims to provide many conveniences over raw assembly code (even when using a macro assembler).
|
||||||
|
|
||||||
|
**Want to buy me a coffee or a pizza perhaps?**
|
||||||
|
|
||||||
|
This project was created over the last couple of years by dedicating thousands of hours of my free time to it, to make it the best I possibly can.
|
||||||
|
If you like Prog8, and think it's worth a nice cup of hot coffee or a delicious pizza,
|
||||||
|
you can help me out a little bit over at [ko-fi.com/irmen](https://ko-fi.com/irmen).
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
Full documentation (syntax reference, how to use the language and the compiler, etc.) can be found at:
|
Full documentation (syntax reference, how to use the language and the compiler, etc.) can be found at:
|
||||||
https://prog8.readthedocs.io/
|
https://prog8.readthedocs.io/
|
||||||
|
|
||||||
|
How to get it/build it
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
- Download the latest [official release](https://github.com/irmen/prog8/releases) from github.
|
||||||
|
- Or, if you want/need a bleeding edge development version, you can:
|
||||||
|
- download a build artifact zipfile from a recent [github action build](https://github.com/irmen/prog8/actions).
|
||||||
|
- you can also compile it yourself from source. [Instructions here](https://prog8.readthedocs.io/en/latest/compiling.html).
|
||||||
|
Note that if you are not using *gradle* to build it, you might have to perform some manual
|
||||||
|
tasks once to make it compile fully. These are explained in the linked instructions.
|
||||||
|
- Alternatively, you can also install the compiler as a package on some linux distros:
|
||||||
|
- Arch (via AUR): [`prog8`](https://aur.archlinux.org/packages/prog8)
|
||||||
|
|
||||||
|
Community
|
||||||
|
---------
|
||||||
|
Most of the development on Prog8 and the use of it is currently centered around
|
||||||
|
the [Commander X16](https://www.commanderx16.com/) retro computer. Their [discord server](https://discord.gg/nS2PqEC) contains a small channel
|
||||||
|
dedicated to Prog8. Other than that, use the issue tracker on github.
|
||||||
|
|
||||||
|
|
||||||
Software license
|
Software license
|
||||||
----------------
|
----------------
|
||||||
GNU GPL 3.0 (see file LICENSE), with exception for generated code:
|
GNU GPL 3.0 (see file LICENSE), with exception for generated code:
|
||||||
@ -26,26 +53,27 @@ GNU GPL 3.0 (see file LICENSE), with exception for generated code:
|
|||||||
What does Prog8 provide?
|
What does Prog8 provide?
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
- reduction of source code length over raw assembly
|
- all advantages of a higher level language over having to write assembly code manually
|
||||||
- fast execution speed due to compilation to native assembly code. It's possible to write certain raster interrupt 'demoscene' effects purely in Prog8.
|
- programs run very fast because it's compiled to native machine code
|
||||||
- modularity, symbol scoping, subroutines
|
- code often is smaller and faster than equivalent C code compiled with CC65 or even LLVM-MOS
|
||||||
|
- modularity, symbol scoping, subroutines. No need for forward declarations.
|
||||||
- various data types other than just bytes (16-bit words, floats, strings)
|
- various data types other than just bytes (16-bit words, floats, strings)
|
||||||
- floating point math is supported if the target system provides floating point library routines (C64 and Cx16 both do)
|
- floating point math is supported on certain targets
|
||||||
- strings can contain escaped characters but also many symbols directly if they have a petscii equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \, {, } and | are also accepted and converted to the closest petscii equivalents.
|
- strings can contain escaped characters but also many symbols directly if they have a petscii equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \, {, } and | are also accepted and converted to the closest petscii equivalents.
|
||||||
- automatic static variable allocations, automatic string and array variables and string sharing
|
- automatic static variable allocations, automatic string and array variables and string sharing
|
||||||
- subroutines with input parameters and result values
|
|
||||||
- high-level program optimizations
|
- high-level program optimizations
|
||||||
- small program boilerplate/compilersupport overhead
|
|
||||||
- programs can be run multiple times without reloading because of automatic variable (re)initializations.
|
- programs can be run multiple times without reloading because of automatic variable (re)initializations.
|
||||||
- conditional branches
|
- conditional branches that map 1:1 to cpu status flags
|
||||||
- ``when`` statement to provide a concise jump table alternative to if/elseif chains
|
- ``when`` statement to provide a concise jump table alternative to if/elseif chains
|
||||||
- ``in`` expression for concise and efficient multi-value/containment check
|
- ``in`` expression for concise and efficient multi-value/containment check
|
||||||
- many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``sort`` and ``reverse``
|
- ``defer`` statement to help write concise and robust subroutine cleanup logic
|
||||||
|
- several specialized built-in functions such as ``lsb``, ``msb``, ``min``, ``max``, ``rol``, ``ror``
|
||||||
- various powerful built-in libraries to do I/O, number conversions, graphics and more
|
- various powerful built-in libraries to do I/O, number conversions, graphics and more
|
||||||
- convenience abstractions for low level aspects such as ZeroPage handling, program startup, explicit memory addresses
|
|
||||||
- inline assembly allows you to have full control when every cycle or byte matters
|
- inline assembly allows you to have full control when every cycle or byte matters
|
||||||
- supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16, and provides them also on the C64.
|
- supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16 (also available on other targets)
|
||||||
- encode strings and characters into petscii or screencodes as desired (C64/Cx16)
|
- encode strings and characters into petscii or screencodes or even other encodings
|
||||||
|
- Automatic ROM/RAM bank switching on certain compiler targets when calling routines in other banks
|
||||||
|
- 50 Kb of available program RAM size on the C64 by default; because Basic ROM is banked out altogether
|
||||||
|
|
||||||
*Rapid edit-compile-run-debug cycle:*
|
*Rapid edit-compile-run-debug cycle:*
|
||||||
|
|
||||||
@ -56,9 +84,12 @@ What does Prog8 provide?
|
|||||||
|
|
||||||
*Multiple supported compiler targets* (contributions to improve these or to add support for other machines are welcome!):
|
*Multiple supported compiler targets* (contributions to improve these or to add support for other machines are welcome!):
|
||||||
|
|
||||||
|
- "cx16": [CommanderX16](https://www.commanderx16.com) (65c02 CPU)
|
||||||
- "c64": Commodore-64 (6502 like CPU)
|
- "c64": Commodore-64 (6502 like CPU)
|
||||||
- "c128": Commodore-128 (6502 like CPU - the Z80 cpu mode is not supported)
|
- "c128": Commodore-128 (6502 like CPU - the Z80 cpu mode is not supported)
|
||||||
- "cx16": [CommanderX16](https://www.commanderx16.com) (65c02 CPU)
|
- "pet32": Commodore PET (limited support)
|
||||||
|
- "atari": Atari 8 bit such as 800XL (experimental)
|
||||||
|
- "neo": Neo6502 (experimental)
|
||||||
- If you only use standard kernal and prog8 library routines, it is possible to compile the *exact same program* for different machines (just change the compiler target flag)
|
- If you only use standard kernal and prog8 library routines, it is possible to compile the *exact same program* for different machines (just change the compiler target flag)
|
||||||
|
|
||||||
|
|
||||||
@ -76,7 +107,12 @@ IntelliJ IDEA with the Kotlin plugin).
|
|||||||
|
|
||||||
It's handy to have an emulator (or a real machine perhaps!) to run the programs on. The compiler assumes the presence
|
It's handy to have an emulator (or a real machine perhaps!) to run the programs on. The compiler assumes the presence
|
||||||
of the [Vice emulator](http://vice-emu.sourceforge.net/) for the C64 target,
|
of the [Vice emulator](http://vice-emu.sourceforge.net/) for the C64 target,
|
||||||
and the [x16emu emulator](https://github.com/commanderx16/x16-emulator) for the CommanderX16 target.
|
and a recent emulator version (R42 or newer) for the CommanderX16, such as [x16emu](https://cx16forum.com/forum/viewforum.php?f=30)
|
||||||
|
(preferred, this is the official emulator. If required, source code is [here](https://github.com/X16Community/x16-emulator/)).
|
||||||
|
There is also [Box16](https://github.com/indigodarkwolf/box16) which has powerful debugging features.
|
||||||
|
|
||||||
|
**Syntax highlighting:** for a few different editors, syntax highlighting definition files are provided.
|
||||||
|
Look in the [syntax-files](https://github.com/irmen/prog8/tree/master/syntax-files) directory in the github repository to find them.
|
||||||
|
|
||||||
|
|
||||||
Example code
|
Example code
|
||||||
@ -86,14 +122,13 @@ This code calculates prime numbers using the Sieve of Eratosthenes algorithm::
|
|||||||
|
|
||||||
%import textio
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
bool[256] sieve
|
||||||
ubyte[256] sieve
|
|
||||||
ubyte candidate_prime = 2 ; is increased in the loop
|
ubyte candidate_prime = 2 ; is increased in the loop
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
sys.memset(sieve, 256, false) ; clear the sieve
|
sys.memset(sieve, 256, 0) ; clear the sieve
|
||||||
txt.print("prime numbers up to 255:\n\n")
|
txt.print("prime numbers up to 255:\n\n")
|
||||||
ubyte amount=0
|
ubyte amount=0
|
||||||
repeat {
|
repeat {
|
||||||
@ -129,9 +164,6 @@ This code calculates prime numbers using the Sieve of Eratosthenes algorithm::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
when compiled an ran on a C-64 you'll get:
|
when compiled an ran on a C-64 you'll get:
|
||||||
|
|
||||||

|

|
||||||
|
@ -10,8 +10,15 @@
|
|||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||||
<orderEntry type="library" name="jetbrains.kotlinx.cli.jvm" level="project" />
|
<orderEntry type="library" name="jetbrains.kotlinx.cli.jvm" level="project" />
|
||||||
<orderEntry type="library" name="github.hypfvieh.dbus.java" level="project" />
|
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||||
<orderEntry type="library" name="slf4j.simple" level="project" />
|
<orderEntry type="module-library">
|
||||||
<orderEntry type="module" module-name="codeCore" />
|
<library>
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$MODULE_DIR$/lib/bsh-3.0.0-SNAPSHOT.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</orderEntry>
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
65
beanshell/build.gradle.kts
Normal file
65
beanshell/build.gradle.kts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("application")
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
val serverMainClassName = "prog8lsp.MainKt"
|
||||||
|
val applicationName = "prog8-beanshell"
|
||||||
|
|
||||||
|
application {
|
||||||
|
mainClass.set(serverMainClassName)
|
||||||
|
description = "Code completions, diagnostics and more for Prog8"
|
||||||
|
// applicationDefaultJvmArgs = listOf("-DkotlinLanguageServer.version=$version")
|
||||||
|
applicationDistribution.into("bin") {
|
||||||
|
filePermissions {
|
||||||
|
user {
|
||||||
|
read=true
|
||||||
|
execute=true
|
||||||
|
write=true
|
||||||
|
}
|
||||||
|
other.execute = true
|
||||||
|
group.execute = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(files("lib/bsh-3.0.0-SNAPSHOT.jar"))
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations.forEach { config ->
|
||||||
|
config.resolutionStrategy {
|
||||||
|
preferProjectModules()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets.main {
|
||||||
|
java.srcDir("src")
|
||||||
|
resources.srcDir("resources")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.startScripts {
|
||||||
|
applicationName = "prog8-beanshell"
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register<Exec>("fixFilePermissions") {
|
||||||
|
// When running on macOS or Linux the start script
|
||||||
|
// needs executable permissions to run.
|
||||||
|
|
||||||
|
onlyIf { !System.getProperty("os.name").lowercase().contains("windows") }
|
||||||
|
commandLine("chmod", "+x", "${tasks.installDist.get().destinationDir}/bin/prog8-beanshell")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.installDist {
|
||||||
|
finalizedBy("fixFilePermissions")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.build {
|
||||||
|
finalizedBy("installDist")
|
||||||
|
}
|
BIN
beanshell/lib/bsh-3.0.0-SNAPSHOT.jar
Normal file
BIN
beanshell/lib/bsh-3.0.0-SNAPSHOT.jar
Normal file
Binary file not shown.
48
beanshell/src/prog8beanshell/CommandLineReader.kt
Normal file
48
beanshell/src/prog8beanshell/CommandLineReader.kt
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package prog8beanshell
|
||||||
|
|
||||||
|
import java.io.FilterReader
|
||||||
|
import java.io.Reader
|
||||||
|
|
||||||
|
|
||||||
|
class CommandLineReader(val input: Reader): FilterReader(input) {
|
||||||
|
private val normal = 0
|
||||||
|
private val lastCharNL = 1
|
||||||
|
private val sentSemi = 2
|
||||||
|
private var state = lastCharNL
|
||||||
|
|
||||||
|
override fun read(): Int {
|
||||||
|
if (state == sentSemi) {
|
||||||
|
this.state = lastCharNL
|
||||||
|
return 10
|
||||||
|
} else {
|
||||||
|
var b = input.read()
|
||||||
|
while(b==13) b = input.read()
|
||||||
|
|
||||||
|
if (b == 10) {
|
||||||
|
if (this.state == lastCharNL) {
|
||||||
|
b = 59
|
||||||
|
this.state = sentSemi
|
||||||
|
} else {
|
||||||
|
this.state = lastCharNL
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.state = normal
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(buff: CharArray, off: Int, len: Int): Int {
|
||||||
|
val b = read()
|
||||||
|
if (b == -1) {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
buff[off] = b.toChar()
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
23
beanshell/src/prog8beanshell/Main.kt
Normal file
23
beanshell/src/prog8beanshell/Main.kt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package prog8beanshell
|
||||||
|
|
||||||
|
import bsh.FileReader
|
||||||
|
import bsh.Interpreter
|
||||||
|
|
||||||
|
|
||||||
|
class BeanshellInterpreter {
|
||||||
|
|
||||||
|
fun run(symbols: Map<String, Any>) {
|
||||||
|
val interpreter = Interpreter(CommandLineReader(FileReader(System.`in`)), System.out, System.err, true)
|
||||||
|
interpreter.setExitOnEOF(false)
|
||||||
|
symbols.forEach { (name, value) -> interpreter.set(name, value) }
|
||||||
|
interpreter.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val i = BeanshellInterpreter()
|
||||||
|
i.run(mapOf(
|
||||||
|
"env" to System.getenv(),
|
||||||
|
"args" to args
|
||||||
|
))
|
||||||
|
}
|
10
benchmark-program/Makefile
Normal file
10
benchmark-program/Makefile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.PHONY: clean run
|
||||||
|
|
||||||
|
run:
|
||||||
|
prog8c -target cx16 benchmark.p8
|
||||||
|
x16emu -run -prg benchmark.prg -warp
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.prg *.PRG *.asm *.vice-* *.BIN *.PAL *.zip *.7z
|
||||||
|
|
||||||
|
|
109
benchmark-program/b_3d.p8
Normal file
109
benchmark-program/b_3d.p8
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
%import textio
|
||||||
|
%import math
|
||||||
|
|
||||||
|
rotate3d {
|
||||||
|
const ubyte WIDTH = 40
|
||||||
|
const ubyte HEIGHT = 30
|
||||||
|
|
||||||
|
sub benchmark(uword max_time) -> uword {
|
||||||
|
|
||||||
|
uword anglex
|
||||||
|
uword angley
|
||||||
|
uword anglez
|
||||||
|
uword frames
|
||||||
|
|
||||||
|
txt.nl()
|
||||||
|
cbm.SETTIM(0,0,0)
|
||||||
|
|
||||||
|
while cbm.RDTIM16()<max_time {
|
||||||
|
matrix_math.rotate_vertices(msb(anglex), msb(angley), msb(anglez))
|
||||||
|
draw_edges() ; doesn't really draw anything in the benchmark, but does do the screen calculations
|
||||||
|
anglex+=500
|
||||||
|
angley+=215
|
||||||
|
anglez+=453
|
||||||
|
frames++
|
||||||
|
}
|
||||||
|
|
||||||
|
return frames
|
||||||
|
}
|
||||||
|
|
||||||
|
sub draw_edges() {
|
||||||
|
|
||||||
|
; plot the points of the 3d cube
|
||||||
|
; first the points on the back, then the points on the front (painter algorithm)
|
||||||
|
|
||||||
|
ubyte @zp i
|
||||||
|
word @zp rz
|
||||||
|
word @zp persp
|
||||||
|
byte @shared sx
|
||||||
|
byte @shared sy
|
||||||
|
|
||||||
|
for i in 0 to len(matrix_math.xcoor)-1 {
|
||||||
|
rz = matrix_math.rotatedz[i]
|
||||||
|
if rz >= 10 {
|
||||||
|
persp = 600 + rz/64
|
||||||
|
sx = matrix_math.rotatedx[i] / persp as byte + WIDTH/2
|
||||||
|
sy = matrix_math.rotatedy[i] / persp as byte + HEIGHT/2
|
||||||
|
;; txt.setcc(sx as ubyte, sy as ubyte, 46, 7)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0 to len(matrix_math.xcoor)-1 {
|
||||||
|
rz = matrix_math.rotatedz[i]
|
||||||
|
if rz < 10 {
|
||||||
|
persp = 600 + rz/64
|
||||||
|
sx = matrix_math.rotatedx[i] / persp as byte + WIDTH/2
|
||||||
|
sy = matrix_math.rotatedy[i] / persp as byte + HEIGHT/2
|
||||||
|
;; txt.setcc(sx as ubyte, sy as ubyte, 81, 7)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
txt.chrout('.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix_math {
|
||||||
|
; vertices
|
||||||
|
word[] xcoor = [ -40, -40, -40, -40, 40, 40, 40, 40 ]
|
||||||
|
word[] ycoor = [ -40, -40, 40, 40, -40, -40, 40, 40 ]
|
||||||
|
word[] zcoor = [ -40, 40, -40, 40, -40, 40, -40, 40 ]
|
||||||
|
|
||||||
|
; storage for rotated coordinates
|
||||||
|
word[len(xcoor)] rotatedx
|
||||||
|
word[len(ycoor)] rotatedy
|
||||||
|
word[len(zcoor)] rotatedz
|
||||||
|
|
||||||
|
sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) {
|
||||||
|
; rotate around origin (0,0,0)
|
||||||
|
|
||||||
|
; set up the 3d rotation matrix values
|
||||||
|
word wcosa = math.cos8(ax)
|
||||||
|
word wsina = math.sin8(ax)
|
||||||
|
word wcosb = math.cos8(ay)
|
||||||
|
word wsinb = math.sin8(ay)
|
||||||
|
word wcosc = math.cos8(az)
|
||||||
|
word wsinc = math.sin8(az)
|
||||||
|
|
||||||
|
word wcosa_sinb = wcosa*wsinb / 128
|
||||||
|
word wsina_sinb = wsina*wsinb / 128
|
||||||
|
|
||||||
|
word Axx = wcosa*wcosb / 128
|
||||||
|
word Axy = (wcosa_sinb*wsinc - wsina*wcosc) / 128
|
||||||
|
word Axz = (wcosa_sinb*wcosc + wsina*wsinc) / 128
|
||||||
|
word Ayx = wsina*wcosb / 128
|
||||||
|
word Ayy = (wsina_sinb*wsinc + wcosa*wcosc) / 128
|
||||||
|
word Ayz = (wsina_sinb*wcosc - wcosa*wsinc) / 128
|
||||||
|
word Azx = -wsinb
|
||||||
|
word Azy = wcosb*wsinc / 128
|
||||||
|
word Azz = wcosb*wcosc / 128
|
||||||
|
|
||||||
|
ubyte @zp i
|
||||||
|
for i in 0 to len(xcoor)-1 {
|
||||||
|
; don't normalize by dividing by 128, instead keep some precision for perspective calc later
|
||||||
|
rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i]
|
||||||
|
rotatedy[i] = Ayx*xcoor[i] + Ayy*ycoor[i] + Ayz*zcoor[i]
|
||||||
|
rotatedz[i] = Azx*xcoor[i] + Azy*ycoor[i] + Azz*zcoor[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
89
benchmark-program/b_adpcm.p8
Normal file
89
benchmark-program/b_adpcm.p8
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
adpcm {
|
||||||
|
|
||||||
|
sub decode_benchmark(uword max_time) -> uword {
|
||||||
|
uword num_blocks
|
||||||
|
txt.nl()
|
||||||
|
cbm.SETTIM(0,0,0)
|
||||||
|
|
||||||
|
while cbm.RDTIM16()<max_time {
|
||||||
|
adpcm.init(0,0)
|
||||||
|
uword @requirezp nibbles_ptr = $a000 ; for benchmark purposes, the exact nibbles don't really matter, so we just take the basic ROM as input
|
||||||
|
repeat 252/2 {
|
||||||
|
unroll 2 {
|
||||||
|
ubyte @zp nibble = @(nibbles_ptr)
|
||||||
|
adpcm.decode_nibble(nibble & 15) ; first word (note: upper nibble needs to be zero!)
|
||||||
|
adpcm.decode_nibble(nibble>>4) ; second word (note: upper nibble is zero, after the shifts.)
|
||||||
|
nibbles_ptr++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num_blocks++
|
||||||
|
txt.chrout('.')
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
; IMA ADPCM decoder. Supports mono and stereo streams.
|
||||||
|
|
||||||
|
byte[] t_index = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8]
|
||||||
|
uword[] t_step = [
|
||||||
|
7, 8, 9, 10, 11, 12, 13, 14,
|
||||||
|
16, 17, 19, 21, 23, 25, 28, 31,
|
||||||
|
34, 37, 41, 45, 50, 55, 60, 66,
|
||||||
|
73, 80, 88, 97, 107, 118, 130, 143,
|
||||||
|
157, 173, 190, 209, 230, 253, 279, 307,
|
||||||
|
337, 371, 408, 449, 494, 544, 598, 658,
|
||||||
|
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
||||||
|
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
||||||
|
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
||||||
|
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||||
|
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
||||||
|
32767]
|
||||||
|
|
||||||
|
uword @requirezp predict ; decoded 16 bit pcm sample for first channel.
|
||||||
|
ubyte @requirezp index
|
||||||
|
uword @requirezp pstep
|
||||||
|
|
||||||
|
sub init(uword startPredict, ubyte startIndex) {
|
||||||
|
; initialize first decoding channel.
|
||||||
|
predict = startPredict
|
||||||
|
index = startIndex
|
||||||
|
pstep = t_step[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
sub decode_nibble(ubyte @zp nibble) {
|
||||||
|
; Decoder for a single nibble for the first channel. (value of 'nibble' needs to be strictly 0-15 !)
|
||||||
|
; This is the hotspot of the decoder algorithm!
|
||||||
|
; Note that the generated assembly from this is pretty efficient,
|
||||||
|
; rewriting it by hand in asm seems to improve it only ~10%.
|
||||||
|
cx16.r0s = 0 ; difference
|
||||||
|
if nibble & %0100 !=0
|
||||||
|
cx16.r0s += pstep
|
||||||
|
pstep >>= 1
|
||||||
|
if nibble & %0010 !=0
|
||||||
|
cx16.r0s += pstep
|
||||||
|
pstep >>= 1
|
||||||
|
if nibble & %0001 !=0
|
||||||
|
cx16.r0s += pstep
|
||||||
|
pstep >>= 1
|
||||||
|
cx16.r0s += pstep
|
||||||
|
if nibble & %1000 !=0
|
||||||
|
predict -= cx16.r0
|
||||||
|
else
|
||||||
|
predict += cx16.r0
|
||||||
|
|
||||||
|
; NOTE: the original C/Python code uses a 32 bits prediction value and clips it to a 16 bit word
|
||||||
|
; but for speed reasons we only work with 16 bit words here all the time (with possible clipping error)
|
||||||
|
; if predicted > 32767:
|
||||||
|
; predicted = 32767
|
||||||
|
; elif predicted < -32767:
|
||||||
|
; predicted = - 32767
|
||||||
|
|
||||||
|
index += t_index[nibble] as ubyte
|
||||||
|
if_neg
|
||||||
|
index = 0
|
||||||
|
else if index >= len(t_step)-1
|
||||||
|
index = len(t_step)-1
|
||||||
|
pstep = t_step[index]
|
||||||
|
}
|
||||||
|
}
|
111
benchmark-program/b_circles.p8
Normal file
111
benchmark-program/b_circles.p8
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
%import gfx_lores
|
||||||
|
%import math
|
||||||
|
|
||||||
|
circles {
|
||||||
|
const ubyte MAX_NUM_CIRCLES = 80
|
||||||
|
const ubyte GROWTH_RATE = 4
|
||||||
|
uword[MAX_NUM_CIRCLES] circle_x
|
||||||
|
uword[MAX_NUM_CIRCLES] circle_y
|
||||||
|
ubyte[MAX_NUM_CIRCLES] circle_radius
|
||||||
|
ubyte color
|
||||||
|
uword total_num_circles
|
||||||
|
|
||||||
|
sub draw(bool use_kernal, uword max_time) -> uword {
|
||||||
|
if use_kernal
|
||||||
|
void cx16.set_screen_mode(128)
|
||||||
|
else
|
||||||
|
gfx_lores.graphics_mode()
|
||||||
|
|
||||||
|
math.rndseed(12345,6789)
|
||||||
|
cbm.SETTIM(0,0,0)
|
||||||
|
|
||||||
|
total_num_circles = 0
|
||||||
|
color = 16
|
||||||
|
|
||||||
|
while cbm.RDTIM16()<max_time {
|
||||||
|
if use_kernal {
|
||||||
|
cx16.GRAPH_set_colors(0,0,0)
|
||||||
|
cx16.GRAPH_clear()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gfx_lores.clear_screen(0)
|
||||||
|
total_num_circles += draw_circles(use_kernal, max_time)
|
||||||
|
}
|
||||||
|
|
||||||
|
if use_kernal
|
||||||
|
void cx16.set_screen_mode(3)
|
||||||
|
else {
|
||||||
|
gfx_lores.text_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_num_circles
|
||||||
|
}
|
||||||
|
|
||||||
|
sub draw_circles(bool use_kernal, uword max_time) -> uword {
|
||||||
|
uword @zp x
|
||||||
|
uword @zp y
|
||||||
|
ubyte @zp radius
|
||||||
|
|
||||||
|
ubyte num_circles
|
||||||
|
|
||||||
|
while num_circles<MAX_NUM_CIRCLES and cbm.RDTIM16()<max_time {
|
||||||
|
x = math.rndw() % 320
|
||||||
|
y = math.rndw() % 240
|
||||||
|
radius = GROWTH_RATE
|
||||||
|
if not_colliding() {
|
||||||
|
while not_edge() and not_colliding() {
|
||||||
|
radius += GROWTH_RATE
|
||||||
|
}
|
||||||
|
radius -= GROWTH_RATE
|
||||||
|
if radius>0 {
|
||||||
|
color++
|
||||||
|
if color==0
|
||||||
|
color=16
|
||||||
|
if use_kernal {
|
||||||
|
cx16.GRAPH_set_colors(color, 255-color, 0)
|
||||||
|
cx16.GRAPH_draw_oval(x-radius, y-radius, radius*2, radius*2, true)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gfx_lores.disc(x, y as ubyte, radius, color)
|
||||||
|
circle_x[num_circles] = x
|
||||||
|
circle_y[num_circles] = y
|
||||||
|
circle_radius[num_circles] = radius
|
||||||
|
num_circles++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_circles
|
||||||
|
|
||||||
|
sub not_colliding() -> bool {
|
||||||
|
if num_circles==0
|
||||||
|
return true
|
||||||
|
ubyte @zp c
|
||||||
|
for c in 0 to num_circles-1 {
|
||||||
|
if distance(c) < (radius as uword) + circle_radius[c]
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
sub distance(ubyte cix) -> uword {
|
||||||
|
word dx = x as word - circle_x[cix]
|
||||||
|
word dy = y as word - circle_y[cix]
|
||||||
|
uword sqx = dx*dx as uword
|
||||||
|
uword sqy = dy*dy as uword
|
||||||
|
return sqrt(sqx + sqy)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub not_edge() -> bool {
|
||||||
|
if x as word - radius < 0
|
||||||
|
return false
|
||||||
|
if x + radius >= 320
|
||||||
|
return false
|
||||||
|
if y as word - radius < 0
|
||||||
|
return false
|
||||||
|
if y + radius >= 240
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
123
benchmark-program/b_life.p8
Normal file
123
benchmark-program/b_life.p8
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
; conway's game of life.
|
||||||
|
|
||||||
|
%import math
|
||||||
|
%import textio
|
||||||
|
|
||||||
|
life {
|
||||||
|
const ubyte WIDTH = 40
|
||||||
|
const ubyte HEIGHT = 30
|
||||||
|
const uword STRIDE = $0002+WIDTH
|
||||||
|
uword world1 = memory("world1", (WIDTH+2)*(HEIGHT+2), 0)
|
||||||
|
uword world2 = memory("world2", (WIDTH+2)*(HEIGHT+2), 0)
|
||||||
|
uword @requirezp active_world = world1
|
||||||
|
|
||||||
|
sub benchmark(uword max_time) -> uword {
|
||||||
|
txt.clear_screen()
|
||||||
|
sys.memset(world1, (WIDTH+2)*(HEIGHT+2), 0)
|
||||||
|
sys.memset(world2, (WIDTH+2)*(HEIGHT+2), 0)
|
||||||
|
|
||||||
|
set_start_gen()
|
||||||
|
|
||||||
|
uword gen
|
||||||
|
cbm.SETTIM(0,0,0)
|
||||||
|
|
||||||
|
while cbm.RDTIM16()<max_time {
|
||||||
|
next_gen()
|
||||||
|
gen++
|
||||||
|
}
|
||||||
|
|
||||||
|
return gen
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_start_gen() {
|
||||||
|
|
||||||
|
; some way to set a custom start generation:
|
||||||
|
; str start_gen = " " +
|
||||||
|
; " " +
|
||||||
|
; " " +
|
||||||
|
; " ** " +
|
||||||
|
; " * * " +
|
||||||
|
; " * " +
|
||||||
|
; " * * " +
|
||||||
|
; " ****** " +
|
||||||
|
; " " +
|
||||||
|
; " " +
|
||||||
|
; " " +
|
||||||
|
; " " +
|
||||||
|
; " " +
|
||||||
|
; " " +
|
||||||
|
; " " +
|
||||||
|
; " "
|
||||||
|
;
|
||||||
|
; for y in 0 to 15 {
|
||||||
|
; for x in 0 to 15 {
|
||||||
|
; if start_gen[y*16 + x]=='*'
|
||||||
|
; active_world[offset + x] = 1
|
||||||
|
; }
|
||||||
|
; offset += STRIDE
|
||||||
|
; }
|
||||||
|
|
||||||
|
; randomize whole world
|
||||||
|
math.rndseed(12345,9999)
|
||||||
|
uword offset = STRIDE+1
|
||||||
|
ubyte x
|
||||||
|
ubyte y
|
||||||
|
for y in 0 to HEIGHT-1 {
|
||||||
|
for x in 0 to WIDTH-1 {
|
||||||
|
active_world[offset+x] = math.rnd() & 1
|
||||||
|
}
|
||||||
|
offset += STRIDE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub next_gen() {
|
||||||
|
const ubyte DXOFFSET = 0
|
||||||
|
const ubyte DYOFFSET = 0
|
||||||
|
ubyte[2] cell_chars = [sc:' ', sc:'●']
|
||||||
|
|
||||||
|
uword @requirezp new_world = world1
|
||||||
|
if active_world == world1
|
||||||
|
new_world = world2
|
||||||
|
|
||||||
|
; To avoid re-calculating word index lookups into the new- and active world arrays,
|
||||||
|
; we calculate the required pointer values upfront.
|
||||||
|
; Inside the loop we can use ptr+x just fine (results in efficient LDA (ptr),Y instruction because x is a byte type),
|
||||||
|
; and for each row we simply add the stride to the pointer.
|
||||||
|
; It's more readable to use active_world[offset] etc, but offset is a word value, and this produces
|
||||||
|
; inefficient assembly code because we can't use a register indexed mode in this case. Costly inside a loop.
|
||||||
|
|
||||||
|
uword @requirezp new_world_ptr = new_world + STRIDE+1-DXOFFSET
|
||||||
|
uword @requirezp active_world_ptr = active_world + STRIDE+1-DXOFFSET
|
||||||
|
|
||||||
|
ubyte x
|
||||||
|
ubyte y
|
||||||
|
for y in DYOFFSET to HEIGHT+DYOFFSET-1 {
|
||||||
|
|
||||||
|
cx16.vaddr_autoincr(1, $b000 + 256*y, 0, 2) ; allows us to use simple Vera data byte assigns later instead of setchr() calls
|
||||||
|
|
||||||
|
for x in DXOFFSET to WIDTH+DXOFFSET-1 {
|
||||||
|
; count the living neighbors
|
||||||
|
ubyte cell = @(active_world_ptr + x)
|
||||||
|
uword @requirezp ptr = active_world_ptr + x - STRIDE - 1
|
||||||
|
ubyte neighbors = @(ptr) + @(ptr+1) + @(ptr+2) +
|
||||||
|
@(ptr+STRIDE) + cell + @(ptr+STRIDE+2) +
|
||||||
|
@(ptr+STRIDE*2) + @(ptr+STRIDE*2+1) + @(ptr+STRIDE*2+2)
|
||||||
|
|
||||||
|
; apply game of life rules
|
||||||
|
if neighbors==3
|
||||||
|
cell=1
|
||||||
|
else if neighbors!=4
|
||||||
|
cell=0
|
||||||
|
@(new_world_ptr + x) = cell
|
||||||
|
|
||||||
|
; draw new cell
|
||||||
|
; txt.setchr(x,y,cell_chars[cell])
|
||||||
|
cx16.VERA_DATA0 = cell_chars[cell]
|
||||||
|
}
|
||||||
|
active_world_ptr += STRIDE
|
||||||
|
new_world_ptr += STRIDE
|
||||||
|
}
|
||||||
|
|
||||||
|
active_world = new_world
|
||||||
|
}
|
||||||
|
}
|
54
benchmark-program/b_mandelbrot.p8
Normal file
54
benchmark-program/b_mandelbrot.p8
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
%import textio
|
||||||
|
%import floats
|
||||||
|
|
||||||
|
mandelbrot {
|
||||||
|
const ubyte width = 39
|
||||||
|
const ubyte height = 29
|
||||||
|
const ubyte max_iter = 15
|
||||||
|
|
||||||
|
sub calc(uword max_time) -> uword {
|
||||||
|
uword num_pixels
|
||||||
|
ubyte pixelx
|
||||||
|
ubyte pixely
|
||||||
|
|
||||||
|
txt.home()
|
||||||
|
cbm.SETTIM(0,0,0)
|
||||||
|
|
||||||
|
while cbm.RDTIM16() < max_time {
|
||||||
|
for pixely in 0 to height-1 {
|
||||||
|
float yy = (pixely as float)/0.40/height - 1.3
|
||||||
|
|
||||||
|
for pixelx in 0 to width-1 {
|
||||||
|
float xx = (pixelx as float)/0.32/width - 2.2
|
||||||
|
|
||||||
|
float xsquared = 0.0
|
||||||
|
float ysquared = 0.0
|
||||||
|
float x = 0.0
|
||||||
|
float y = 0.0
|
||||||
|
ubyte iter = 0
|
||||||
|
|
||||||
|
while iter<max_iter and xsquared+ysquared<4.0 {
|
||||||
|
y = x*y*2.0 + yy
|
||||||
|
x = xsquared - ysquared + xx
|
||||||
|
xsquared = x*x
|
||||||
|
ysquared = y*y
|
||||||
|
iter++
|
||||||
|
}
|
||||||
|
txt.color2(1, max_iter-iter)
|
||||||
|
txt.spc()
|
||||||
|
num_pixels++
|
||||||
|
|
||||||
|
if cbm.RDTIM16()>=max_time
|
||||||
|
goto finished
|
||||||
|
}
|
||||||
|
txt.nl()
|
||||||
|
}
|
||||||
|
|
||||||
|
txt.clear_screen()
|
||||||
|
}
|
||||||
|
|
||||||
|
finished:
|
||||||
|
txt.color2(1, 6)
|
||||||
|
return num_pixels
|
||||||
|
}
|
||||||
|
}
|
343
benchmark-program/b_maze.p8
Normal file
343
benchmark-program/b_maze.p8
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
%import textio
|
||||||
|
%import math
|
||||||
|
|
||||||
|
; Even though prog8 only has support for extremely limited recursion,
|
||||||
|
; you can write recursive algorithms with a bit of extra work by building your own explicit stack structure.
|
||||||
|
; This program shows a depth-first maze generation algorithm (1 possible path from start to finish),
|
||||||
|
; and a depth-first maze solver algorithm, both using a stack to store the path taken.
|
||||||
|
|
||||||
|
; Note: this program can be compiled for multiple target systems.
|
||||||
|
|
||||||
|
maze {
|
||||||
|
uword score
|
||||||
|
|
||||||
|
sub bench(uword max_time) -> uword {
|
||||||
|
txt.nl()
|
||||||
|
score=0
|
||||||
|
math.rndseed(2345,44332)
|
||||||
|
cbm.SETTIM(0,0,0)
|
||||||
|
while cbm.RDTIM16()<max_time {
|
||||||
|
maze.initialize()
|
||||||
|
maze.drawStartFinish()
|
||||||
|
if maze.generate(max_time) {
|
||||||
|
maze.openpassages()
|
||||||
|
maze.drawStartFinish()
|
||||||
|
if maze.solve(max_time) {
|
||||||
|
maze.drawStartFinish()
|
||||||
|
} else break
|
||||||
|
} else break
|
||||||
|
}
|
||||||
|
|
||||||
|
return score
|
||||||
|
}
|
||||||
|
|
||||||
|
const uword screenwidth = 40
|
||||||
|
const uword screenheight = 30
|
||||||
|
|
||||||
|
const ubyte numCellsHoriz = (screenwidth-1) / 2
|
||||||
|
const ubyte numCellsVert = (screenheight-1) / 2
|
||||||
|
|
||||||
|
; maze start and finish cells
|
||||||
|
const ubyte startCx = 0
|
||||||
|
const ubyte startCy = 0
|
||||||
|
const ubyte finishCx = numCellsHoriz-1
|
||||||
|
const ubyte finishCy = numCellsVert-1
|
||||||
|
|
||||||
|
; cell properties
|
||||||
|
const ubyte STONE = 128
|
||||||
|
const ubyte WALKED = 64
|
||||||
|
const ubyte BACKTRACKED = 32
|
||||||
|
const ubyte UP = 1
|
||||||
|
const ubyte RIGHT = 2
|
||||||
|
const ubyte DOWN = 4
|
||||||
|
const ubyte LEFT = 8
|
||||||
|
const ubyte WALLCOLOR = 12
|
||||||
|
const ubyte EMPTYCOLOR = 0
|
||||||
|
|
||||||
|
; unfortunately on larger screens (cx16), the number of cells exceeds 256 and doesn't fit in a regular array anymore.
|
||||||
|
uword cells = memory("cells", numCellsHoriz*numCellsVert, 0)
|
||||||
|
|
||||||
|
ubyte[256] cx_stack
|
||||||
|
ubyte[256] cy_stack
|
||||||
|
ubyte stackptr
|
||||||
|
|
||||||
|
ubyte[4] directionflags = [LEFT,RIGHT,UP,DOWN]
|
||||||
|
|
||||||
|
sub generate(uword max_time) -> bool {
|
||||||
|
ubyte cx = startCx
|
||||||
|
ubyte cy = startCy
|
||||||
|
|
||||||
|
stackptr = 0
|
||||||
|
@(celladdr(cx,cy)) &= ~STONE
|
||||||
|
drawCell(cx, cy)
|
||||||
|
uword cells_to_carve = numCellsHoriz * numCellsVert - 1
|
||||||
|
|
||||||
|
while cbm.RDTIM16()<max_time {
|
||||||
|
carve_restart_after_repath:
|
||||||
|
ubyte direction = choose_uncarved_direction()
|
||||||
|
if direction==0 {
|
||||||
|
;backtrack
|
||||||
|
stackptr--
|
||||||
|
if stackptr==255 {
|
||||||
|
; stack empty.
|
||||||
|
; repath if we are not done yet. (this is a workaround for the prog8 256 array lenght limit)
|
||||||
|
if cells_to_carve!=0 {
|
||||||
|
if repath()
|
||||||
|
goto carve_restart_after_repath
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
cx = cx_stack[stackptr]
|
||||||
|
cy = cy_stack[stackptr]
|
||||||
|
} else {
|
||||||
|
cx_stack[stackptr] = cx
|
||||||
|
cy_stack[stackptr] = cy
|
||||||
|
stackptr++
|
||||||
|
if stackptr==0 {
|
||||||
|
; stack overflow, we can't track our path any longer.
|
||||||
|
; repath if we are not done yet. (this is a workaround for the prog8 256 array lenght limit)
|
||||||
|
if cells_to_carve!=0 {
|
||||||
|
if repath()
|
||||||
|
goto carve_restart_after_repath
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@(celladdr(cx,cy)) |= direction
|
||||||
|
when direction {
|
||||||
|
UP -> {
|
||||||
|
cy--
|
||||||
|
@(celladdr(cx,cy)) |= DOWN
|
||||||
|
}
|
||||||
|
RIGHT -> {
|
||||||
|
cx++
|
||||||
|
@(celladdr(cx,cy)) |= LEFT
|
||||||
|
|
||||||
|
score++
|
||||||
|
}
|
||||||
|
DOWN -> {
|
||||||
|
cy++
|
||||||
|
@(celladdr(cx,cy)) |= UP
|
||||||
|
}
|
||||||
|
LEFT -> {
|
||||||
|
cx--
|
||||||
|
@(celladdr(cx,cy)) |= RIGHT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@(celladdr(cx,cy)) &= ~STONE
|
||||||
|
cells_to_carve--
|
||||||
|
drawCell(cx, cy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
|
||||||
|
sub repath() -> bool {
|
||||||
|
; repath: try to find a new start cell with possible directions.
|
||||||
|
; we limit our number of searches so that the algorith doesn't get stuck
|
||||||
|
; for too long on bad rng... just accept a few unused cells in that case.
|
||||||
|
repeat 255 {
|
||||||
|
do {
|
||||||
|
cx = math.rnd() % numCellsHoriz
|
||||||
|
cy = math.rnd() % numCellsVert
|
||||||
|
} until @(celladdr(cx, cy)) & STONE ==0
|
||||||
|
if available_uncarved()!=0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
sub available_uncarved() -> ubyte {
|
||||||
|
ubyte candidates = 0
|
||||||
|
if cx>0 and @(celladdr(cx-1, cy)) & STONE !=0
|
||||||
|
candidates |= LEFT
|
||||||
|
if cx<numCellsHoriz-1 and @(celladdr(cx+1, cy)) & STONE !=0
|
||||||
|
candidates |= RIGHT
|
||||||
|
if cy>0 and @(celladdr(cx, cy-1)) & STONE !=0
|
||||||
|
candidates |= UP
|
||||||
|
if cy<numCellsVert-1 and @(celladdr(cx, cy+1)) & STONE !=0
|
||||||
|
candidates |= DOWN
|
||||||
|
return candidates
|
||||||
|
}
|
||||||
|
|
||||||
|
sub choose_uncarved_direction() -> ubyte {
|
||||||
|
ubyte candidates = available_uncarved()
|
||||||
|
if candidates==0
|
||||||
|
return 0
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
ubyte choice = candidates & directionflags[math.rnd() & 3]
|
||||||
|
if choice!=0
|
||||||
|
return choice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub openpassages() {
|
||||||
|
; open just a few extra passages, so that multiple routes are possible in theory.
|
||||||
|
ubyte numpassages
|
||||||
|
ubyte cx
|
||||||
|
ubyte cy
|
||||||
|
do {
|
||||||
|
do {
|
||||||
|
cx = math.rnd() % (numCellsHoriz-2) + 1
|
||||||
|
cy = math.rnd() % (numCellsVert-2) + 1
|
||||||
|
} until @(celladdr(cx, cy)) & STONE ==0
|
||||||
|
ubyte direction = directionflags[math.rnd() & 3]
|
||||||
|
if @(celladdr(cx, cy)) & direction == 0 {
|
||||||
|
when direction {
|
||||||
|
LEFT -> {
|
||||||
|
if @(celladdr(cx-1,cy)) & STONE == 0 {
|
||||||
|
@(celladdr(cx,cy)) |= LEFT
|
||||||
|
drawCell(cx,cy)
|
||||||
|
numpassages++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RIGHT -> {
|
||||||
|
if @(celladdr(cx+1,cy)) & STONE == 0 {
|
||||||
|
@(celladdr(cx,cy)) |= RIGHT
|
||||||
|
drawCell(cx,cy)
|
||||||
|
numpassages++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UP -> {
|
||||||
|
if @(celladdr(cx,cy-1)) & STONE == 0 {
|
||||||
|
@(celladdr(cx,cy)) |= UP
|
||||||
|
drawCell(cx,cy)
|
||||||
|
numpassages++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DOWN -> {
|
||||||
|
if @(celladdr(cx,cy+1)) & STONE == 0 {
|
||||||
|
@(celladdr(cx,cy)) |= DOWN
|
||||||
|
drawCell(cx,cy)
|
||||||
|
numpassages++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} until numpassages==10
|
||||||
|
}
|
||||||
|
|
||||||
|
sub solve(uword max_time) -> bool {
|
||||||
|
ubyte cx = startCx
|
||||||
|
ubyte cy = startCy
|
||||||
|
const uword max_path_length = 1024
|
||||||
|
|
||||||
|
; the path through the maze can be longer than 256 so doesn't fit in a regular array.... :(
|
||||||
|
uword pathstack = memory("pathstack", max_path_length, 0)
|
||||||
|
uword pathstackptr = 0
|
||||||
|
|
||||||
|
@(celladdr(cx,cy)) |= WALKED
|
||||||
|
; txt.setcc(cx*2+1, cy*2+1, 81, 1)
|
||||||
|
|
||||||
|
while cbm.RDTIM16()<max_time {
|
||||||
|
solve_loop:
|
||||||
|
if cx==finishCx and cy==finishCy {
|
||||||
|
;txt.home()
|
||||||
|
txt.print("found! path length: ")
|
||||||
|
txt.print_uw(pathstackptr)
|
||||||
|
txt.nl()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
ubyte cell = @(celladdr(cx,cy))
|
||||||
|
if cell & UP!=0 and @(celladdr(cx,cy-1)) & (WALKED|BACKTRACKED) ==0 {
|
||||||
|
@(pathstack + pathstackptr) = UP
|
||||||
|
;txt.setcc(cx*2+1, cy*2, 81, 3)
|
||||||
|
cy--
|
||||||
|
}
|
||||||
|
else if cell & DOWN !=0 and @(celladdr(cx,cy+1)) & (WALKED|BACKTRACKED) ==0 {
|
||||||
|
@(pathstack + pathstackptr) = DOWN
|
||||||
|
;txt.setcc(cx*2+1, cy*2+2, 81, 3)
|
||||||
|
cy++
|
||||||
|
}
|
||||||
|
else if cell & LEFT !=0 and @(celladdr(cx-1,cy)) & (WALKED|BACKTRACKED) ==0 {
|
||||||
|
@(pathstack + pathstackptr) = LEFT
|
||||||
|
;txt.setcc(cx*2, cy*2+1, 81, 3)
|
||||||
|
cx--
|
||||||
|
}
|
||||||
|
else if cell & RIGHT !=0 and @(celladdr(cx+1,cy)) & (WALKED|BACKTRACKED) ==0 {
|
||||||
|
@(pathstack + pathstackptr) = RIGHT
|
||||||
|
;txt.setcc(cx*2+2, cy*2+1, 81, 3)
|
||||||
|
cx++
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
; dead end, pop stack
|
||||||
|
pathstackptr--
|
||||||
|
if pathstackptr==65535 {
|
||||||
|
txt.print("no solution?!\n")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@(celladdr(cx,cy)) |= BACKTRACKED
|
||||||
|
;txt.setcc(cx*2+1, cy*2+1, 81, 2)
|
||||||
|
when @(pathstack + pathstackptr) {
|
||||||
|
UP -> {
|
||||||
|
;txt.setcc(cx*2+1, cy*2+2, 81, 9)
|
||||||
|
cy++
|
||||||
|
}
|
||||||
|
DOWN -> {
|
||||||
|
;txt.setcc(cx*2+1, cy*2, 81, 9)
|
||||||
|
cy--
|
||||||
|
}
|
||||||
|
LEFT -> {
|
||||||
|
;txt.setcc(cx*2+2, cy*2+1, 81, 9)
|
||||||
|
cx++
|
||||||
|
}
|
||||||
|
RIGHT -> {
|
||||||
|
;txt.setcc(cx*2, cy*2+1, 81, 9)
|
||||||
|
cx--
|
||||||
|
|
||||||
|
score++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto solve_loop
|
||||||
|
}
|
||||||
|
pathstackptr++
|
||||||
|
if pathstackptr==max_path_length {
|
||||||
|
txt.print("stack overflow, path too long\n")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@(celladdr(cx,cy)) |= WALKED
|
||||||
|
;txt.setcc(cx*2+1, cy*2+1, 81, 1)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
sub celladdr(ubyte cx, ubyte cy) -> uword {
|
||||||
|
return cells+(numCellsHoriz as uword)*cy+cx
|
||||||
|
}
|
||||||
|
|
||||||
|
sub drawCell(ubyte cx, ubyte cy) {
|
||||||
|
return
|
||||||
|
; ubyte x = cx * 2 + 1
|
||||||
|
; ubyte y = cy * 2 + 1
|
||||||
|
; ubyte doors = @(celladdr(cx,cy))
|
||||||
|
; if doors & UP !=0
|
||||||
|
; txt.setcc(x, y-1, ' ', EMPTYCOLOR)
|
||||||
|
; if doors & RIGHT !=0
|
||||||
|
; txt.setcc(x+1, y, ' ', EMPTYCOLOR)
|
||||||
|
; if doors & DOWN !=0
|
||||||
|
; txt.setcc(x, y+1, ' ', EMPTYCOLOR)
|
||||||
|
; if doors & LEFT !=0
|
||||||
|
; txt.setcc(x-1, y, ' ', EMPTYCOLOR)
|
||||||
|
; if doors & STONE !=0
|
||||||
|
; txt.setcc(x, y, 160, WALLCOLOR)
|
||||||
|
; else
|
||||||
|
; txt.setcc(x, y, 32, EMPTYCOLOR)
|
||||||
|
;
|
||||||
|
; if doors & WALKED !=0
|
||||||
|
; txt.setcc(x, y, 81, 1)
|
||||||
|
; if doors & BACKTRACKED !=0
|
||||||
|
; txt.setcc(x, y, 81, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub initialize() {
|
||||||
|
sys.memset(cells, numCellsHoriz*numCellsVert, STONE)
|
||||||
|
; txt.fill_screen(160, WALLCOLOR)
|
||||||
|
drawStartFinish()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub drawStartFinish() {
|
||||||
|
; txt.setcc(startCx*2+1,startCy*2+1,sc:'s',5)
|
||||||
|
; txt.setcc(finishCx*2+1, finishCy*2+1, sc:'f', 13)
|
||||||
|
}
|
||||||
|
}
|
63
benchmark-program/b_queens.p8
Normal file
63
benchmark-program/b_queens.p8
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
%import textio
|
||||||
|
|
||||||
|
; Recursive N-Queens solver.
|
||||||
|
; The problem is: find all possible ways to place 8 Queen chess pieces on a chess board, so that none of them attacks any other.
|
||||||
|
; (this program prints all solutions without taking mirroring and flipping the chess board into account)
|
||||||
|
; Note: this program can be compiled for multiple target systems.
|
||||||
|
|
||||||
|
queens {
|
||||||
|
const ubyte NUMQUEENS=8
|
||||||
|
ubyte[NUMQUEENS] board
|
||||||
|
|
||||||
|
sub could_place(ubyte row, ubyte col) -> bool {
|
||||||
|
if row==0
|
||||||
|
return true
|
||||||
|
ubyte i
|
||||||
|
for i in 0 to row-1 {
|
||||||
|
if board[i]==col or board[i]-i==col-row or board[i]+i==col+row
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
uword solution_count
|
||||||
|
uword maximum_duration
|
||||||
|
|
||||||
|
sub place_queen(ubyte row) -> bool {
|
||||||
|
if row == NUMQUEENS {
|
||||||
|
solution_count++
|
||||||
|
txt.chrout('.')
|
||||||
|
return cbm.RDTIM16()<maximum_duration
|
||||||
|
}
|
||||||
|
bool continue_running=true
|
||||||
|
ubyte col
|
||||||
|
for col in 0 to NUMQUEENS-1 {
|
||||||
|
if could_place(row, col) {
|
||||||
|
board[row] = col
|
||||||
|
; we need to save the local variables row and col.
|
||||||
|
sys.push(row)
|
||||||
|
sys.push(col)
|
||||||
|
continue_running = place_queen(row + 1)
|
||||||
|
; restore the local variables after the recursive call.
|
||||||
|
col = sys.pop()
|
||||||
|
row = sys.pop()
|
||||||
|
board[row] = 0
|
||||||
|
|
||||||
|
if not continue_running
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return continue_running
|
||||||
|
}
|
||||||
|
|
||||||
|
sub bench(uword max_time) -> uword {
|
||||||
|
solution_count = 0
|
||||||
|
maximum_duration = max_time
|
||||||
|
txt.nl()
|
||||||
|
cbm.SETTIM(0,0,0)
|
||||||
|
while cbm.RDTIM16() < maximum_duration {
|
||||||
|
void place_queen(0)
|
||||||
|
}
|
||||||
|
return solution_count
|
||||||
|
}
|
||||||
|
}
|
989
benchmark-program/b_textelite.p8
Normal file
989
benchmark-program/b_textelite.p8
Normal file
@ -0,0 +1,989 @@
|
|||||||
|
%import textio
|
||||||
|
%import conv
|
||||||
|
%import strings
|
||||||
|
|
||||||
|
|
||||||
|
textelite {
|
||||||
|
|
||||||
|
const ubyte numforLave = 7 ; Lave is 7th generated planet in galaxy one
|
||||||
|
const ubyte numforZaonce = 129
|
||||||
|
const ubyte numforDiso = 147
|
||||||
|
const ubyte numforRiedquat = 46
|
||||||
|
uword num_commands
|
||||||
|
|
||||||
|
sub bench(uword max_time) -> uword {
|
||||||
|
num_commands = 0
|
||||||
|
txt.lowercase()
|
||||||
|
cbm.SETTIM(0,0,0)
|
||||||
|
while cbm.RDTIM16()<max_time {
|
||||||
|
reinit()
|
||||||
|
run_commands(max_time)
|
||||||
|
}
|
||||||
|
return num_commands
|
||||||
|
}
|
||||||
|
|
||||||
|
sub reinit() {
|
||||||
|
;txt.clear_screen()
|
||||||
|
;txt.print("\n --- TextElite v1.3 ---\n")
|
||||||
|
txt.print("\nnew game\n")
|
||||||
|
elite_planet.set_seed(0, 0)
|
||||||
|
elite_galaxy.travel_to(1, numforLave)
|
||||||
|
elite_market.init(0) ; Lave's market is seeded with 0
|
||||||
|
elite_ship.init()
|
||||||
|
elite_planet.display(false, 0)
|
||||||
|
input_index = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sub run_commands(uword max_time) {
|
||||||
|
while cbm.RDTIM16() < max_time {
|
||||||
|
str input = "????????"
|
||||||
|
;txt.print("\nCash: ")
|
||||||
|
;elite_util.print_10s(elite_ship.cash)
|
||||||
|
;txt.print("\nCommand (?=help): ")
|
||||||
|
ubyte num_chars = next_input(input)
|
||||||
|
;txt.nl()
|
||||||
|
if num_chars!=0 {
|
||||||
|
when input[0] {
|
||||||
|
'q' -> {
|
||||||
|
bool has_error = false
|
||||||
|
if elite_galaxy.number != 2 {
|
||||||
|
txt.print("\nERROR: galaxy is not 2: ")
|
||||||
|
txt.print_ub(elite_galaxy.number)
|
||||||
|
txt.nl()
|
||||||
|
has_error=true
|
||||||
|
}
|
||||||
|
if elite_planet.number != 164 {
|
||||||
|
txt.print("\nERROR: planet is not 164: ")
|
||||||
|
txt.print_ub(elite_planet.number)
|
||||||
|
txt.nl()
|
||||||
|
has_error=true
|
||||||
|
}
|
||||||
|
if elite_planet.x != 116 {
|
||||||
|
txt.print("\nERROR: planet.x is not 116: ")
|
||||||
|
txt.print_ub(elite_planet.x)
|
||||||
|
txt.nl()
|
||||||
|
has_error=true
|
||||||
|
}
|
||||||
|
if elite_planet.y != 201 {
|
||||||
|
txt.print("\nERROR: planet.y is not 201: ")
|
||||||
|
txt.print_ub(elite_planet.y)
|
||||||
|
txt.nl()
|
||||||
|
has_error=true
|
||||||
|
}
|
||||||
|
if "ribeen" != elite_planet.name {
|
||||||
|
txt.print("\nERROR: planet.name is not 'ribeen': ")
|
||||||
|
txt.print(elite_planet.name)
|
||||||
|
txt.nl()
|
||||||
|
has_error=true
|
||||||
|
}
|
||||||
|
if elite_ship.cash != 1212 {
|
||||||
|
txt.print("\nERROR: cash is not 1212: ")
|
||||||
|
txt.print_uw(elite_ship.cash)
|
||||||
|
txt.nl()
|
||||||
|
has_error=true
|
||||||
|
}
|
||||||
|
if elite_ship.fuel != 50 {
|
||||||
|
txt.print("\nERROR: fuel is not 50:")
|
||||||
|
txt.print_ub(elite_ship.fuel)
|
||||||
|
txt.nl()
|
||||||
|
has_error=true
|
||||||
|
}
|
||||||
|
if elite_ship.cargohold[0] != 3 {
|
||||||
|
txt.print("\nERROR: food is not 3:")
|
||||||
|
txt.print_ub(elite_ship.cargohold[0])
|
||||||
|
txt.nl()
|
||||||
|
has_error=true
|
||||||
|
}
|
||||||
|
if elite_ship.cargohold[1] != 0 {
|
||||||
|
txt.print("\nERROR: textiles is not 0:")
|
||||||
|
txt.print_ub(elite_ship.cargohold[1])
|
||||||
|
txt.nl()
|
||||||
|
has_error=true
|
||||||
|
}
|
||||||
|
if has_error
|
||||||
|
sys.exit(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
'b' -> elite_trader.do_buy()
|
||||||
|
's' -> elite_trader.do_sell()
|
||||||
|
'f' -> elite_trader.do_fuel()
|
||||||
|
'j' -> elite_trader.do_jump()
|
||||||
|
't' -> elite_trader.do_teleport()
|
||||||
|
'g' -> elite_trader.do_next_galaxy()
|
||||||
|
'i' -> elite_trader.do_info()
|
||||||
|
'm' -> {
|
||||||
|
if input[1]=='a' and input[2]=='p'
|
||||||
|
elite_trader.do_map()
|
||||||
|
else
|
||||||
|
elite_trader.do_show_market()
|
||||||
|
}
|
||||||
|
'l' -> elite_trader.do_local()
|
||||||
|
'c' -> elite_trader.do_cash()
|
||||||
|
'h' -> elite_trader.do_hold()
|
||||||
|
}
|
||||||
|
num_commands++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str[] inputs = [
|
||||||
|
"i",
|
||||||
|
"diso",
|
||||||
|
"i",
|
||||||
|
"lave",
|
||||||
|
"m",
|
||||||
|
"b",
|
||||||
|
"food",
|
||||||
|
"15",
|
||||||
|
"map",
|
||||||
|
"g",
|
||||||
|
"map",
|
||||||
|
"l",
|
||||||
|
"j",
|
||||||
|
"zao",
|
||||||
|
"s",
|
||||||
|
"food",
|
||||||
|
"12",
|
||||||
|
"tele",
|
||||||
|
"quti",
|
||||||
|
"tele",
|
||||||
|
"aro",
|
||||||
|
"i",
|
||||||
|
"diso",
|
||||||
|
"i",
|
||||||
|
"lave",
|
||||||
|
"i",
|
||||||
|
"zao",
|
||||||
|
"galhyp",
|
||||||
|
"fuel",
|
||||||
|
"20",
|
||||||
|
"j",
|
||||||
|
"rib",
|
||||||
|
"i",
|
||||||
|
"rib",
|
||||||
|
"i",
|
||||||
|
"tiri",
|
||||||
|
"q",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
|
||||||
|
ubyte input_index
|
||||||
|
|
||||||
|
sub next_input(str buffer) -> ubyte {
|
||||||
|
input_index++
|
||||||
|
return strings.copy(inputs[input_index], buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elite_trader {
|
||||||
|
str input = "??????????"
|
||||||
|
ubyte num_chars
|
||||||
|
|
||||||
|
sub do_jump() {
|
||||||
|
;txt.print("\nJump to what system? ")
|
||||||
|
jump_to_system()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_teleport() {
|
||||||
|
;txt.print("\nCheat! Teleport to what system? ")
|
||||||
|
ubyte fuel = elite_ship.fuel
|
||||||
|
elite_ship.fuel = 255
|
||||||
|
jump_to_system()
|
||||||
|
elite_ship.fuel = fuel
|
||||||
|
}
|
||||||
|
|
||||||
|
sub jump_to_system() {
|
||||||
|
void textelite.next_input(input)
|
||||||
|
ubyte current_planet = elite_planet.number
|
||||||
|
ubyte x = elite_planet.x
|
||||||
|
ubyte y = elite_planet.y
|
||||||
|
if elite_galaxy.search_closest_planet(input) {
|
||||||
|
ubyte distance = elite_planet.distance(x, y)
|
||||||
|
if distance <= elite_ship.fuel {
|
||||||
|
elite_galaxy.init_market_for_planet()
|
||||||
|
elite_ship.fuel -= distance
|
||||||
|
;txt.print("\n\nHyperspace jump! Arrived at:\n")
|
||||||
|
elite_planet.display(true,0 )
|
||||||
|
return
|
||||||
|
}
|
||||||
|
;txt.print("\nInsufficient fuel\n")
|
||||||
|
} else {
|
||||||
|
;txt.print(" Not found!\n")
|
||||||
|
}
|
||||||
|
elite_galaxy.travel_to(elite_galaxy.number, current_planet)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_buy() {
|
||||||
|
;txt.print("\nBuy what commodity? ")
|
||||||
|
str commodity = "???????????????"
|
||||||
|
void textelite.next_input(commodity)
|
||||||
|
ubyte ci = elite_market.match(commodity)
|
||||||
|
if ci & 128 !=0 {
|
||||||
|
txt.print("Unknown\n")
|
||||||
|
} else {
|
||||||
|
;txt.print("\nHow much? ")
|
||||||
|
void textelite.next_input(input)
|
||||||
|
ubyte amount = conv.str2ubyte(input)
|
||||||
|
if elite_market.current_quantity[ci] < amount {
|
||||||
|
txt.print(" Insufficient supply!\n")
|
||||||
|
} else {
|
||||||
|
uword price = elite_market.current_price[ci] * amount
|
||||||
|
;txt.print(" Total price: ")
|
||||||
|
;elite_util.print_10s(price)
|
||||||
|
if price > elite_ship.cash {
|
||||||
|
txt.print(" Not enough cash!\n")
|
||||||
|
} else {
|
||||||
|
elite_ship.cash -= price
|
||||||
|
elite_ship.cargohold[ci] += amount
|
||||||
|
elite_market.current_quantity[ci] -= amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_sell() {
|
||||||
|
;txt.print("\nSell what commodity? ")
|
||||||
|
str commodity = "???????????????"
|
||||||
|
void textelite.next_input(commodity)
|
||||||
|
ubyte ci = elite_market.match(commodity)
|
||||||
|
if ci & 128 !=0 {
|
||||||
|
txt.print("Unknown\n")
|
||||||
|
} else {
|
||||||
|
;txt.print("\nHow much? ")
|
||||||
|
void textelite.next_input(input)
|
||||||
|
ubyte amount = conv.str2ubyte(input)
|
||||||
|
if elite_ship.cargohold[ci] < amount {
|
||||||
|
txt.print(" Insufficient supply!\n")
|
||||||
|
} else {
|
||||||
|
uword price = elite_market.current_price[ci] * amount
|
||||||
|
;txt.print(" Total price: ")
|
||||||
|
;elite_util.print_10s(price)
|
||||||
|
elite_ship.cash += price
|
||||||
|
elite_ship.cargohold[ci] -= amount
|
||||||
|
elite_market.current_quantity[ci] += amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_fuel() {
|
||||||
|
;txt.print("\nBuy fuel. Amount? ")
|
||||||
|
void textelite.next_input(input)
|
||||||
|
ubyte buy_fuel = 10*conv.str2ubyte(input)
|
||||||
|
ubyte max_fuel = elite_ship.Max_fuel - elite_ship.fuel
|
||||||
|
if buy_fuel > max_fuel
|
||||||
|
buy_fuel = max_fuel
|
||||||
|
uword price = buy_fuel as uword * elite_ship.Fuel_cost
|
||||||
|
if price > elite_ship.cash {
|
||||||
|
txt.print("Not enough cash!\n")
|
||||||
|
} else {
|
||||||
|
elite_ship.cash -= price
|
||||||
|
elite_ship.fuel += buy_fuel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_cash() {
|
||||||
|
;txt.print("\nCheat! Set cash amount: ")
|
||||||
|
void textelite.next_input(input)
|
||||||
|
elite_ship.cash = conv.str2uword(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_hold() {
|
||||||
|
;txt.print("\nCheat! Set cargohold size: ")
|
||||||
|
void textelite.next_input(input)
|
||||||
|
elite_ship.Max_cargo = conv.str2ubyte(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_next_galaxy() {
|
||||||
|
txt.print("\n>>>>> Galaxy Hyperjump!\n")
|
||||||
|
elite_galaxy.travel_to(elite_galaxy.number+1, elite_planet.number)
|
||||||
|
elite_planet.display(false, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_info() {
|
||||||
|
;txt.print("\nSystem name (empty=current): ")
|
||||||
|
num_chars = textelite.next_input(input)
|
||||||
|
if num_chars!=0 {
|
||||||
|
ubyte current_planet = elite_planet.number
|
||||||
|
ubyte x = elite_planet.x
|
||||||
|
ubyte y = elite_planet.y
|
||||||
|
if elite_galaxy.search_closest_planet(input) {
|
||||||
|
ubyte distance = elite_planet.distance(x, y)
|
||||||
|
elite_planet.display(false, distance)
|
||||||
|
} else {
|
||||||
|
;txt.print(" Not found!")
|
||||||
|
}
|
||||||
|
elite_galaxy.travel_to(elite_galaxy.number, current_planet)
|
||||||
|
} else {
|
||||||
|
elite_planet.display(false, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_local() {
|
||||||
|
elite_galaxy.local_area()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_map() {
|
||||||
|
;txt.print("\n(l)ocal or (g)alaxy starmap? ")
|
||||||
|
num_chars = textelite.next_input(input)
|
||||||
|
if num_chars!=0 {
|
||||||
|
elite_galaxy.starmap(input[0]=='l')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub do_show_market() {
|
||||||
|
elite_market.display()
|
||||||
|
;txt.print("\nFuel: ")
|
||||||
|
;elite_util.print_10s(elite_ship.fuel)
|
||||||
|
;txt.print(" Cargohold space: ")
|
||||||
|
;txt.print_ub(elite_ship.cargo_free())
|
||||||
|
;txt.print("t\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elite_ship {
|
||||||
|
const ubyte Max_fuel = 70
|
||||||
|
const ubyte Fuel_cost = 2
|
||||||
|
ubyte Max_cargo = 20
|
||||||
|
|
||||||
|
ubyte fuel
|
||||||
|
uword cash
|
||||||
|
ubyte[17] cargohold
|
||||||
|
|
||||||
|
sub init() {
|
||||||
|
sys.memset(cargohold, len(cargohold), 0)
|
||||||
|
fuel = Max_fuel
|
||||||
|
cash = 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elite_market {
|
||||||
|
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
|
||||||
|
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
|
||||||
|
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
|
||||||
|
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
|
||||||
|
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
|
||||||
|
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
|
||||||
|
|
||||||
|
ubyte[17] current_quantity
|
||||||
|
uword[17] current_price
|
||||||
|
|
||||||
|
sub init(ubyte fluct) {
|
||||||
|
; Prices and availabilities are influenced by the planet's economy type
|
||||||
|
; (0-7) and a random "fluctuation" byte that was kept within the saved
|
||||||
|
; commander position to keep the market prices constant over gamesaves.
|
||||||
|
; Availabilities must be saved with the game since the player alters them
|
||||||
|
; by buying (and selling(?))
|
||||||
|
;
|
||||||
|
; Almost all commands are one byte only and overflow "errors" are
|
||||||
|
; extremely frequent and exploited.
|
||||||
|
;
|
||||||
|
; Trade Item prices are held internally in a single byte=true value/4.
|
||||||
|
; The decimal point in prices is introduced only when printing them.
|
||||||
|
; Internally, all prices are integers.
|
||||||
|
; The player's cash is held in four bytes.
|
||||||
|
ubyte ci
|
||||||
|
for ci in 0 to len(names)-1 {
|
||||||
|
word product
|
||||||
|
byte changing
|
||||||
|
product = elite_planet.economy as word * gradients[ci]
|
||||||
|
changing = fluct & maskbytes[ci] as byte
|
||||||
|
ubyte q = (basequants[ci] as word + changing - product) as ubyte
|
||||||
|
if q & $80 !=0
|
||||||
|
q = 0 ; clip to positive 8-bit
|
||||||
|
current_quantity[ci] = q & $3f
|
||||||
|
q = (baseprices[ci] + changing + product) as ubyte
|
||||||
|
current_price[ci] = q * $0004
|
||||||
|
}
|
||||||
|
current_quantity[16] = 0 ; force nonavailability of Alien Items
|
||||||
|
}
|
||||||
|
|
||||||
|
sub display() {
|
||||||
|
return
|
||||||
|
; ubyte ci
|
||||||
|
; txt.nl()
|
||||||
|
; elite_planet.print_name_uppercase()
|
||||||
|
; txt.print(" trade market:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
|
||||||
|
; for ci in 0 to len(names)-1 {
|
||||||
|
; elite_util.print_right(13, names[ci])
|
||||||
|
; txt.print(" ")
|
||||||
|
; elite_util.print_10s(current_price[ci])
|
||||||
|
; txt.column(24)
|
||||||
|
; txt.print_ub(current_quantity[ci])
|
||||||
|
; txt.chrout(' ')
|
||||||
|
; when units[ci] {
|
||||||
|
; 0 -> txt.chrout('t')
|
||||||
|
; 1 -> txt.print("kg")
|
||||||
|
; 2 -> txt.chrout('g')
|
||||||
|
; }
|
||||||
|
; txt.column(32)
|
||||||
|
; txt.print_ub(elite_ship.cargohold[ci])
|
||||||
|
; txt.nl()
|
||||||
|
; }
|
||||||
|
}
|
||||||
|
|
||||||
|
sub match(uword nameptr) -> ubyte {
|
||||||
|
ubyte ci
|
||||||
|
for ci in 0 to len(names)-1 {
|
||||||
|
if elite_util.prefix_matches(nameptr, names[ci])
|
||||||
|
return ci
|
||||||
|
}
|
||||||
|
return 255
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elite_galaxy {
|
||||||
|
const uword GALSIZE = 256
|
||||||
|
const uword base0 = $5A4A ; seeds for the first galaxy
|
||||||
|
const uword base1 = $0248
|
||||||
|
const uword base2 = $B753
|
||||||
|
|
||||||
|
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
|
||||||
|
|
||||||
|
ubyte number
|
||||||
|
|
||||||
|
uword[3] seed
|
||||||
|
|
||||||
|
sub init(ubyte galaxynum) {
|
||||||
|
number = 1
|
||||||
|
elite_planet.number = 255
|
||||||
|
seed[0] = base0
|
||||||
|
seed[1] = base1
|
||||||
|
seed[2] = base2
|
||||||
|
repeat galaxynum-1 {
|
||||||
|
nextgalaxy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub nextgalaxy() {
|
||||||
|
textelite.num_commands++
|
||||||
|
|
||||||
|
seed[0] = twist(seed[0])
|
||||||
|
seed[1] = twist(seed[1])
|
||||||
|
seed[2] = twist(seed[2])
|
||||||
|
number++
|
||||||
|
if number==9
|
||||||
|
number = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
sub travel_to(ubyte galaxynum, ubyte system) {
|
||||||
|
init(galaxynum)
|
||||||
|
generate_next_planet() ; always at least planet 0 (separate to avoid repeat ubyte overflow)
|
||||||
|
repeat system {
|
||||||
|
generate_next_planet()
|
||||||
|
textelite.num_commands++
|
||||||
|
}
|
||||||
|
elite_planet.name = make_current_planet_name()
|
||||||
|
init_market_for_planet()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub init_market_for_planet() {
|
||||||
|
elite_market.init(lsb(seed[0])+msb(seed[2]))
|
||||||
|
}
|
||||||
|
|
||||||
|
sub search_closest_planet(uword nameptr) -> bool {
|
||||||
|
textelite.num_commands++
|
||||||
|
|
||||||
|
ubyte x = elite_planet.x
|
||||||
|
ubyte y = elite_planet.y
|
||||||
|
ubyte current_planet_num = elite_planet.number
|
||||||
|
|
||||||
|
init(number)
|
||||||
|
bool found = false
|
||||||
|
ubyte current_closest_pi
|
||||||
|
ubyte current_distance = 127
|
||||||
|
ubyte pi
|
||||||
|
for pi in 0 to 255 {
|
||||||
|
generate_next_planet()
|
||||||
|
elite_planet.name = make_current_planet_name()
|
||||||
|
if elite_util.prefix_matches(nameptr, elite_planet.name) {
|
||||||
|
ubyte distance = elite_planet.distance(x, y)
|
||||||
|
if distance < current_distance {
|
||||||
|
current_distance = distance
|
||||||
|
current_closest_pi = pi
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found
|
||||||
|
travel_to(number, current_closest_pi)
|
||||||
|
else
|
||||||
|
travel_to(number, current_planet_num)
|
||||||
|
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
sub local_area() {
|
||||||
|
ubyte current_planet = elite_planet.number
|
||||||
|
ubyte px = elite_planet.x
|
||||||
|
ubyte py = elite_planet.y
|
||||||
|
ubyte pn = 0
|
||||||
|
|
||||||
|
init(number)
|
||||||
|
; txt.print("\nGalaxy #")
|
||||||
|
; txt.print_ub(number)
|
||||||
|
; txt.print(" - systems in vicinity:\n")
|
||||||
|
do {
|
||||||
|
generate_next_planet()
|
||||||
|
ubyte distance = elite_planet.distance(px, py)
|
||||||
|
if distance <= elite_ship.Max_fuel {
|
||||||
|
; if distance <= elite_ship.fuel
|
||||||
|
; txt.chrout('*')
|
||||||
|
; else
|
||||||
|
; txt.chrout('-')
|
||||||
|
; txt.spc()
|
||||||
|
elite_planet.name = make_current_planet_name()
|
||||||
|
elite_planet.display(true, distance)
|
||||||
|
}
|
||||||
|
pn++
|
||||||
|
} until pn==0
|
||||||
|
|
||||||
|
travel_to(number, current_planet)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub starmap(bool local) {
|
||||||
|
ubyte current_planet = elite_planet.number
|
||||||
|
ubyte px = elite_planet.x
|
||||||
|
ubyte py = elite_planet.y
|
||||||
|
str current_name = " " ; 8 max
|
||||||
|
ubyte pn = 0
|
||||||
|
|
||||||
|
current_name = elite_planet.name
|
||||||
|
init(number)
|
||||||
|
; txt.clear_screen()
|
||||||
|
; txt.print("Galaxy #")
|
||||||
|
; txt.print_ub(number)
|
||||||
|
; if local
|
||||||
|
; txt.print(" - local systems")
|
||||||
|
; else
|
||||||
|
; txt.print(" - galaxy")
|
||||||
|
; txt.print(" starmap:\n")
|
||||||
|
ubyte max_distance = 255
|
||||||
|
if local
|
||||||
|
max_distance = elite_ship.Max_fuel
|
||||||
|
ubyte home_sx
|
||||||
|
ubyte home_sy
|
||||||
|
ubyte home_distance
|
||||||
|
|
||||||
|
do {
|
||||||
|
generate_next_planet()
|
||||||
|
ubyte distance = elite_planet.distance(px, py)
|
||||||
|
if distance <= max_distance {
|
||||||
|
elite_planet.name = make_current_planet_name()
|
||||||
|
elite_planet.name[0] = strings.upperchar(elite_planet.name[0])
|
||||||
|
uword tx = elite_planet.x
|
||||||
|
uword ty = elite_planet.y
|
||||||
|
if local {
|
||||||
|
tx = tx + 24 - px
|
||||||
|
ty = ty + 24 - py
|
||||||
|
}
|
||||||
|
ubyte sx = display_scale_x(tx)
|
||||||
|
ubyte sy = display_scale_y(ty)
|
||||||
|
ubyte char = '*'
|
||||||
|
if elite_planet.number==current_planet
|
||||||
|
char = '%'
|
||||||
|
if local {
|
||||||
|
print_planet_details(elite_planet.name, sx, sy, distance)
|
||||||
|
} else if elite_planet.number==current_planet {
|
||||||
|
home_distance = distance
|
||||||
|
home_sx = sx
|
||||||
|
home_sy = sy
|
||||||
|
}
|
||||||
|
; txt.setchr(2+sx, 2+sy, char)
|
||||||
|
}
|
||||||
|
pn++
|
||||||
|
} until pn==0
|
||||||
|
|
||||||
|
if not local
|
||||||
|
print_planet_details(current_name, home_sx, home_sy, home_distance)
|
||||||
|
|
||||||
|
; if local
|
||||||
|
; txt.plot(0, display_scale_y(64) + 4)
|
||||||
|
; else
|
||||||
|
; txt.plot(0, display_scale_y(256) + 4 as ubyte)
|
||||||
|
travel_to(number, current_planet)
|
||||||
|
|
||||||
|
sub print_planet_details(str name, ubyte screenx, ubyte screeny, ubyte d) {
|
||||||
|
return
|
||||||
|
; txt.plot(2+screenx-2, 2+screeny+1)
|
||||||
|
; txt.print(name)
|
||||||
|
; if d!=0 {
|
||||||
|
; txt.plot(2+screenx-2, 2+screeny+2)
|
||||||
|
; elite_util.print_10s(d)
|
||||||
|
; txt.print(" LY")
|
||||||
|
; }
|
||||||
|
}
|
||||||
|
|
||||||
|
sub display_scale_x(uword x) -> ubyte {
|
||||||
|
if local
|
||||||
|
return x/2 as ubyte
|
||||||
|
return x/8 as ubyte
|
||||||
|
}
|
||||||
|
|
||||||
|
sub display_scale_y(uword y) -> ubyte {
|
||||||
|
if local
|
||||||
|
return y/4 as ubyte
|
||||||
|
return y/16 as ubyte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ubyte pn_pair1
|
||||||
|
ubyte pn_pair2
|
||||||
|
ubyte pn_pair3
|
||||||
|
ubyte pn_pair4
|
||||||
|
bool longname
|
||||||
|
|
||||||
|
sub generate_next_planet() {
|
||||||
|
determine_planet_properties()
|
||||||
|
longname = lsb(seed[0]) & 64 !=0
|
||||||
|
|
||||||
|
; Always four iterations of random number
|
||||||
|
pn_pair1 = (msb(seed[2]) & 31) * 2
|
||||||
|
tweakseed()
|
||||||
|
pn_pair2 = (msb(seed[2]) & 31) * 2
|
||||||
|
tweakseed()
|
||||||
|
pn_pair3 = (msb(seed[2]) & 31) * 2
|
||||||
|
tweakseed()
|
||||||
|
pn_pair4 = (msb(seed[2]) & 31) * 2
|
||||||
|
tweakseed()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub make_current_planet_name() -> str {
|
||||||
|
ubyte ni = 0
|
||||||
|
str name = " " ; max 8
|
||||||
|
|
||||||
|
if pn_pairs[pn_pair1] != '.' {
|
||||||
|
name[ni] = pn_pairs[pn_pair1]
|
||||||
|
ni++
|
||||||
|
}
|
||||||
|
if pn_pairs[pn_pair1+1] != '.' {
|
||||||
|
name[ni] = pn_pairs[pn_pair1+1]
|
||||||
|
ni++
|
||||||
|
}
|
||||||
|
if pn_pairs[pn_pair2] != '.' {
|
||||||
|
name[ni] = pn_pairs[pn_pair2]
|
||||||
|
ni++
|
||||||
|
}
|
||||||
|
if pn_pairs[pn_pair2+1] != '.' {
|
||||||
|
name[ni] = pn_pairs[pn_pair2+1]
|
||||||
|
ni++
|
||||||
|
}
|
||||||
|
if pn_pairs[pn_pair3] != '.' {
|
||||||
|
name[ni] = pn_pairs[pn_pair3]
|
||||||
|
ni++
|
||||||
|
}
|
||||||
|
if pn_pairs[pn_pair3+1] != '.' {
|
||||||
|
name[ni] = pn_pairs[pn_pair3+1]
|
||||||
|
ni++
|
||||||
|
}
|
||||||
|
|
||||||
|
if longname {
|
||||||
|
if pn_pairs[pn_pair4] != '.' {
|
||||||
|
name[ni] = pn_pairs[pn_pair4]
|
||||||
|
ni++
|
||||||
|
}
|
||||||
|
if pn_pairs[pn_pair4+1] != '.' {
|
||||||
|
name[ni] = pn_pairs[pn_pair4+1]
|
||||||
|
ni++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name[ni] = 0
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
sub determine_planet_properties() {
|
||||||
|
; create the planet's characteristics
|
||||||
|
elite_planet.number++
|
||||||
|
elite_planet.x = msb(seed[1])
|
||||||
|
elite_planet.y = msb(seed[0])
|
||||||
|
elite_planet.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
|
||||||
|
elite_planet.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
|
||||||
|
if elite_planet.govtype <= 1
|
||||||
|
elite_planet.economy = (elite_planet.economy | 2)
|
||||||
|
elite_planet.techlevel = (msb(seed[1]) & 3) + (elite_planet.economy ^ 7)
|
||||||
|
elite_planet.techlevel += elite_planet.govtype >> 1
|
||||||
|
if elite_planet.govtype & 1 !=0
|
||||||
|
elite_planet.techlevel++
|
||||||
|
elite_planet.population = 4 * elite_planet.techlevel + elite_planet.economy
|
||||||
|
elite_planet.population += elite_planet.govtype + 1
|
||||||
|
elite_planet.productivity = ((elite_planet.economy ^ 7) + 3) * (elite_planet.govtype + 4)
|
||||||
|
elite_planet.productivity *= elite_planet.population * 8
|
||||||
|
ubyte seed2_msb = msb(seed[2])
|
||||||
|
elite_planet.radius = mkword((seed2_msb & 15) + 11, elite_planet.x)
|
||||||
|
elite_planet.species_is_alien = lsb(seed[2]) & 128 !=0 ; bit 7 of w2_lo
|
||||||
|
if elite_planet.species_is_alien {
|
||||||
|
elite_planet.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
|
||||||
|
elite_planet.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
|
||||||
|
elite_planet.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
|
||||||
|
elite_planet.species_kind = (elite_planet.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||||
|
}
|
||||||
|
|
||||||
|
elite_planet.goatsoup_seed[0] = lsb(seed[1])
|
||||||
|
elite_planet.goatsoup_seed[1] = msb(seed[1])
|
||||||
|
elite_planet.goatsoup_seed[2] = lsb(seed[2])
|
||||||
|
elite_planet.goatsoup_seed[3] = seed2_msb
|
||||||
|
}
|
||||||
|
|
||||||
|
sub tweakseed() {
|
||||||
|
uword temp = seed[0] + seed[1] + seed[2]
|
||||||
|
seed[0] = seed[1]
|
||||||
|
seed[1] = seed[2]
|
||||||
|
seed[2] = temp
|
||||||
|
}
|
||||||
|
|
||||||
|
sub twist(uword x) -> uword {
|
||||||
|
ubyte xh = msb(x)
|
||||||
|
ubyte xl = lsb(x)
|
||||||
|
xh <<= 1 ; make sure carry flag is not used on first shift!
|
||||||
|
rol(xl)
|
||||||
|
return mkword(xh, xl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elite_planet {
|
||||||
|
str[] @nosplit words81 = ["fabled", "notable", "well known", "famous", "noted"]
|
||||||
|
str[] @nosplit words82 = ["very", "mildly", "most", "reasonably", ""]
|
||||||
|
str[] @nosplit words83 = ["ancient", "\x95", "great", "vast", "pink"]
|
||||||
|
str[] @nosplit words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
|
||||||
|
str[] @nosplit words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
|
||||||
|
str[] @nosplit words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
|
||||||
|
str[] @nosplit words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
|
||||||
|
str[] @nosplit words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
|
||||||
|
str[] @nosplit words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
|
||||||
|
str[] @nosplit words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
|
||||||
|
str[] @nosplit words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
|
||||||
|
str[] @nosplit words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
|
||||||
|
str[] @nosplit words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
|
||||||
|
str[] @nosplit words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
|
||||||
|
str[] @nosplit words8F = ["\xB0", "The planet \xB0", "The world \xB0", "This planet", "This world"]
|
||||||
|
str[] @nosplit words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
|
||||||
|
str[] @nosplit words91 = ["planet", "world", "place", "little planet", "dump"]
|
||||||
|
str[] @nosplit words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
|
||||||
|
str[] @nosplit words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
|
||||||
|
str[] @nosplit words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
|
||||||
|
str[] @nosplit words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
|
||||||
|
str[] @nosplit words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
|
||||||
|
str[] @nosplit words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
|
||||||
|
str[] @nosplit words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
|
||||||
|
str[] @nosplit words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
|
||||||
|
str[] @nosplit words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
|
||||||
|
str[] @nosplit words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
|
||||||
|
str[] @nosplit words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
|
||||||
|
str[] @nosplit words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
|
||||||
|
str[] @nosplit words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
|
||||||
|
str[] @nosplit words9F = ["shrew", "beast", "bison", "snake", "wolf"]
|
||||||
|
str[] @nosplit wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
|
||||||
|
str[] @nosplit wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
|
||||||
|
str[] @nosplit wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
|
||||||
|
str[] @nosplit wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
|
||||||
|
str[] @nosplit wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
|
||||||
|
|
||||||
|
uword[] @shared wordlists = [
|
||||||
|
words81, words82, words83, words84, words85, words86, words87, words88,
|
||||||
|
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
|
||||||
|
words91, words92, words93, words94, words95, words96, words97, words98,
|
||||||
|
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
|
||||||
|
wordsA1, wordsA2, wordsA3, wordsA4]
|
||||||
|
|
||||||
|
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
|
||||||
|
|
||||||
|
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
|
||||||
|
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
|
||||||
|
|
||||||
|
str name = " " ; 8 max
|
||||||
|
ubyte number ; starts at 0 in new galaxy, then increases by 1 for each generated planet
|
||||||
|
ubyte x
|
||||||
|
ubyte y
|
||||||
|
ubyte economy
|
||||||
|
ubyte govtype
|
||||||
|
ubyte techlevel
|
||||||
|
ubyte population
|
||||||
|
uword productivity
|
||||||
|
uword radius
|
||||||
|
bool species_is_alien ; otherwise "Human Colonials"
|
||||||
|
ubyte species_size
|
||||||
|
ubyte species_color
|
||||||
|
ubyte species_look
|
||||||
|
ubyte species_kind
|
||||||
|
|
||||||
|
sub set_seed(uword s1, uword s2) {
|
||||||
|
goatsoup_seed[0] = lsb(s1)
|
||||||
|
goatsoup_seed[1] = msb(s1)
|
||||||
|
goatsoup_seed[2] = lsb(s2)
|
||||||
|
goatsoup_seed[3] = msb(s2)
|
||||||
|
reset_rnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub reset_rnd() {
|
||||||
|
goatsoup_rnd[0] = goatsoup_seed[0]
|
||||||
|
goatsoup_rnd[1] = goatsoup_seed[1]
|
||||||
|
goatsoup_rnd[2] = goatsoup_seed[2]
|
||||||
|
goatsoup_rnd[3] = goatsoup_seed[3]
|
||||||
|
}
|
||||||
|
|
||||||
|
sub random_name() -> str {
|
||||||
|
ubyte ii
|
||||||
|
str randname = " " ; 8 chars max
|
||||||
|
ubyte nx = 0
|
||||||
|
for ii in 0 to goatsoup_rnd_number() & 3 {
|
||||||
|
ubyte xx = goatsoup_rnd_number() & $3e
|
||||||
|
if pairs0[xx] != '.' {
|
||||||
|
randname[nx] = pairs0[xx]
|
||||||
|
nx++
|
||||||
|
}
|
||||||
|
xx++
|
||||||
|
if pairs0[xx] != '.' {
|
||||||
|
randname[nx] = pairs0[xx]
|
||||||
|
nx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
randname[nx] = 0
|
||||||
|
randname[0] = strings.upperchar(randname[0])
|
||||||
|
return randname
|
||||||
|
}
|
||||||
|
|
||||||
|
sub goatsoup_rnd_number() -> ubyte {
|
||||||
|
ubyte xx = goatsoup_rnd[0] * 2
|
||||||
|
uword a = xx as uword + goatsoup_rnd[2]
|
||||||
|
if goatsoup_rnd[0] > 127
|
||||||
|
a ++
|
||||||
|
goatsoup_rnd[0] = lsb(a)
|
||||||
|
goatsoup_rnd[2] = xx
|
||||||
|
xx = goatsoup_rnd[1]
|
||||||
|
ubyte ac = xx + goatsoup_rnd[3] + msb(a)
|
||||||
|
goatsoup_rnd[1] = ac
|
||||||
|
goatsoup_rnd[3] = xx
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
sub distance(ubyte px, ubyte py) -> ubyte {
|
||||||
|
uword ax
|
||||||
|
uword ay
|
||||||
|
if px>x
|
||||||
|
ax=px-x
|
||||||
|
else
|
||||||
|
ax=x-px
|
||||||
|
if py>y
|
||||||
|
ay=py-y
|
||||||
|
else
|
||||||
|
ay=y-py
|
||||||
|
ay /= 2
|
||||||
|
ubyte d = sqrt(ax*ax + ay*ay)
|
||||||
|
if d>63
|
||||||
|
return 255
|
||||||
|
return d*4
|
||||||
|
}
|
||||||
|
|
||||||
|
sub soup() -> str {
|
||||||
|
str planet_result = " " * 160
|
||||||
|
uword[6] source_stack
|
||||||
|
ubyte stack_ptr = 0
|
||||||
|
str start_source = "\x8F is \x97."
|
||||||
|
uword source_ptr = &start_source
|
||||||
|
uword result_ptr = &planet_result
|
||||||
|
|
||||||
|
reset_rnd()
|
||||||
|
recursive_soup()
|
||||||
|
return planet_result
|
||||||
|
|
||||||
|
sub recursive_soup() {
|
||||||
|
repeat {
|
||||||
|
ubyte c = @(source_ptr)
|
||||||
|
source_ptr++
|
||||||
|
if c == $00 {
|
||||||
|
@(result_ptr) = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else if c <= $80 {
|
||||||
|
@(result_ptr) = c
|
||||||
|
result_ptr++
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if c <= $a4 {
|
||||||
|
ubyte rnr = goatsoup_rnd_number()
|
||||||
|
ubyte wordNr = ((rnr >= $33) as ubyte) + ((rnr >= $66) as ubyte) + ((rnr >= $99) as ubyte) + ((rnr >= $CC) as ubyte)
|
||||||
|
source_stack[stack_ptr] = source_ptr
|
||||||
|
stack_ptr++
|
||||||
|
source_ptr = getword(c, wordNr)
|
||||||
|
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
|
||||||
|
stack_ptr--
|
||||||
|
source_ptr = source_stack[stack_ptr]
|
||||||
|
} else {
|
||||||
|
if c == $b0 {
|
||||||
|
@(result_ptr) = strings.upperchar(name[0])
|
||||||
|
result_ptr++
|
||||||
|
concat_string(&name + 1)
|
||||||
|
}
|
||||||
|
else if c == $b1 {
|
||||||
|
@(result_ptr) = strings.upperchar(name[0])
|
||||||
|
result_ptr++
|
||||||
|
ubyte ni
|
||||||
|
for ni in 1 to len(name) {
|
||||||
|
ubyte cc = name[ni]
|
||||||
|
if cc in ['e', 'o', 0]
|
||||||
|
break
|
||||||
|
else {
|
||||||
|
@(result_ptr) = cc
|
||||||
|
result_ptr++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@(result_ptr) = 'i'
|
||||||
|
result_ptr++
|
||||||
|
@(result_ptr) = 'a'
|
||||||
|
result_ptr++
|
||||||
|
@(result_ptr) = 'n'
|
||||||
|
result_ptr++
|
||||||
|
}
|
||||||
|
else if c == $b2 {
|
||||||
|
concat_string(random_name())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@(result_ptr) = c
|
||||||
|
result_ptr++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub concat_string(uword str_ptr) {
|
||||||
|
repeat {
|
||||||
|
ubyte c = @(str_ptr)
|
||||||
|
if c==0
|
||||||
|
break
|
||||||
|
else {
|
||||||
|
@(result_ptr) = c
|
||||||
|
str_ptr++
|
||||||
|
result_ptr++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub display(bool compressed, ubyte distance) {
|
||||||
|
txt.print(soup())
|
||||||
|
txt.nl()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getword(ubyte listnum, ubyte wordidx) -> uword {
|
||||||
|
uword list = wordlists[listnum-$81]
|
||||||
|
return peekw(list + wordidx*2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elite_util {
|
||||||
|
sub prefix_matches(uword prefixptr, uword stringptr) -> bool {
|
||||||
|
repeat {
|
||||||
|
ubyte pc = @(prefixptr)
|
||||||
|
ubyte sc = @(stringptr)
|
||||||
|
if pc == 0
|
||||||
|
return true
|
||||||
|
; to lowercase for case insensitive compare:
|
||||||
|
if strings.lowerchar(pc)!=strings.lowerchar(sc)
|
||||||
|
return false
|
||||||
|
prefixptr++
|
||||||
|
stringptr++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
112
benchmark-program/benchmark.p8
Normal file
112
benchmark-program/benchmark.p8
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
|
||||||
|
; This benchmark program is meant to check for regressions in the
|
||||||
|
; Prog8 compiler's code-generator (performance wise).
|
||||||
|
;
|
||||||
|
; As the X16 computer is a more or less fixed system, it's not very useful
|
||||||
|
; to benchmark the computer itself with.
|
||||||
|
|
||||||
|
|
||||||
|
%import textio
|
||||||
|
%import b_adpcm
|
||||||
|
%import b_circles
|
||||||
|
%import b_3d
|
||||||
|
%import b_life
|
||||||
|
%import b_mandelbrot
|
||||||
|
%import b_queens
|
||||||
|
%import b_textelite
|
||||||
|
%import b_maze
|
||||||
|
|
||||||
|
%zeropage basicsafe
|
||||||
|
%option no_sysinit
|
||||||
|
|
||||||
|
|
||||||
|
main {
|
||||||
|
|
||||||
|
str[20] benchmark_names
|
||||||
|
uword[20] benchmark_score
|
||||||
|
|
||||||
|
|
||||||
|
sub start() {
|
||||||
|
ubyte benchmark_number
|
||||||
|
|
||||||
|
void cx16.set_screen_mode(3)
|
||||||
|
txt.color2(1, 6)
|
||||||
|
txt.clear_screen()
|
||||||
|
|
||||||
|
txt.print("\n\n\n prog8 compiler benchmark tests.\n")
|
||||||
|
sys.wait(60)
|
||||||
|
|
||||||
|
benchmark_number = 0
|
||||||
|
|
||||||
|
announce_benchmark("maze solver")
|
||||||
|
benchmark_score[benchmark_number] = maze.bench(300)
|
||||||
|
benchmark_number++
|
||||||
|
|
||||||
|
announce_benchmark("n-queens")
|
||||||
|
benchmark_score[benchmark_number] = queens.bench(300)
|
||||||
|
benchmark_number++
|
||||||
|
|
||||||
|
announce_benchmark("mandelbrot (floating point)")
|
||||||
|
benchmark_score[benchmark_number] = mandelbrot.calc(400)
|
||||||
|
benchmark_number++
|
||||||
|
|
||||||
|
announce_benchmark("game of life")
|
||||||
|
benchmark_score[benchmark_number] = life.benchmark(300)
|
||||||
|
benchmark_number++
|
||||||
|
|
||||||
|
announce_benchmark("3d model rotation")
|
||||||
|
benchmark_score[benchmark_number] = rotate3d.benchmark(300)
|
||||||
|
benchmark_number++
|
||||||
|
|
||||||
|
announce_benchmark("adpcm audio decoding")
|
||||||
|
benchmark_score[benchmark_number] = adpcm.decode_benchmark(300)
|
||||||
|
benchmark_number++
|
||||||
|
|
||||||
|
announce_benchmark("circles with gfx_lores")
|
||||||
|
benchmark_score[benchmark_number] = circles.draw(false, 300)
|
||||||
|
benchmark_number++
|
||||||
|
|
||||||
|
; announce_benchmark("circles with kernal")
|
||||||
|
; benchmark_score[benchmark_number] = circles.draw(true, 300)
|
||||||
|
; benchmark_number++
|
||||||
|
|
||||||
|
announce_benchmark("text-elite")
|
||||||
|
benchmark_score[benchmark_number] = textelite.bench(120)
|
||||||
|
benchmark_number++
|
||||||
|
|
||||||
|
benchmark_names[benchmark_number] = 0
|
||||||
|
benchmark_score[benchmark_number] = 0
|
||||||
|
|
||||||
|
void cx16.set_screen_mode(3)
|
||||||
|
txt.uppercase()
|
||||||
|
txt.color2(1, 6)
|
||||||
|
uword final_score
|
||||||
|
benchmark_number = 0
|
||||||
|
txt.print("\nscore benchmark\n\n")
|
||||||
|
do {
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(benchmark_score[benchmark_number])
|
||||||
|
txt.column(6)
|
||||||
|
txt.print(benchmark_names[benchmark_number])
|
||||||
|
final_score += benchmark_score[benchmark_number]
|
||||||
|
txt.nl()
|
||||||
|
benchmark_number++
|
||||||
|
} until benchmark_names[benchmark_number]==0
|
||||||
|
|
||||||
|
txt.print("\n\nfinal score : ")
|
||||||
|
txt.print_uw(final_score)
|
||||||
|
txt.nl()
|
||||||
|
|
||||||
|
sub announce_benchmark(str name) {
|
||||||
|
benchmark_names[benchmark_number] = name
|
||||||
|
void cx16.set_screen_mode(3)
|
||||||
|
txt.uppercase()
|
||||||
|
txt.color2(1, 6)
|
||||||
|
txt.clear_screen()
|
||||||
|
txt.plot(4, 6)
|
||||||
|
txt.print(benchmark_names[benchmark_number])
|
||||||
|
txt.nl()
|
||||||
|
sys.wait(60)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
build.gradle
10
build.gradle
@ -1,10 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id "org.jetbrains.kotlin.jvm" version "$kotlinVersion" apply false
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
26
build.gradle.kts
Normal file
26
build.gradle.kts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm") version "2.1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
apply(plugin="kotlin")
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
compilerOptions {
|
||||||
|
freeCompilerArgs = listOf("-Xwhen-guards")
|
||||||
|
jvmTarget = JvmTarget.JVM_11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
}
|
||||||
|
}
|
@ -1,43 +0,0 @@
|
|||||||
|
|
||||||
plugins {
|
|
||||||
id 'java'
|
|
||||||
id 'application'
|
|
||||||
id "org.jetbrains.kotlin.jvm"
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
toolchain {
|
|
||||||
languageVersion = JavaLanguageVersion.of(javaVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileKotlin {
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = javaVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileTestKotlin {
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = javaVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
// should have no dependencies to other modules
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
|
||||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16"
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
java {
|
|
||||||
srcDirs = ["${project.projectDir}/src"]
|
|
||||||
}
|
|
||||||
resources {
|
|
||||||
srcDirs = ["${project.projectDir}/res"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// note: there are no unit tests in this module!
|
|
24
codeCore/build.gradle.kts
Normal file
24
codeCore/build.gradle.kts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// should have no dependencies to other modules
|
||||||
|
// implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
implementation("com.michael-bull.kotlin-result:kotlin-result-jvm:2.0.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java {
|
||||||
|
srcDir("${project.projectDir}/src")
|
||||||
|
}
|
||||||
|
resources {
|
||||||
|
srcDir("${project.projectDir}/res")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: there are no unit tests in this module!
|
@ -1,8 +1,7 @@
|
|||||||
package prog8
|
package prog8.code
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By convention, the right side of an `Either` is used to hold successful values.
|
* By convention, the right side of an `Either` is used to hold successful values.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
sealed class Either<out L, out R> {
|
sealed class Either<out L, out R> {
|
||||||
|
|
@ -1,29 +1,44 @@
|
|||||||
package prog8.code
|
package prog8.code
|
||||||
|
|
||||||
|
import prog8.code.ast.PtAsmSub
|
||||||
|
import prog8.code.ast.PtNode
|
||||||
|
import prog8.code.ast.PtProgram
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
|
||||||
|
|
||||||
|
const val internedStringsModuleName = "prog8_interned_strings"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tree structure containing all symbol definitions in the program
|
* Tree structure containing all symbol definitions in the program
|
||||||
* (blocks, subroutines, variables (all types), memoryslabs, and labels).
|
* (blocks, subroutines, variables (all types), memoryslabs, and labels).
|
||||||
*/
|
*/
|
||||||
class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) {
|
class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GLOBAL, astProgram) {
|
||||||
fun print() = printIndented(0)
|
|
||||||
|
|
||||||
override fun printProperties() { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The table as a flat mapping of scoped names to the StNode.
|
* The table as a flat mapping of scoped names to the StNode.
|
||||||
* This gives the fastest lookup possible (no need to traverse tree nodes)
|
* This gives the fastest lookup possible (no need to traverse tree nodes)
|
||||||
*/
|
*/
|
||||||
val flat: Map<List<String>, StNode> by lazy {
|
|
||||||
val result = mutableMapOf<List<String>, StNode>()
|
private var cachedFlat: Map<String, StNode>? = null
|
||||||
fun flatten(node: StNode) {
|
|
||||||
result[node.scopedName] = node
|
val flat: Map<String, StNode> get() {
|
||||||
node.children.values.forEach { flatten(it) }
|
if(cachedFlat!=null)
|
||||||
|
return cachedFlat!!
|
||||||
|
|
||||||
|
val result = mutableMapOf<String, StNode>()
|
||||||
|
fun collect(node: StNode) {
|
||||||
|
for(child in node.children) {
|
||||||
|
result[child.value.scopedName] = child.value
|
||||||
|
collect(child.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
children.values.forEach { flatten(it) }
|
collect(this)
|
||||||
result
|
cachedFlat = result
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetCachedFlat() {
|
||||||
|
cachedFlat = null
|
||||||
}
|
}
|
||||||
|
|
||||||
val allVariables: Collection<StStaticVariable> by lazy {
|
val allVariables: Collection<StStaticVariable> by lazy {
|
||||||
@ -55,10 +70,29 @@ class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val allMemorySlabs: Collection<StMemorySlab> by lazy {
|
val allMemorySlabs: Collection<StMemorySlab> by lazy {
|
||||||
children.mapNotNull { if (it.value.type == StNodeType.MEMORYSLAB) it.value as StMemorySlab else null }
|
val vars = mutableListOf<StMemorySlab>()
|
||||||
|
fun collect(node: StNode) {
|
||||||
|
for(child in node.children) {
|
||||||
|
if(child.value.type== StNodeType.MEMORYSLAB)
|
||||||
|
vars.add(child.value as StMemorySlab)
|
||||||
|
else
|
||||||
|
collect(child.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collect(this)
|
||||||
|
vars
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lookup(scopedName: List<String>) = flat[scopedName]
|
override fun lookup(scopedName: String) = flat[scopedName]
|
||||||
|
|
||||||
|
fun getLength(name: String): Int? {
|
||||||
|
return when(val node = flat[name]) {
|
||||||
|
is StMemVar -> node.length
|
||||||
|
is StMemorySlab -> node.size.toInt()
|
||||||
|
is StStaticVariable -> node.length
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -67,7 +101,7 @@ enum class StNodeType {
|
|||||||
// MODULE, // not used with current scoping rules
|
// MODULE, // not used with current scoping rules
|
||||||
BLOCK,
|
BLOCK,
|
||||||
SUBROUTINE,
|
SUBROUTINE,
|
||||||
ROMSUB,
|
EXTSUB,
|
||||||
LABEL,
|
LABEL,
|
||||||
STATICVAR,
|
STATICVAR,
|
||||||
MEMVAR,
|
MEMVAR,
|
||||||
@ -79,44 +113,24 @@ enum class StNodeType {
|
|||||||
|
|
||||||
open class StNode(val name: String,
|
open class StNode(val name: String,
|
||||||
val type: StNodeType,
|
val type: StNodeType,
|
||||||
val position: Position,
|
val astNode: PtNode,
|
||||||
val children: MutableMap<String, StNode> = mutableMapOf()
|
val children: MutableMap<String, StNode> = mutableMapOf()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
lateinit var parent: StNode
|
lateinit var parent: StNode
|
||||||
|
|
||||||
val scopedName: List<String> by lazy {
|
val scopedName: String by lazy { scopedNameList.joinToString(".") }
|
||||||
if(type== StNodeType.GLOBAL)
|
|
||||||
emptyList()
|
|
||||||
else
|
|
||||||
parent.scopedName + name
|
|
||||||
}
|
|
||||||
|
|
||||||
fun lookup(name: String) =
|
open fun lookup(scopedName: String) =
|
||||||
lookupUnqualified(name)
|
lookup(scopedName.split('.'))
|
||||||
open fun lookup(scopedName: List<String>) =
|
|
||||||
if(scopedName.size>1) lookupQualified(scopedName) else lookupUnqualified(scopedName[0])
|
|
||||||
fun lookupOrElse(name: String, default: () -> StNode) =
|
|
||||||
lookupUnqualified(name) ?: default()
|
|
||||||
fun lookupOrElse(scopedName: List<String>, default: () -> StNode) =
|
|
||||||
lookup(scopedName) ?: default()
|
|
||||||
|
|
||||||
private fun lookupQualified(scopedName: List<String>): StNode? {
|
fun lookupUnscopedOrElse(name: String, default: () -> StNode) =
|
||||||
// a scoped name refers to a name in another namespace, and always stars from the root.
|
lookupUnscoped(name) ?: default()
|
||||||
var node = this
|
|
||||||
while(node.type!= StNodeType.GLOBAL)
|
|
||||||
node = node.parent
|
|
||||||
|
|
||||||
for(name in scopedName) {
|
fun lookupOrElse(scopedName: String, default: () -> StNode): StNode =
|
||||||
if(name in node.children)
|
lookup(scopedName.split('.')) ?: default()
|
||||||
node = node.children.getValue(name)
|
|
||||||
else
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun lookupUnqualified(name: String): StNode? {
|
fun lookupUnscoped(name: String): StNode? {
|
||||||
// first consider the builtin functions
|
// first consider the builtin functions
|
||||||
var globalscope = this
|
var globalscope = this
|
||||||
while(globalscope.type!= StNodeType.GLOBAL)
|
while(globalscope.type!= StNodeType.GLOBAL)
|
||||||
@ -138,82 +152,98 @@ open class StNode(val name: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun printIndented(indent: Int) {
|
|
||||||
print(" ".repeat(indent))
|
|
||||||
when(type) {
|
|
||||||
StNodeType.GLOBAL -> print("SYMBOL-TABLE:")
|
|
||||||
StNodeType.BLOCK -> print("(B) ")
|
|
||||||
StNodeType.SUBROUTINE -> print("(S) ")
|
|
||||||
StNodeType.LABEL -> print("(L) ")
|
|
||||||
StNodeType.STATICVAR -> print("(V) ")
|
|
||||||
StNodeType.MEMVAR -> print("(M) ")
|
|
||||||
StNodeType.MEMORYSLAB -> print("(MS) ")
|
|
||||||
StNodeType.CONSTANT -> print("(C) ")
|
|
||||||
StNodeType.BUILTINFUNC -> print("(F) ")
|
|
||||||
StNodeType.ROMSUB -> print("(R) ")
|
|
||||||
}
|
|
||||||
printProperties()
|
|
||||||
println()
|
|
||||||
children.forEach { (_, node) -> node.printIndented(indent+1) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun printProperties() {
|
|
||||||
print("$name ")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(child: StNode) {
|
fun add(child: StNode) {
|
||||||
children[child.name] = child
|
children[child.name] = child
|
||||||
child.parent = this
|
child.parent = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val scopedNameList: List<String> by lazy {
|
||||||
|
if(type==StNodeType.GLOBAL)
|
||||||
|
emptyList()
|
||||||
|
else
|
||||||
|
parent.scopedNameList + name
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lookup(scopedName: List<String>): StNode? {
|
||||||
|
// a scoped name refers to a name in another namespace, and always stars from the root.
|
||||||
|
var node = this
|
||||||
|
while(node.type!=StNodeType.GLOBAL)
|
||||||
|
node = node.parent
|
||||||
|
|
||||||
|
for(name in scopedName) {
|
||||||
|
if(name in node.children)
|
||||||
|
node = node.children.getValue(name)
|
||||||
|
else
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StStaticVariable(name: String,
|
class StStaticVariable(name: String,
|
||||||
val dt: DataType,
|
val dt: DataType,
|
||||||
val onetimeInitializationNumericValue: Double?, // regular (every-run-time) initialization is done via regular assignments
|
val initializationStringValue: StString?,
|
||||||
val onetimeInitializationStringValue: StString?,
|
val initializationArrayValue: StArray?,
|
||||||
val onetimeInitializationArrayValue: StArray?,
|
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||||
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
val zpwish: ZeropageWish, // used in the variable allocator
|
||||||
val zpwish: ZeropageWish,
|
val align: Int,
|
||||||
position: Position) : StNode(name, StNodeType.STATICVAR, position) {
|
astNode: PtNode) : StNode(name, StNodeType.STATICVAR, astNode) {
|
||||||
|
|
||||||
|
var initializationNumericValue: Double? = null
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun setOnetimeInitNumeric(number: Double) {
|
||||||
|
// In certain cases the init value of an existing var should be updated,
|
||||||
|
// so we can't ask this as a constructor parameter.
|
||||||
|
// This has to do with the way Prog8 does the (re)initialization of such variables: via code assignment statements.
|
||||||
|
// Certain codegens might want to put them back into the variable directly.
|
||||||
|
// For strings and arrays this doesn't occur - these are always already specced at creation time.
|
||||||
|
initializationNumericValue = number
|
||||||
|
}
|
||||||
|
|
||||||
|
val uninitialized: Boolean
|
||||||
|
get() = initializationArrayValue==null && initializationStringValue==null && initializationNumericValue==null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(length!=null) {
|
if(length!=null) {
|
||||||
require(onetimeInitializationNumericValue == null)
|
require(initializationNumericValue == null)
|
||||||
if(onetimeInitializationArrayValue!=null)
|
if(initializationArrayValue!=null)
|
||||||
require(length == onetimeInitializationArrayValue.size)
|
require(initializationArrayValue.isEmpty() ||initializationArrayValue.size==length)
|
||||||
}
|
}
|
||||||
if(onetimeInitializationNumericValue!=null)
|
if(initializationNumericValue!=null) {
|
||||||
require(dt in NumericDatatypes)
|
require(dt.isNumericOrBool)
|
||||||
if(onetimeInitializationArrayValue!=null)
|
}
|
||||||
require(dt in ArrayDatatypes)
|
if(initializationArrayValue!=null) {
|
||||||
if(onetimeInitializationStringValue!=null) {
|
require(dt.isArray)
|
||||||
require(dt == DataType.STR)
|
require(length == initializationArrayValue.size)
|
||||||
require(length == onetimeInitializationStringValue.first.length+1)
|
}
|
||||||
|
if(initializationStringValue!=null) {
|
||||||
|
require(dt.isString)
|
||||||
|
require(length == initializationStringValue.first.length + 1)
|
||||||
|
}
|
||||||
|
if(align > 0) {
|
||||||
|
require(dt.isString || dt.isArray)
|
||||||
|
require(zpwish != ZeropageWish.REQUIRE_ZEROPAGE && zpwish != ZeropageWish.PREFER_ZEROPAGE)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun printProperties() {
|
|
||||||
print("$name dt=$dt zpw=$zpwish")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class StConstant(name: String, val dt: DataType, val value: Double, position: Position) :
|
class StConstant(name: String, val dt: BaseDataType, val value: Double, astNode: PtNode) :
|
||||||
StNode(name, StNodeType.CONSTANT, position) {
|
StNode(name, StNodeType.CONSTANT, astNode)
|
||||||
override fun printProperties() {
|
|
||||||
print("$name dt=$dt value=$value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class StMemVar(name: String,
|
class StMemVar(name: String,
|
||||||
val dt: DataType,
|
val dt: DataType,
|
||||||
val address: UInt,
|
val address: UInt,
|
||||||
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||||
position: Position) :
|
astNode: PtNode) :
|
||||||
StNode(name, StNodeType.MEMVAR, position) {
|
StNode(name, StNodeType.MEMVAR, astNode) {
|
||||||
override fun printProperties() {
|
|
||||||
print("$name dt=$dt address=${address.toHex()}")
|
init{
|
||||||
|
require(!dt.isString)
|
||||||
|
if(dt.isStringly && !dt.isWord)
|
||||||
|
requireNotNull(length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,37 +251,33 @@ class StMemorySlab(
|
|||||||
name: String,
|
name: String,
|
||||||
val size: UInt,
|
val size: UInt,
|
||||||
val align: UInt,
|
val align: UInt,
|
||||||
position: Position
|
astNode: PtNode
|
||||||
):
|
):
|
||||||
StNode(name, StNodeType.MEMORYSLAB, position) {
|
StNode(name, StNodeType.MEMORYSLAB, astNode)
|
||||||
override fun printProperties() {
|
|
||||||
print("$name size=$size align=$align")
|
|
||||||
|
class StSub(name: String, val parameters: List<StSubroutineParameter>, val returnType: DataType?, astNode: PtNode) :
|
||||||
|
StNode(name, StNodeType.SUBROUTINE, astNode)
|
||||||
|
|
||||||
|
|
||||||
|
class StExtSub(name: String,
|
||||||
|
val address: PtAsmSub.Address?, // null in case of asmsub, specified in case of extsub.
|
||||||
|
val parameters: List<StExtSubParameter>,
|
||||||
|
val returns: List<StExtSubParameter>,
|
||||||
|
astNode: PtNode) :
|
||||||
|
StNode(name, StNodeType.EXTSUB, astNode)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class StSubroutineParameter(val name: String, val type: DataType, val register: RegisterOrPair?)
|
||||||
|
class StExtSubParameter(val register: RegisterOrStatusflag, val type: DataType)
|
||||||
|
class StArrayElement(val number: Double?, val addressOfSymbol: String?, val boolean: Boolean?) {
|
||||||
|
init {
|
||||||
|
if(number!=null) require(addressOfSymbol==null && boolean==null)
|
||||||
|
if(addressOfSymbol!=null) require(number==null && boolean==null)
|
||||||
|
if(boolean!=null) require(addressOfSymbol==null && number==null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StSub(name: String, val parameters: List<StSubroutineParameter>, val returnType: DataType?, position: Position) :
|
|
||||||
StNode(name, StNodeType.SUBROUTINE, position) {
|
|
||||||
override fun printProperties() {
|
|
||||||
print(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class StRomSub(name: String,
|
|
||||||
val address: UInt,
|
|
||||||
val parameters: List<StRomSubParameter>,
|
|
||||||
val returns: List<RegisterOrStatusflag>,
|
|
||||||
position: Position) :
|
|
||||||
StNode(name, StNodeType.ROMSUB, position) {
|
|
||||||
override fun printProperties() {
|
|
||||||
print("$name address=${address.toHex()}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class StSubroutineParameter(val name: String, val type: DataType)
|
|
||||||
class StRomSubParameter(val register: RegisterOrStatusflag, val type: DataType)
|
|
||||||
class StArrayElement(val number: Double?, val addressOf: List<String>?)
|
|
||||||
|
|
||||||
typealias StString = Pair<String, Encoding>
|
typealias StString = Pair<String, Encoding>
|
||||||
typealias StArray = List<StArrayElement>
|
typealias StArray = List<StArrayElement>
|
||||||
|
214
codeCore/src/prog8/code/SymbolTableMaker.kt
Normal file
214
codeCore/src/prog8/code/SymbolTableMaker.kt
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
package prog8.code
|
||||||
|
|
||||||
|
import prog8.code.ast.*
|
||||||
|
import prog8.code.core.*
|
||||||
|
import prog8.code.target.VMTarget
|
||||||
|
|
||||||
|
|
||||||
|
class SymbolTableMaker(private val program: PtProgram, private val options: CompilationOptions) {
|
||||||
|
fun make(): SymbolTable {
|
||||||
|
val st = SymbolTable(program)
|
||||||
|
|
||||||
|
BuiltinFunctions.forEach {
|
||||||
|
val dt = DataType.forDt(it.value.returnType ?: BaseDataType.UNDEFINED)
|
||||||
|
st.add(StNode(it.key, StNodeType.BUILTINFUNC, PtIdentifier(it.key, dt, Position.DUMMY)))
|
||||||
|
}
|
||||||
|
|
||||||
|
val scopestack = ArrayDeque<StNode>()
|
||||||
|
scopestack.add(st)
|
||||||
|
program.children.forEach {
|
||||||
|
addToSt(it, scopestack)
|
||||||
|
}
|
||||||
|
require(scopestack.size==1)
|
||||||
|
|
||||||
|
if(options.compTarget.name != VMTarget.NAME) {
|
||||||
|
listOf(
|
||||||
|
PtMemMapped("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_B1, null, Position.DUMMY),
|
||||||
|
PtMemMapped("P8ZP_SCRATCH_REG", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY),
|
||||||
|
PtMemMapped("P8ZP_SCRATCH_W1", DataType.forDt(BaseDataType.UWORD), options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY),
|
||||||
|
PtMemMapped("P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD), options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY),
|
||||||
|
).forEach {
|
||||||
|
it.parent = program
|
||||||
|
st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return st
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addToSt(node: PtNode, scope: ArrayDeque<StNode>) {
|
||||||
|
val stNode = when(node) {
|
||||||
|
is PtAsmSub -> {
|
||||||
|
val parameters = node.parameters.map { StExtSubParameter(it.first, it.second.type) }
|
||||||
|
val returns = node.returns.map { StExtSubParameter(it.first, it.second) }
|
||||||
|
StExtSub(node.name, node.address, parameters, returns, node)
|
||||||
|
}
|
||||||
|
is PtBlock -> {
|
||||||
|
StNode(node.name, StNodeType.BLOCK, node)
|
||||||
|
}
|
||||||
|
is PtConstant -> {
|
||||||
|
require(node.type.isNumericOrBool)
|
||||||
|
StConstant(node.name, node.type.base, node.value, node)
|
||||||
|
}
|
||||||
|
is PtLabel -> {
|
||||||
|
StNode(node.name, StNodeType.LABEL, node)
|
||||||
|
}
|
||||||
|
is PtMemMapped -> {
|
||||||
|
StMemVar(node.name, node.type, node.address, node.arraySize?.toInt(), node)
|
||||||
|
}
|
||||||
|
is PtSub -> {
|
||||||
|
val params = node.parameters.map {StSubroutineParameter(it.name, it.type, it.register) }
|
||||||
|
StSub(node.name, params, node.returntype, node)
|
||||||
|
}
|
||||||
|
is PtVariable -> {
|
||||||
|
val initialNumeric: Double?
|
||||||
|
val initialString: StString?
|
||||||
|
val initialArray: StArray?
|
||||||
|
val numElements: Int?
|
||||||
|
val value = node.value
|
||||||
|
if(value!=null) {
|
||||||
|
when (value) {
|
||||||
|
is PtString -> {
|
||||||
|
initialString = StString(value.value, value.encoding)
|
||||||
|
initialArray = null
|
||||||
|
initialNumeric = null
|
||||||
|
numElements = value.value.length + 1 // include the terminating 0-byte
|
||||||
|
}
|
||||||
|
is PtArray -> {
|
||||||
|
initialArray = makeInitialArray(value)
|
||||||
|
initialString = null
|
||||||
|
initialNumeric = null
|
||||||
|
numElements = initialArray.size
|
||||||
|
require(node.arraySize?.toInt()==numElements)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
require(value is PtNumber)
|
||||||
|
initialString = null
|
||||||
|
initialArray = null
|
||||||
|
val number = value.number
|
||||||
|
initialNumeric = number
|
||||||
|
numElements = node.arraySize?.toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
initialNumeric = null
|
||||||
|
initialArray = null
|
||||||
|
initialString = null
|
||||||
|
numElements = node.arraySize?.toInt()
|
||||||
|
}
|
||||||
|
// if(node.type in SplitWordArrayTypes) {
|
||||||
|
// ... split array also add _lsb and _msb to symboltable?
|
||||||
|
// }
|
||||||
|
val stVar = StStaticVariable(node.name, node.type, initialString, initialArray, numElements, node.zeropage, node.align.toInt(), node)
|
||||||
|
if(initialNumeric!=null)
|
||||||
|
stVar.setOnetimeInitNumeric(initialNumeric)
|
||||||
|
stVar
|
||||||
|
}
|
||||||
|
is PtBuiltinFunctionCall -> {
|
||||||
|
if(node.name=="memory") {
|
||||||
|
// memory slab allocations are a builtin functioncall in the program, but end up named as well in the symboltable
|
||||||
|
require(node.name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
|
||||||
|
val slabname = (node.args[0] as PtString).value
|
||||||
|
val size = (node.args[1] as PtNumber).number.toUInt()
|
||||||
|
val align = (node.args[2] as PtNumber).number.toUInt()
|
||||||
|
// don't add memory slabs in nested scope, just put them in the top level of the ST
|
||||||
|
scope.first().add(StMemorySlab("prog8_memoryslab_$slabname", size, align, node))
|
||||||
|
}
|
||||||
|
null
|
||||||
|
}
|
||||||
|
else -> null // node is not present in the ST
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stNode!=null) {
|
||||||
|
scope.last().add(stNode)
|
||||||
|
scope.add(stNode)
|
||||||
|
}
|
||||||
|
node.children.forEach {
|
||||||
|
addToSt(it, scope)
|
||||||
|
}
|
||||||
|
if(stNode!=null)
|
||||||
|
scope.removeLast()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeInitialArray(value: PtArray): List<StArrayElement> {
|
||||||
|
return value.children.map {
|
||||||
|
when(it) {
|
||||||
|
is PtAddressOf -> {
|
||||||
|
if(it.isFromArrayElement)
|
||||||
|
TODO("address-of array element $it in initial array value")
|
||||||
|
StArrayElement(null, it.identifier.name, null)
|
||||||
|
}
|
||||||
|
is PtNumber -> StArrayElement(it.number, null, null)
|
||||||
|
is PtBool -> StArrayElement(null, null, it.value)
|
||||||
|
else -> throw AssemblyError("invalid array element $it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// override fun visit(decl: VarDecl) {
|
||||||
|
// val node =
|
||||||
|
// when(decl.type) {
|
||||||
|
// VarDeclType.VAR -> {
|
||||||
|
// var initialNumeric = (decl.value as? NumericLiteral)?.number
|
||||||
|
// if(initialNumeric==0.0)
|
||||||
|
// initialNumeric=null // variable will go into BSS and this will be set to 0
|
||||||
|
// val initialStringLit = decl.value as? StringLiteral
|
||||||
|
// val initialString = if(initialStringLit==null) null else Pair(initialStringLit.value, initialStringLit.encoding)
|
||||||
|
// val initialArrayLit = decl.value as? ArrayLiteral
|
||||||
|
// val initialArray = makeInitialArray(initialArrayLit)
|
||||||
|
// if(decl.isArray && decl.datatype !in ArrayDatatypes)
|
||||||
|
// throw FatalAstException("array vardecl has mismatched dt ${decl.datatype}")
|
||||||
|
// val numElements =
|
||||||
|
// if(decl.isArray)
|
||||||
|
// decl.arraysize!!.constIndex()
|
||||||
|
// else if(initialStringLit!=null)
|
||||||
|
// initialStringLit.value.length+1 // include the terminating 0-byte
|
||||||
|
// else
|
||||||
|
// null
|
||||||
|
// val bss = if(decl.datatype==DataType.STR)
|
||||||
|
// false
|
||||||
|
// else if(decl.isArray)
|
||||||
|
// initialArray.isNullOrEmpty()
|
||||||
|
// else
|
||||||
|
// initialNumeric == null
|
||||||
|
// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position)
|
||||||
|
// StStaticVariable(decl.name, decl.datatype, bss, initialNumeric, initialString, initialArray, numElements, decl.zeropage, astNode, decl.position)
|
||||||
|
// }
|
||||||
|
// VarDeclType.CONST -> {
|
||||||
|
// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position)
|
||||||
|
// StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, astNode, decl.position)
|
||||||
|
// }
|
||||||
|
// VarDeclType.MEMORY -> {
|
||||||
|
// val numElements =
|
||||||
|
// if(decl.isArray)
|
||||||
|
// decl.arraysize!!.constIndex()
|
||||||
|
// else null
|
||||||
|
// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position)
|
||||||
|
// StMemVar(decl.name, decl.datatype, (decl.value as NumericLiteral).number.toUInt(), numElements, astNode, decl.position)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// scopestack.peek().add(node)
|
||||||
|
// // st.origAstLinks[decl] = node
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun makeInitialArray(arrayLit: ArrayLiteral?): StArray? {
|
||||||
|
// if(arrayLit==null)
|
||||||
|
// return null
|
||||||
|
// return arrayLit.value.map {
|
||||||
|
// when(it){
|
||||||
|
// is AddressOf -> {
|
||||||
|
// val scopedName = it.identifier.targetNameAndType(program).first
|
||||||
|
// StArrayElement(null, scopedName)
|
||||||
|
// }
|
||||||
|
// is IdentifierReference -> {
|
||||||
|
// val scopedName = it.targetNameAndType(program).first
|
||||||
|
// StArrayElement(null, scopedName)
|
||||||
|
// }
|
||||||
|
// is NumericLiteral -> StArrayElement(it.number, null)
|
||||||
|
// else -> throw FatalAstException("weird element dt in array literal")
|
||||||
|
// }
|
||||||
|
// }.toList()
|
||||||
|
// }
|
||||||
|
//
|
@ -1,6 +1,9 @@
|
|||||||
package prog8.code.ast
|
package prog8.code.ast
|
||||||
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.IMemSizer
|
||||||
|
import prog8.code.core.IStringEncoding
|
||||||
|
import prog8.code.core.Position
|
||||||
|
import prog8.code.source.SourceCode
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
// New simplified AST for the code generator.
|
// New simplified AST for the code generator.
|
||||||
@ -11,16 +14,6 @@ sealed class PtNode(val position: Position) {
|
|||||||
val children = mutableListOf<PtNode>()
|
val children = mutableListOf<PtNode>()
|
||||||
lateinit var parent: PtNode
|
lateinit var parent: PtNode
|
||||||
|
|
||||||
fun printIndented(indent: Int) {
|
|
||||||
print(" ".repeat(indent))
|
|
||||||
print("${this.javaClass.simpleName} ")
|
|
||||||
printProperties()
|
|
||||||
println()
|
|
||||||
children.forEach { it.printIndented(indent+1) }
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun printProperties()
|
|
||||||
|
|
||||||
fun add(child: PtNode) {
|
fun add(child: PtNode) {
|
||||||
children.add(child)
|
children.add(child)
|
||||||
child.parent = this
|
child.parent = this
|
||||||
@ -34,25 +27,30 @@ sealed class PtNode(val position: Position) {
|
|||||||
fun definingBlock() = findParentNode<PtBlock>(this)
|
fun definingBlock() = findParentNode<PtBlock>(this)
|
||||||
fun definingSub() = findParentNode<PtSub>(this)
|
fun definingSub() = findParentNode<PtSub>(this)
|
||||||
fun definingAsmSub() = findParentNode<PtAsmSub>(this)
|
fun definingAsmSub() = findParentNode<PtAsmSub>(this)
|
||||||
|
fun definingISub() = findParentNode<IPtSubroutine>(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtNodeGroup : PtNode(Position.DUMMY) {
|
sealed interface IPtStatementContainer
|
||||||
override fun printProperties() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
abstract class PtNamedNode(val name: String, position: Position): PtNode(position) {
|
class PtNodeGroup : PtNode(Position.DUMMY), IPtStatementContainer
|
||||||
val scopedName: List<String> by lazy {
|
|
||||||
var namedParent: PtNode = this.parent
|
|
||||||
if(namedParent is PtProgram)
|
sealed class PtNamedNode(var name: String, position: Position): PtNode(position) {
|
||||||
listOf(name)
|
// Note that as an exception, the 'name' is not read-only
|
||||||
else {
|
// but a var. This is to allow for cheap node renames.
|
||||||
while (namedParent !is PtNamedNode)
|
val scopedName: String
|
||||||
namedParent = namedParent.parent
|
get() {
|
||||||
namedParent.scopedName + name
|
var namedParent: PtNode = this.parent
|
||||||
|
return if(namedParent is PtProgram)
|
||||||
|
name
|
||||||
|
else {
|
||||||
|
while (namedParent !is PtNamedNode)
|
||||||
|
namedParent = namedParent.parent
|
||||||
|
namedParent.scopedName + "." + name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -61,10 +59,6 @@ class PtProgram(
|
|||||||
val memsizer: IMemSizer,
|
val memsizer: IMemSizer,
|
||||||
val encoding: IStringEncoding
|
val encoding: IStringEncoding
|
||||||
) : PtNode(Position.DUMMY) {
|
) : PtNode(Position.DUMMY) {
|
||||||
fun print() = printIndented(0)
|
|
||||||
override fun printProperties() {
|
|
||||||
print("'$name'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// fun allModuleDirectives(): Sequence<PtDirective> =
|
// fun allModuleDirectives(): Sequence<PtDirective> =
|
||||||
// children.asSequence().flatMap { it.children }.filterIsInstance<PtDirective>().distinct()
|
// children.asSequence().flatMap { it.children }.filterIsInstance<PtDirective>().distinct()
|
||||||
@ -73,62 +67,53 @@ class PtProgram(
|
|||||||
children.asSequence().filterIsInstance<PtBlock>()
|
children.asSequence().filterIsInstance<PtBlock>()
|
||||||
|
|
||||||
fun entrypoint(): PtSub? =
|
fun entrypoint(): PtSub? =
|
||||||
allBlocks().firstOrNull { it.name == "main" }?.children?.firstOrNull { it is PtSub && it.name == "start" } as PtSub?
|
// returns the main.start subroutine if it exists
|
||||||
|
allBlocks().firstOrNull { it.name == "main" || it.name=="p8b_main" }
|
||||||
|
?.children
|
||||||
|
?.firstOrNull { it is PtSub && (it.name == "start" || it.name=="main.start" || it.name=="p8s_start" || it.name=="p8b_main.p8s_start") } as PtSub?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtBlock(name: String,
|
class PtBlock(name: String,
|
||||||
val address: UInt?,
|
|
||||||
val library: Boolean,
|
val library: Boolean,
|
||||||
val forceOutput: Boolean,
|
val source: SourceCode, // taken from the module the block is defined in.
|
||||||
val alignment: BlockAlignment,
|
val options: Options,
|
||||||
position: Position
|
position: Position
|
||||||
) : PtNamedNode(name, position) {
|
) : PtNamedNode(name, position), IPtStatementContainer {
|
||||||
override fun printProperties() {
|
class Options(val address: UInt? = null,
|
||||||
print("$name addr=$address library=$library forceOutput=$forceOutput alignment=$alignment")
|
val forceOutput: Boolean = false,
|
||||||
}
|
val noSymbolPrefixing: Boolean = false,
|
||||||
|
val veraFxMuls: Boolean = false,
|
||||||
enum class BlockAlignment {
|
val ignoreUnused: Boolean = false)
|
||||||
NONE,
|
|
||||||
WORD,
|
|
||||||
PAGE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtInlineAssembly(val assembly: String, position: Position) : PtNode(position) {
|
class PtInlineAssembly(val assembly: String, val isIR: Boolean, position: Position) : PtNode(position) {
|
||||||
override fun printProperties() {}
|
init {
|
||||||
|
require(!assembly.startsWith('\n') && !assembly.startsWith('\r')) { "inline assembly should be trimmed" }
|
||||||
|
require(!assembly.endsWith('\n') && !assembly.endsWith('\r')) { "inline assembly should be trimmed" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtLabel(name: String, position: Position) : PtNamedNode(name, position) {
|
class PtLabel(name: String, position: Position) : PtNamedNode(name, position) {
|
||||||
override fun printProperties() {
|
companion object {
|
||||||
print(name)
|
// all automatically generated labels everywhere need to have the same label name prefix:
|
||||||
|
const val GENERATED_LABEL_PREFIX = "p8_label_gen_"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtBreakpoint(position: Position): PtNode(position) {
|
class PtBreakpoint(position: Position): PtNode(position)
|
||||||
override fun printProperties() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PtIncludeBinary(val file: Path, val offset: UInt?, val length: UInt?, position: Position) : PtNode(position) {
|
class PtAlign(val align: UInt, position: Position): PtNode(position)
|
||||||
override fun printProperties() {
|
|
||||||
print("filename=$file offset=$offset length=$length")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PtNop(position: Position): PtNode(position) {
|
class PtIncludeBinary(val file: Path, val offset: UInt?, val length: UInt?, position: Position) : PtNode(position)
|
||||||
override fun printProperties() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PtScopeVarsDecls(position: Position): PtNode(position) {
|
class PtNop(position: Position): PtNode(position)
|
||||||
override fun printProperties() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// find the parent node of a specific type or interface
|
// find the parent node of a specific type or interface
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
package prog8.code.ast
|
package prog8.code.ast
|
||||||
|
|
||||||
import prog8.code.core.DataType
|
import prog8.code.core.*
|
||||||
import prog8.code.core.Encoding
|
|
||||||
import prog8.code.core.Position
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.round
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.truncate
|
||||||
|
|
||||||
|
|
||||||
sealed class PtExpression(val type: DataType, position: Position) : PtNode(position) {
|
sealed class PtExpression(val type: DataType, position: Position) : PtNode(position) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(type==DataType.BOOL)
|
if(type.isUndefined) {
|
||||||
throw IllegalArgumentException("bool should have become ubyte @$position")
|
|
||||||
if(type==DataType.UNDEFINED) {
|
|
||||||
@Suppress("LeakingThis")
|
@Suppress("LeakingThis")
|
||||||
when(this) {
|
when(this) {
|
||||||
is PtBuiltinFunctionCall -> { /* void function call */ }
|
is PtBuiltinFunctionCall -> { /* void function call */ }
|
||||||
@ -23,49 +20,159 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun printProperties() {
|
|
||||||
print(type)
|
|
||||||
}
|
|
||||||
|
|
||||||
infix fun isSameAs(other: PtExpression): Boolean {
|
infix fun isSameAs(other: PtExpression): Boolean {
|
||||||
return when(this) {
|
return when(this) {
|
||||||
is PtAddressOf -> other is PtAddressOf && other.type==type && other.identifier isSameAs identifier
|
is PtAddressOf -> {
|
||||||
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index
|
if(other !is PtAddressOf)
|
||||||
is PtBinaryExpression -> other is PtBinaryExpression && other.left isSameAs left && other.right isSameAs right
|
return false
|
||||||
is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable
|
if (other.type!==type || !(other.identifier isSameAs identifier))
|
||||||
is PtIdentifier -> other is PtIdentifier && other.type==type && other.targetName==targetName
|
return false
|
||||||
is PtMachineRegister -> other is PtMachineRegister && other.type==type && other.register==register
|
if(other.children.size!=children.size)
|
||||||
|
return false
|
||||||
|
if(children.size==1)
|
||||||
|
return true
|
||||||
|
return arrayIndexExpr!! isSameAs other.arrayIndexExpr!!
|
||||||
|
}
|
||||||
|
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index && other.splitWords==splitWords
|
||||||
|
is PtBinaryExpression -> {
|
||||||
|
if(other !is PtBinaryExpression || other.operator!=operator)
|
||||||
|
false
|
||||||
|
else if(operator in AssociativeOperators)
|
||||||
|
(other.left isSameAs left && other.right isSameAs right) || (other.left isSameAs right && other.right isSameAs left)
|
||||||
|
else
|
||||||
|
other.left isSameAs left && other.right isSameAs right
|
||||||
|
}
|
||||||
|
is PtContainmentCheck -> {
|
||||||
|
if(other !is PtContainmentCheck || other.type != type || !(other.needle isSameAs needle))
|
||||||
|
false
|
||||||
|
else {
|
||||||
|
if(haystackHeapVar!=null)
|
||||||
|
other.haystackHeapVar!=null && other.haystackHeapVar!! isSameAs haystackHeapVar!!
|
||||||
|
else if(haystackValues!=null)
|
||||||
|
other.haystackValues!=null && other.haystackValues!! isSameAs haystackValues!!
|
||||||
|
else
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is PtIdentifier -> other is PtIdentifier && other.type==type && other.name==name
|
||||||
|
is PtIrRegister -> other is PtIrRegister && other.type==type && other.register==register
|
||||||
is PtMemoryByte -> other is PtMemoryByte && other.address isSameAs address
|
is PtMemoryByte -> other is PtMemoryByte && other.address isSameAs address
|
||||||
is PtNumber -> other is PtNumber && other.type==type && other.number==number
|
is PtNumber -> other is PtNumber && other.type==type && other.number==number
|
||||||
|
is PtBool -> other is PtBool && other.value==value
|
||||||
is PtPrefix -> other is PtPrefix && other.type==type && other.operator==operator && other.value isSameAs value
|
is PtPrefix -> other is PtPrefix && other.type==type && other.operator==operator && other.value isSameAs value
|
||||||
is PtRange -> other is PtRange && other.type==type && other.from==from && other.to==to && other.step==step
|
is PtRange -> other is PtRange && other.type==type && other.from==from && other.to==to && other.step==step
|
||||||
is PtTypeCast -> other is PtTypeCast && other.type==type && other.value isSameAs value
|
is PtTypeCast -> other is PtTypeCast && other.type==type && other.value isSameAs value
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infix fun isSameAs(target: PtAssignTarget): Boolean = when {
|
||||||
|
target.memory != null && this is PtMemoryByte -> {
|
||||||
|
target.memory!!.address isSameAs this.address
|
||||||
|
}
|
||||||
|
target.identifier != null && this is PtIdentifier -> {
|
||||||
|
this.name == target.identifier!!.name
|
||||||
|
}
|
||||||
|
target.array != null && this is PtArrayIndexer -> {
|
||||||
|
this.variable.name == target.array!!.variable.name && this.index isSameAs target.array!!.index && this.splitWords==target.array!!.splitWords
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun asConstInteger(): Int? = (this as? PtNumber)?.number?.toInt() ?: (this as? PtBool)?.asInt()
|
||||||
|
fun asConstValue(): Double? = (this as? PtNumber)?.number ?: (this as? PtBool)?.asInt()?.toDouble()
|
||||||
|
|
||||||
|
fun isSimple(): Boolean {
|
||||||
|
return when(this) {
|
||||||
|
is PtAddressOf -> this.arrayIndexExpr==null || this.arrayIndexExpr?.isSimple()==true
|
||||||
|
is PtArray -> true
|
||||||
|
is PtArrayIndexer -> index is PtNumber || index is PtIdentifier
|
||||||
|
is PtBinaryExpression -> false
|
||||||
|
is PtBuiltinFunctionCall -> {
|
||||||
|
when (name) {
|
||||||
|
in arrayOf("msb", "lsb", "msw", "lsw", "mkword", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> this.args.all { it.isSimple() }
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is PtContainmentCheck -> false
|
||||||
|
is PtFunctionCall -> false
|
||||||
|
is PtIdentifier -> true
|
||||||
|
is PtIrRegister -> true
|
||||||
|
is PtMemoryByte -> address is PtNumber || address is PtIdentifier
|
||||||
|
is PtBool -> true
|
||||||
|
is PtNumber -> true
|
||||||
|
is PtPrefix -> value.isSimple()
|
||||||
|
is PtRange -> true
|
||||||
|
is PtString -> true
|
||||||
|
is PtTypeCast -> value.isSimple()
|
||||||
|
is PtIfExpression -> condition.isSimple() && truevalue.isSimple() && falsevalue.isSimple()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fun clone(): PtExpression {
|
||||||
|
fun withClonedChildrenFrom(orig: PtExpression, clone: PtExpression): PtExpression {
|
||||||
|
orig.children.forEach { clone.add((it as PtExpression).clone()) }
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
when(this) {
|
||||||
|
is PtAddressOf -> return withClonedChildrenFrom(this, PtAddressOf(position))
|
||||||
|
is PtArray -> return withClonedChildrenFrom(this, PtArray(type, position))
|
||||||
|
is PtArrayIndexer -> return withClonedChildrenFrom(this, PtArrayIndexer(type, position))
|
||||||
|
is PtBinaryExpression -> return withClonedChildrenFrom(this, PtBinaryExpression(operator, type, position))
|
||||||
|
is PtBuiltinFunctionCall -> return withClonedChildrenFrom(this, PtBuiltinFunctionCall(name, void, hasNoSideEffects, type, position))
|
||||||
|
is PtContainmentCheck -> return withClonedChildrenFrom(this, PtContainmentCheck(position))
|
||||||
|
is PtFunctionCall -> return withClonedChildrenFrom(this, PtFunctionCall(name, void, type, position))
|
||||||
|
is PtIdentifier -> return withClonedChildrenFrom(this, PtIdentifier(name, type, position))
|
||||||
|
is PtMachineRegister -> return withClonedChildrenFrom(this, PtMachineRegister(register, type, position))
|
||||||
|
is PtMemoryByte -> return withClonedChildrenFrom(this, PtMemoryByte(position))
|
||||||
|
is PtNumber -> return withClonedChildrenFrom(this, PtNumber(type, number, position))
|
||||||
|
is PtBool -> return withClonedChildrenFrom(this, PtBool(value, position))
|
||||||
|
is PtPrefix -> return withClonedChildrenFrom(this, PtPrefix(operator, type, position))
|
||||||
|
is PtRange -> return withClonedChildrenFrom(this, PtRange(type, position))
|
||||||
|
is PtString -> return withClonedChildrenFrom(this, PtString(value, encoding, position))
|
||||||
|
is PtTypeCast -> return withClonedChildrenFrom(this, PtTypeCast(type, position))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
|
class PtAddressOf(position: Position, val isMsbForSplitArray: Boolean=false) : PtExpression(DataType.forDt(BaseDataType.UWORD), position) {
|
||||||
val identifier: PtIdentifier
|
val identifier: PtIdentifier
|
||||||
get() = children.single() as PtIdentifier
|
get() = children[0] as PtIdentifier
|
||||||
|
val arrayIndexExpr: PtExpression?
|
||||||
|
get() = if(children.size==2) children[1] as PtExpression else null
|
||||||
|
|
||||||
|
val isFromArrayElement: Boolean
|
||||||
|
get() = children.size==2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtArrayIndexer(type: DataType, position: Position): PtExpression(type, position) {
|
class PtArrayIndexer(elementType: DataType, position: Position): PtExpression(elementType, position) {
|
||||||
val variable: PtIdentifier
|
val variable: PtIdentifier
|
||||||
get() = children[0] as PtIdentifier
|
get() = children[0] as PtIdentifier
|
||||||
val index: PtExpression
|
val index: PtExpression
|
||||||
get() = children[1] as PtExpression
|
get() = children[1] as PtExpression
|
||||||
|
val splitWords: Boolean
|
||||||
|
get() = variable.type.isSplitWordArray
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(elementType.isNumericOrBool)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtArray(type: DataType, position: Position): PtExpression(type, position) {
|
class PtArray(type: DataType, position: Position): PtExpression(type, position) {
|
||||||
|
// children are always one of 3 types: PtBool, PtNumber or PtAddressOf.
|
||||||
override fun hashCode(): Int = Objects.hash(children, type)
|
override fun hashCode(): Int = Objects.hash(children, type)
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if(other==null || other !is PtArray)
|
if(other==null || other !is PtArray)
|
||||||
return false
|
return false
|
||||||
return type==other.type && children == other.children
|
return type==other.type && children == other.children
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val size: Int
|
||||||
|
get() = children.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -76,94 +183,139 @@ class PtBuiltinFunctionCall(val name: String,
|
|||||||
position: Position) : PtExpression(type, position) {
|
position: Position) : PtExpression(type, position) {
|
||||||
init {
|
init {
|
||||||
if(!void)
|
if(!void)
|
||||||
require(type!=DataType.UNDEFINED)
|
require(!type.isUndefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
val args: List<PtExpression>
|
val args: List<PtExpression>
|
||||||
get() = children.map { it as PtExpression }
|
get() = children.map { it as PtExpression }
|
||||||
override fun printProperties() {
|
|
||||||
print("$name void=$void noSideFx=$hasNoSideEffects")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtBinaryExpression(val operator: String, type: DataType, position: Position): PtExpression(type, position) {
|
class PtBinaryExpression(val operator: String, type: DataType, position: Position): PtExpression(type, position) {
|
||||||
// note: "and", "or", "xor" do not occur anymore as operators. They've been replaced int the ast by their bitwise versions &, |, ^.
|
|
||||||
val left: PtExpression
|
val left: PtExpression
|
||||||
get() = children[0] as PtExpression
|
get() = children[0] as PtExpression
|
||||||
val right: PtExpression
|
val right: PtExpression
|
||||||
get() = children[1] as PtExpression
|
get() = children[1] as PtExpression
|
||||||
|
|
||||||
override fun printProperties() {
|
init {
|
||||||
print("$operator -> $type")
|
if(operator in ComparisonOperators + LogicalOperators)
|
||||||
|
require(type.isBool)
|
||||||
|
else
|
||||||
|
require(!type.isBool) { "no bool allowed for this operator $operator"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtContainmentCheck(position: Position): PtExpression(DataType.UBYTE, position) {
|
class PtIfExpression(type: DataType, position: Position): PtExpression(type, position) {
|
||||||
val element: PtExpression
|
val condition: PtExpression
|
||||||
get() = children[0] as PtExpression
|
get() = children[0] as PtExpression
|
||||||
val iterable: PtIdentifier
|
val truevalue: PtExpression
|
||||||
get() = children[1] as PtIdentifier
|
get() = children[1] as PtExpression
|
||||||
|
val falsevalue: PtExpression
|
||||||
|
get() = children[2] as PtExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtFunctionCall(val functionName: List<String>,
|
class PtContainmentCheck(position: Position): PtExpression(DataType.forDt(BaseDataType.BOOL), position) {
|
||||||
|
val needle: PtExpression
|
||||||
|
get() = children[0] as PtExpression
|
||||||
|
val haystackHeapVar: PtIdentifier?
|
||||||
|
get() = children[1] as? PtIdentifier
|
||||||
|
val haystackValues: PtArray?
|
||||||
|
get() = children[1] as? PtArray
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val MAX_SIZE_FOR_INLINE_CHECKS_BYTE = 5
|
||||||
|
const val MAX_SIZE_FOR_INLINE_CHECKS_WORD = 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PtFunctionCall(val name: String,
|
||||||
val void: Boolean,
|
val void: Boolean,
|
||||||
type: DataType,
|
type: DataType,
|
||||||
position: Position) : PtExpression(type, position) {
|
position: Position) : PtExpression(type, position) {
|
||||||
init {
|
|
||||||
if(!void)
|
|
||||||
require(type!=DataType.UNDEFINED)
|
|
||||||
}
|
|
||||||
|
|
||||||
val args: List<PtExpression>
|
val args: List<PtExpression>
|
||||||
get() = children.map { it as PtExpression }
|
get() = children.map { it as PtExpression }
|
||||||
override fun printProperties() {
|
|
||||||
print("${functionName.joinToString(".")} void=$void")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PtIdentifier(val ref: List<String>, val targetName: List<String>, type: DataType, position: Position) : PtExpression(type, position) {
|
|
||||||
override fun printProperties() {
|
|
||||||
print("$ref --> $targetName $type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PtMemoryByte(position: Position) : PtExpression(DataType.UBYTE, position) {
|
|
||||||
val address: PtExpression
|
|
||||||
get() = children.single() as PtExpression
|
|
||||||
override fun printProperties() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PtNumber(type: DataType, val number: Double, position: Position) : PtExpression(type, position) {
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(type==DataType.BOOL)
|
if(void) require(type.isUndefined) {
|
||||||
throw IllegalArgumentException("bool should have become ubyte @$position")
|
"void fcall should have undefined datatype"
|
||||||
if(type!=DataType.FLOAT) {
|
|
||||||
val rounded = round(number)
|
|
||||||
if (rounded != number)
|
|
||||||
throw IllegalArgumentException("refused rounding of float to avoid loss of precision @$position")
|
|
||||||
}
|
}
|
||||||
|
// note: non-void calls can have UNDEFINED type: is if they return more than 1 value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PtIdentifier(val name: String, type: DataType, position: Position) : PtExpression(type, position) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "[PtIdentifier:$name $type $position]"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun printProperties() {
|
fun copy() = PtIdentifier(name, type, position)
|
||||||
print("$number ($type)")
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PtMemoryByte(position: Position) : PtExpression(DataType.forDt(BaseDataType.UBYTE), position) {
|
||||||
|
val address: PtExpression
|
||||||
|
get() = children.single() as PtExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.forDt(BaseDataType.BOOL), position) {
|
||||||
|
override fun hashCode(): Int = Objects.hash(type, value)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if(other==null || other !is PtBool)
|
||||||
|
return false
|
||||||
|
return value==other.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString() = "PtBool:$value"
|
||||||
|
|
||||||
|
fun asInt(): Int = if(value) 1 else 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PtNumber(type: BaseDataType, val number: Double, position: Position) : PtExpression(DataType.forDt(type), position) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromBoolean(bool: Boolean, position: Position): PtNumber =
|
||||||
|
PtNumber(BaseDataType.UBYTE, if(bool) 1.0 else 0.0, position)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
if(type==BaseDataType.BOOL)
|
||||||
|
throw IllegalArgumentException("use PtBool instead")
|
||||||
|
if(type!=BaseDataType.FLOAT) {
|
||||||
|
val trunc = truncate(number)
|
||||||
|
if (trunc != number)
|
||||||
|
throw IllegalArgumentException("refused truncating of float to avoid loss of precision @$position")
|
||||||
|
}
|
||||||
|
when(type) {
|
||||||
|
BaseDataType.UBYTE -> require(number in 0.0..255.0)
|
||||||
|
BaseDataType.BYTE -> require(number in -128.0..127.0)
|
||||||
|
BaseDataType.UWORD -> require(number in 0.0..65535.0)
|
||||||
|
BaseDataType.WORD -> require(number in -32728.0..32767.0)
|
||||||
|
BaseDataType.LONG -> require(number in -2147483647.0..2147483647.0)
|
||||||
|
else -> require(type.isNumeric) { "numeric literal type should be numeric: $type" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int = Objects.hash(type, number)
|
override fun hashCode(): Int = Objects.hash(type, number)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if(other==null || other !is PtNumber)
|
return if(other==null || other !is PtNumber)
|
||||||
return false
|
false
|
||||||
return number==other.number
|
else if(!type.isBool && !other.type.isBool)
|
||||||
|
number==other.number
|
||||||
|
else
|
||||||
|
type==other.type && number==other.number
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun compareTo(other: PtNumber): Int = number.compareTo(other.number)
|
operator fun compareTo(other: PtNumber): Int = number.compareTo(other.number)
|
||||||
|
|
||||||
|
override fun toString() = "PtNumber:$type:$number"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -172,12 +324,7 @@ class PtPrefix(val operator: String, type: DataType, position: Position): PtExpr
|
|||||||
get() = children.single() as PtExpression
|
get() = children.single() as PtExpression
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// note: the "not" operator may no longer occur in the ast; not x should have been replaced with x==0
|
require(operator in PrefixOperators) { "invalid prefix operator: $operator" }
|
||||||
require(operator in setOf("+", "-", "~")) { "invalid prefix operator: $operator" }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun printProperties() {
|
|
||||||
print(operator)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,15 +337,36 @@ class PtRange(type: DataType, position: Position) : PtExpression(type, position)
|
|||||||
val step: PtNumber
|
val step: PtNumber
|
||||||
get() = children[2] as PtNumber
|
get() = children[2] as PtNumber
|
||||||
|
|
||||||
override fun printProperties() {}
|
fun toConstantIntegerRange(): IntProgression? {
|
||||||
|
fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression {
|
||||||
|
return when {
|
||||||
|
fromVal == toVal -> fromVal .. toVal
|
||||||
|
fromVal <= toVal -> when {
|
||||||
|
stepVal <= 0 -> IntRange.EMPTY
|
||||||
|
stepVal == 1 -> fromVal..toVal
|
||||||
|
else -> fromVal..toVal step stepVal
|
||||||
|
}
|
||||||
|
else -> when {
|
||||||
|
stepVal >= 0 -> IntRange.EMPTY
|
||||||
|
stepVal == -1 -> fromVal downTo toVal
|
||||||
|
else -> fromVal downTo toVal step abs(stepVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val fromLv = from as? PtNumber
|
||||||
|
val toLv = to as? PtNumber
|
||||||
|
if(fromLv==null || toLv==null)
|
||||||
|
return null
|
||||||
|
val fromVal = fromLv.number.toInt()
|
||||||
|
val toVal = toLv.number.toInt()
|
||||||
|
val stepVal = step.number.toInt()
|
||||||
|
return makeRange(fromVal, toVal, stepVal)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtString(val value: String, val encoding: Encoding, position: Position) : PtExpression(DataType.STR, position) {
|
class PtString(val value: String, val encoding: Encoding, position: Position) : PtExpression(DataType.forDt(BaseDataType.STR), position) {
|
||||||
override fun printProperties() {
|
|
||||||
print("$encoding:\"$value\"")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int = Objects.hash(value, encoding)
|
override fun hashCode(): Int = Objects.hash(value, encoding)
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if(other==null || other !is PtString)
|
if(other==null || other !is PtString)
|
||||||
@ -208,19 +376,11 @@ class PtString(val value: String, val encoding: Encoding, position: Position) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtTypeCast(type: DataType, position: Position) : PtExpression(type, position) {
|
class PtTypeCast(type: BaseDataType, position: Position) : PtExpression(DataType.forDt(type), position) {
|
||||||
val value: PtExpression
|
val value: PtExpression
|
||||||
get() = children.single() as PtExpression
|
get() = children.single() as PtExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// special node that isn't created from compiling user code, but used internally
|
// special node that isn't created from compiling user code, but used internally in the Intermediate Code
|
||||||
class PtMachineRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position) {
|
class PtIrRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position)
|
||||||
override fun printProperties() {
|
|
||||||
print("reg=$register $type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun constValue(expr: PtExpression): Double? = if(expr is PtNumber) expr.number else null
|
|
||||||
fun constIntValue(expr: PtExpression): Int? = if(expr is PtNumber) expr.number.toInt() else null
|
|
||||||
|
208
codeCore/src/prog8/code/ast/AstPrinter.kt
Normal file
208
codeCore/src/prog8/code/ast/AstPrinter.kt
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
package prog8.code.ast
|
||||||
|
|
||||||
|
import prog8.code.core.DataType
|
||||||
|
import prog8.code.core.escape
|
||||||
|
import prog8.code.core.toHex
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces readable text from a [PtNode] (AST node, usually starting with PtProgram as root),
|
||||||
|
* passing it as a String to the specified receiver function.
|
||||||
|
*/
|
||||||
|
fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Unit) {
|
||||||
|
fun type(dt: DataType) = "!${dt}!"
|
||||||
|
fun txt(node: PtNode): String {
|
||||||
|
return when(node) {
|
||||||
|
is PtAlign -> "%align ${node.align}"
|
||||||
|
is PtAssignTarget -> if(node.void) "<void>" else "<target>"
|
||||||
|
is PtAssignment -> "<assign>"
|
||||||
|
is PtAugmentedAssign -> "<inplace-assign> ${node.operator}"
|
||||||
|
is PtBreakpoint -> "%breakpoint"
|
||||||
|
is PtConditionalBranch -> "if_${node.condition.name.lowercase()}"
|
||||||
|
is PtAddressOf -> {
|
||||||
|
if(node.isMsbForSplitArray)
|
||||||
|
"&>"
|
||||||
|
else if(node.isFromArrayElement)
|
||||||
|
"& array-element"
|
||||||
|
else
|
||||||
|
"&"
|
||||||
|
}
|
||||||
|
is PtArray -> {
|
||||||
|
val valuelist = node.children.joinToString(", ") {
|
||||||
|
when (it) {
|
||||||
|
is PtBool -> it.toString()
|
||||||
|
is PtNumber -> it.number.toString()
|
||||||
|
is PtIdentifier -> it.name
|
||||||
|
is PtAddressOf -> "& ${it.identifier.name}"
|
||||||
|
else -> "invalid array element $it"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"array len=${node.children.size} ${type(node.type)} [ $valuelist ]"
|
||||||
|
}
|
||||||
|
is PtArrayIndexer -> "<arrayindexer> ${type(node.type)} ${if(node.splitWords) "[splitwords]" else ""}"
|
||||||
|
is PtBinaryExpression -> "<expr> ${node.operator} ${type(node.type)}"
|
||||||
|
is PtBuiltinFunctionCall -> {
|
||||||
|
val str = if(node.void) "void " else ""
|
||||||
|
str + node.name + "()"
|
||||||
|
}
|
||||||
|
is PtContainmentCheck -> "in"
|
||||||
|
is PtFunctionCall -> {
|
||||||
|
val str = if(node.void) "void " else ""
|
||||||
|
str + node.name + "()"
|
||||||
|
}
|
||||||
|
is PtIdentifier -> "${node.name} ${type(node.type)}"
|
||||||
|
is PtIrRegister -> "IRREG#${node.register} ${type(node.type)}"
|
||||||
|
is PtMemoryByte -> "@()"
|
||||||
|
is PtNumber -> {
|
||||||
|
val numstr = if(node.type.isFloat) node.number.toString() else node.number.toHex()
|
||||||
|
"$numstr ${type(node.type)}"
|
||||||
|
}
|
||||||
|
is PtBool -> node.value.toString()
|
||||||
|
is PtPrefix -> node.operator
|
||||||
|
is PtRange -> "<range>"
|
||||||
|
is PtString -> "\"${node.value.escape()}\""
|
||||||
|
is PtTypeCast -> "as ${node.type}"
|
||||||
|
is PtForLoop -> "for"
|
||||||
|
is PtIfElse -> "ifelse"
|
||||||
|
is PtIncludeBinary -> "%incbin '${node.file}', ${node.offset}, ${node.length}"
|
||||||
|
is PtInlineAssembly -> {
|
||||||
|
if(node.isIR)
|
||||||
|
"%ir {{ ...${node.assembly.length} characters... }}"
|
||||||
|
else
|
||||||
|
"%asm {{ ...${node.assembly.length} characters... }}"
|
||||||
|
}
|
||||||
|
is PtJump -> {
|
||||||
|
"goto ${txt(node.target)}"
|
||||||
|
}
|
||||||
|
is PtAsmSub -> {
|
||||||
|
val params = node.parameters.joinToString(", ") {
|
||||||
|
val register = it.first.registerOrPair
|
||||||
|
val statusflag = it.first.statusflag
|
||||||
|
"${it.second.type} ${it.second.name} @${register ?: statusflag}"
|
||||||
|
}
|
||||||
|
val clobbers = if (node.clobbers.isEmpty()) "" else "clobbers ${node.clobbers}"
|
||||||
|
val returns = if (node.returns.isEmpty()) "" else {
|
||||||
|
"-> ${node.returns.joinToString(", ") {
|
||||||
|
val register = it.first.registerOrPair
|
||||||
|
val statusflag = it.first.statusflag
|
||||||
|
"${it.second} @${register ?: statusflag}"
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
}
|
||||||
|
val str = if (node.inline) "inline " else ""
|
||||||
|
if(node.address == null) {
|
||||||
|
str + "asmsub ${node.name}($params) $clobbers $returns"
|
||||||
|
} else {
|
||||||
|
val bank = if(node.address.constbank!=null) "@bank ${node.address.constbank}"
|
||||||
|
else if(node.address.varbank!=null) "@bank ${node.address.varbank?.name}"
|
||||||
|
else ""
|
||||||
|
str + "extsub $bank ${node.address.address.toHex()} = ${node.name}($params) $clobbers $returns"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is PtBlock -> {
|
||||||
|
val addr = if(node.options.address==null) "" else "@${node.options.address.toHex()}"
|
||||||
|
"\nblock '${node.name}' $addr"
|
||||||
|
}
|
||||||
|
is PtConstant -> {
|
||||||
|
val value = when {
|
||||||
|
node.type.isBool -> if(node.value==0.0) "false" else "true"
|
||||||
|
node.type.isInteger -> node.value.toInt().toString()
|
||||||
|
else -> node.value.toString()
|
||||||
|
}
|
||||||
|
"const ${node.type} ${node.name} = $value"
|
||||||
|
}
|
||||||
|
is PtLabel -> "${node.name}:"
|
||||||
|
is PtMemMapped -> {
|
||||||
|
if(node.type.isArray) {
|
||||||
|
val arraysize = if(node.arraySize==null) "" else node.arraySize.toString()
|
||||||
|
"&${node.type.elementType()}[$arraysize] ${node.name} = ${node.address.toHex()}"
|
||||||
|
} else {
|
||||||
|
"&${node.type} ${node.name} = ${node.address.toHex()}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is PtSub -> {
|
||||||
|
val params = node.parameters.joinToString(", ") {
|
||||||
|
val reg = if(it.register!=null) "@${it.register}" else ""
|
||||||
|
"${it.type} ${it.name} $reg"
|
||||||
|
}
|
||||||
|
var str = "sub ${node.name}($params) "
|
||||||
|
if(node.returntype!=null)
|
||||||
|
str += "-> ${node.returntype}"
|
||||||
|
str
|
||||||
|
}
|
||||||
|
is PtVariable -> {
|
||||||
|
val split = if(node.type.isSplitWordArray) "" else "@nosplit"
|
||||||
|
val align = when(node.align) {
|
||||||
|
0u -> ""
|
||||||
|
2u -> "@alignword"
|
||||||
|
64u -> "@align64"
|
||||||
|
256u -> "@alignpage"
|
||||||
|
else -> throw IllegalArgumentException("invalid alignment size")
|
||||||
|
}
|
||||||
|
val str = if(node.arraySize!=null) {
|
||||||
|
val eltType = node.type.elementType()
|
||||||
|
"${eltType}[${node.arraySize}] $split $align ${node.name}"
|
||||||
|
}
|
||||||
|
else if(node.type.isArray) {
|
||||||
|
val eltType = node.type.elementType()
|
||||||
|
"${eltType}[] $split $align ${node.name}"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
"${node.type} ${node.name}"
|
||||||
|
if(node.value!=null)
|
||||||
|
str + " = " + txt(node.value)
|
||||||
|
else
|
||||||
|
str
|
||||||
|
}
|
||||||
|
is PtNodeGroup -> if(node.children.isNotEmpty()) "<group>" else ""
|
||||||
|
is PtNop -> "nop"
|
||||||
|
is PtProgram -> "PROGRAM ${node.name}"
|
||||||
|
is PtRepeatLoop -> "repeat"
|
||||||
|
is PtReturn -> "return"
|
||||||
|
is PtSubroutineParameter -> {
|
||||||
|
val reg = if(node.register!=null) "@${node.register}" else ""
|
||||||
|
"${node.type} ${node.name} $reg"
|
||||||
|
}
|
||||||
|
is PtWhen -> "when"
|
||||||
|
is PtWhenChoice -> {
|
||||||
|
if(node.isElse)
|
||||||
|
"else"
|
||||||
|
else
|
||||||
|
"->"
|
||||||
|
}
|
||||||
|
is PtDefer -> "<defer>"
|
||||||
|
is PtIfExpression -> "<ifexpr>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(root is PtProgram) {
|
||||||
|
output(txt(root))
|
||||||
|
root.children.forEach {
|
||||||
|
walkAst(it) { node, depth ->
|
||||||
|
val txt = txt(node)
|
||||||
|
val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true
|
||||||
|
if(!library || !skipLibraries) {
|
||||||
|
if (txt.isNotEmpty())
|
||||||
|
output(" ".repeat(depth) + txt(node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
} else {
|
||||||
|
walkAst(root) { node, depth ->
|
||||||
|
val txt = txt(node)
|
||||||
|
val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true
|
||||||
|
if(!library || !skipLibraries) {
|
||||||
|
if (txt.isNotEmpty())
|
||||||
|
output(" ".repeat(depth) + txt(node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun walkAst(root: PtNode, act: (node: PtNode, depth: Int) -> Unit) {
|
||||||
|
fun recurse(node: PtNode, depth: Int) {
|
||||||
|
act(node, depth)
|
||||||
|
node.children.forEach { recurse(it, depth+1) }
|
||||||
|
}
|
||||||
|
recurse(root, 0)
|
||||||
|
}
|
@ -3,19 +3,22 @@ package prog8.code.ast
|
|||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
|
||||||
|
|
||||||
|
sealed interface IPtSubroutine {
|
||||||
|
val name: String
|
||||||
|
val scopedName: String
|
||||||
|
}
|
||||||
|
|
||||||
class PtAsmSub(
|
class PtAsmSub(
|
||||||
name: String,
|
name: String,
|
||||||
val address: UInt?,
|
val address: Address?,
|
||||||
val clobbers: Set<CpuRegister>,
|
val clobbers: Set<CpuRegister>,
|
||||||
val parameters: List<Pair<PtSubroutineParameter, RegisterOrStatusflag>>,
|
val parameters: List<Pair<RegisterOrStatusflag, PtSubroutineParameter>>,
|
||||||
val returnTypes: List<DataType>, // TODO join with register as Pairs ?
|
val returns: List<Pair<RegisterOrStatusflag, DataType>>,
|
||||||
val retvalRegisters: List<RegisterOrStatusflag>,
|
|
||||||
val inline: Boolean,
|
val inline: Boolean,
|
||||||
position: Position
|
position: Position
|
||||||
) : PtNamedNode(name, position) {
|
) : PtNamedNode(name, position), IPtSubroutine {
|
||||||
override fun printProperties() {
|
|
||||||
print("$name inline=$inline")
|
class Address(val constbank: UByte?, var varbank: PtIdentifier?, val address: UInt)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -23,68 +26,45 @@ class PtSub(
|
|||||||
name: String,
|
name: String,
|
||||||
val parameters: List<PtSubroutineParameter>,
|
val parameters: List<PtSubroutineParameter>,
|
||||||
val returntype: DataType?,
|
val returntype: DataType?,
|
||||||
val inline: Boolean,
|
|
||||||
position: Position
|
position: Position
|
||||||
) : PtNamedNode(name, position) {
|
) : PtNamedNode(name, position), IPtSubroutine, IPtStatementContainer {
|
||||||
override fun printProperties() {
|
|
||||||
print(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// params and return value should not be str
|
// params and return value should not be str
|
||||||
if(parameters.any{ it.type !in NumericDatatypes })
|
if(parameters.any{ !it.type.isNumericOrBool })
|
||||||
throw AssemblyError("non-numeric parameter")
|
throw AssemblyError("non-numeric/non-bool parameter")
|
||||||
if(returntype!=null && returntype !in NumericDatatypes)
|
if(returntype!=null && !returntype.isNumericOrBool)
|
||||||
throw AssemblyError("non-numeric returntype $returntype")
|
throw AssemblyError("non-numeric/non-bool returntype $returntype")
|
||||||
|
parameters.forEach { it.parent=this }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtSubroutineParameter(val name: String, val type: DataType, position: Position): PtNode(position) {
|
class PtSubroutineParameter(name: String, val type: DataType, val register: RegisterOrPair?, position: Position): PtNamedNode(name, position)
|
||||||
override fun printProperties() {
|
|
||||||
print("$type $name")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PtAssignment(position: Position) : PtNode(position) {
|
sealed interface IPtAssignment {
|
||||||
|
val children: MutableList<PtNode>
|
||||||
val target: PtAssignTarget
|
val target: PtAssignTarget
|
||||||
get() = children[0] as PtAssignTarget
|
get() {
|
||||||
val value: PtExpression
|
if(children.size==2)
|
||||||
get() = children[1] as PtExpression
|
return children[0] as PtAssignTarget
|
||||||
|
else if(children.size<2)
|
||||||
override fun printProperties() { }
|
throw AssemblyError("incomplete node")
|
||||||
|
else
|
||||||
val isInplaceAssign: Boolean by lazy {
|
throw AssemblyError("no singular target")
|
||||||
val target = target.children.single() as PtExpression
|
|
||||||
when(val source = value) {
|
|
||||||
is PtArrayIndexer -> {
|
|
||||||
if(target is PtArrayIndexer && source.type==target.type) {
|
|
||||||
if(target.variable isSameAs source.variable) {
|
|
||||||
target.index isSameAs source.index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
is PtIdentifier -> target is PtIdentifier && target.type==source.type && target.targetName==source.targetName
|
|
||||||
is PtMachineRegister -> target is PtMachineRegister && target.register==source.register
|
|
||||||
is PtMemoryByte -> target is PtMemoryByte && target.address isSameAs source.address
|
|
||||||
is PtNumber -> target is PtNumber && target.type == source.type && target.number==source.number
|
|
||||||
is PtAddressOf -> target is PtAddressOf && target.identifier isSameAs source.identifier
|
|
||||||
is PtPrefix -> {
|
|
||||||
(target is PtPrefix && target.operator==source.operator && target.value isSameAs source.value)
|
|
||||||
||
|
|
||||||
(target is PtIdentifier && (source.value as? PtIdentifier)?.targetName==target.targetName)
|
|
||||||
}
|
|
||||||
is PtTypeCast -> target is PtTypeCast && target.type==source.type && target.value isSameAs source.value
|
|
||||||
is PtBinaryExpression ->
|
|
||||||
target isSameAs source.left
|
|
||||||
else -> false
|
|
||||||
}
|
}
|
||||||
}
|
val value: PtExpression
|
||||||
|
get() = children.last() as PtExpression
|
||||||
|
val multiTarget: Boolean
|
||||||
|
get() = children.size>2
|
||||||
}
|
}
|
||||||
|
|
||||||
class PtAssignTarget(position: Position) : PtNode(position) {
|
class PtAssignment(position: Position) : PtNode(position), IPtAssignment
|
||||||
|
|
||||||
|
class PtAugmentedAssign(val operator: String, position: Position) : PtNode(position), IPtAssignment
|
||||||
|
|
||||||
|
|
||||||
|
class PtAssignTarget(val void: Boolean, position: Position) : PtNode(position) {
|
||||||
val identifier: PtIdentifier?
|
val identifier: PtIdentifier?
|
||||||
get() = children.single() as? PtIdentifier
|
get() = children.single() as? PtIdentifier
|
||||||
val array: PtArrayIndexer?
|
val array: PtArrayIndexer?
|
||||||
@ -102,7 +82,7 @@ class PtAssignTarget(position: Position) : PtNode(position) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun printProperties() {}
|
infix fun isSameAs(expression: PtExpression): Boolean = !void && expression.isSameAs(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -111,10 +91,6 @@ class PtConditionalBranch(val condition: BranchCondition, position: Position) :
|
|||||||
get() = children[0] as PtNodeGroup
|
get() = children[0] as PtNodeGroup
|
||||||
val falseScope: PtNodeGroup
|
val falseScope: PtNodeGroup
|
||||||
get() = children[1] as PtNodeGroup
|
get() = children[1] as PtNodeGroup
|
||||||
|
|
||||||
override fun printProperties() {
|
|
||||||
print(condition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -125,42 +101,24 @@ class PtForLoop(position: Position) : PtNode(position) {
|
|||||||
get() = children[1] as PtExpression
|
get() = children[1] as PtExpression
|
||||||
val statements: PtNodeGroup
|
val statements: PtNodeGroup
|
||||||
get() = children[2] as PtNodeGroup
|
get() = children[2] as PtNodeGroup
|
||||||
|
|
||||||
override fun printProperties() {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtIfElse(position: Position) : PtNode(position) {
|
class PtIfElse(position: Position) : PtNode(position) {
|
||||||
val condition: PtBinaryExpression
|
val condition: PtExpression
|
||||||
get() = children[0] as PtBinaryExpression
|
get() = children[0] as PtExpression
|
||||||
val ifScope: PtNodeGroup
|
val ifScope: PtNodeGroup
|
||||||
get() = children[1] as PtNodeGroup
|
get() = children[1] as PtNodeGroup
|
||||||
val elseScope: PtNodeGroup
|
val elseScope: PtNodeGroup
|
||||||
get() = children[2] as PtNodeGroup
|
get() = children[2] as PtNodeGroup
|
||||||
|
|
||||||
override fun printProperties() {}
|
fun hasElse(): Boolean = children.size==3 && elseScope.children.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtJump(val identifier: PtIdentifier?,
|
class PtJump(position: Position) : PtNode(position) {
|
||||||
val address: UInt?,
|
val target: PtExpression
|
||||||
val generatedLabel: String?,
|
get() = children.single() as PtExpression
|
||||||
position: Position) : PtNode(position) {
|
|
||||||
override fun printProperties() {
|
|
||||||
identifier?.printProperties()
|
|
||||||
if(address!=null) print(address.toHex())
|
|
||||||
if(generatedLabel!=null) print(generatedLabel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PtPostIncrDecr(val operator: String, position: Position) : PtNode(position) {
|
|
||||||
val target: PtAssignTarget
|
|
||||||
get() = children.single() as PtAssignTarget
|
|
||||||
|
|
||||||
override fun printProperties() {
|
|
||||||
print(operator)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -169,13 +127,12 @@ class PtRepeatLoop(position: Position) : PtNode(position) {
|
|||||||
get() = children[0] as PtExpression
|
get() = children[0] as PtExpression
|
||||||
val statements: PtNodeGroup
|
val statements: PtNodeGroup
|
||||||
get() = children[1] as PtNodeGroup
|
get() = children[1] as PtNodeGroup
|
||||||
|
|
||||||
override fun printProperties() {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtReturn(position: Position) : PtNode(position) {
|
class PtReturn(position: Position) : PtNode(position) {
|
||||||
val hasValue = children.any()
|
val hasValue: Boolean
|
||||||
|
get() = children.any()
|
||||||
val value: PtExpression?
|
val value: PtExpression?
|
||||||
get() {
|
get() {
|
||||||
return if(children.any())
|
return if(children.any())
|
||||||
@ -183,28 +140,36 @@ class PtReturn(position: Position) : PtNode(position) {
|
|||||||
else
|
else
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun printProperties() {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtVariable(name: String, val type: DataType, var value: PtExpression?, var arraySize: UInt?, position: Position) : PtNamedNode(name, position) {
|
sealed interface IPtVariable {
|
||||||
override fun printProperties() {
|
val name: String
|
||||||
print("$type $name")
|
val type: DataType
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PtVariable(
|
||||||
|
name: String,
|
||||||
|
override val type: DataType,
|
||||||
|
val zeropage: ZeropageWish,
|
||||||
|
val align: UInt,
|
||||||
|
val value: PtExpression?,
|
||||||
|
val arraySize: UInt?,
|
||||||
|
position: Position
|
||||||
|
) : PtNamedNode(name, position), IPtVariable {
|
||||||
|
init {
|
||||||
|
value?.let {it.parent=this}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtConstant(name: String, val type: DataType, val value: Double, position: Position) : PtNamedNode(name, position) {
|
class PtConstant(name: String, override val type: DataType, val value: Double, position: Position) : PtNamedNode(name, position), IPtVariable
|
||||||
override fun printProperties() {
|
|
||||||
print("$type $name = $value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PtMemMapped(name: String, val type: DataType, val address: UInt, position: Position) : PtNamedNode(name, position) {
|
class PtMemMapped(name: String, override val type: DataType, val address: UInt, val arraySize: UInt?, position: Position) : PtNamedNode(name, position), IPtVariable {
|
||||||
override fun printProperties() {
|
init {
|
||||||
print("&$type $name = ${address.toHex()}")
|
require(!type.isString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,8 +179,6 @@ class PtWhen(position: Position) : PtNode(position) {
|
|||||||
get() = children[0] as PtExpression
|
get() = children[0] as PtExpression
|
||||||
val choices: PtNodeGroup
|
val choices: PtNodeGroup
|
||||||
get() = children[1] as PtNodeGroup
|
get() = children[1] as PtNodeGroup
|
||||||
|
|
||||||
override fun printProperties() {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -224,5 +187,7 @@ class PtWhenChoice(val isElse: Boolean, position: Position) : PtNode(position) {
|
|||||||
get() = children[0] as PtNodeGroup
|
get() = children[0] as PtNodeGroup
|
||||||
val statements: PtNodeGroup
|
val statements: PtNodeGroup
|
||||||
get() = children[1] as PtNodeGroup
|
get() = children[1] as PtNodeGroup
|
||||||
override fun printProperties() {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PtDefer(position: Position): PtNode(position), IPtStatementContainer
|
||||||
|
16
codeCore/src/prog8/code/ast/Verify.kt
Normal file
16
codeCore/src/prog8/code/ast/Verify.kt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package prog8.code.ast
|
||||||
|
|
||||||
|
import prog8.code.SymbolTable
|
||||||
|
import prog8.code.core.*
|
||||||
|
|
||||||
|
fun verifyFinalAstBeforeAsmGen(program: PtProgram, options: CompilationOptions, st: SymbolTable, errors: IErrorReporter) {
|
||||||
|
/*
|
||||||
|
walkAst(program) { node, _ ->
|
||||||
|
if(node is PtVariable) {
|
||||||
|
if(node.value!=null) {
|
||||||
|
// require(node.type in ArrayDatatypes || node.type==DataType.STR) { "final check before asmgen: only string and array variables can still have an init value ${node.name} ${node.type} ${node.position}"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
156
codeCore/src/prog8/code/core/BuiltinFunctions.kt
Normal file
156
codeCore/src/prog8/code/core/BuiltinFunctions.kt
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package prog8.code.core
|
||||||
|
|
||||||
|
class ReturnConvention(val dt: BaseDataType?, val reg: RegisterOrPair?)
|
||||||
|
class ParamConvention(val dt: BaseDataType, val reg: RegisterOrPair?, val variable: Boolean)
|
||||||
|
class CallConvention(val params: List<ParamConvention>, val returns: ReturnConvention) {
|
||||||
|
override fun toString(): String {
|
||||||
|
val paramConvs = params.mapIndexed { index, it ->
|
||||||
|
when {
|
||||||
|
it.reg!=null -> "$index:${it.reg}"
|
||||||
|
it.variable -> "$index:variable"
|
||||||
|
else -> "$index:???"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val returnConv =
|
||||||
|
when {
|
||||||
|
returns.reg == RegisterOrPair.FAC1 -> "floatFAC1"
|
||||||
|
returns.reg != null -> returns.reg.toString()
|
||||||
|
else -> "<no returnvalue>"
|
||||||
|
}
|
||||||
|
return "CallConvention[" + paramConvs.joinToString() + " ; returns: $returnConv]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FParam(val name: String, vararg val possibleDatatypes: BaseDataType)
|
||||||
|
|
||||||
|
|
||||||
|
private val IterableDatatypes = arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
|
||||||
|
private val IntegerDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)
|
||||||
|
private val NumericDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||||
|
private val ByteDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE)
|
||||||
|
private val ArrayDatatypes = arrayOf(BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
|
||||||
|
|
||||||
|
|
||||||
|
class FSignature(val pure: Boolean, // does it have side effects?
|
||||||
|
val returnType: BaseDataType?,
|
||||||
|
vararg val parameters: FParam) {
|
||||||
|
|
||||||
|
fun callConvention(actualParamTypes: List<BaseDataType>): CallConvention {
|
||||||
|
val returns: ReturnConvention = when (returnType) {
|
||||||
|
BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A)
|
||||||
|
BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY)
|
||||||
|
BaseDataType.FLOAT -> ReturnConvention(returnType, RegisterOrPair.FAC1)
|
||||||
|
in IterableDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY)
|
||||||
|
null -> ReturnConvention(null, null)
|
||||||
|
else -> {
|
||||||
|
// return type depends on arg type
|
||||||
|
when (val paramType = actualParamTypes.first()) {
|
||||||
|
BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A)
|
||||||
|
BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY)
|
||||||
|
BaseDataType.FLOAT -> ReturnConvention(paramType, RegisterOrPair.FAC1)
|
||||||
|
in IterableDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY)
|
||||||
|
else -> ReturnConvention(paramType, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return when {
|
||||||
|
actualParamTypes.isEmpty() -> CallConvention(emptyList(), returns)
|
||||||
|
actualParamTypes.size==1 -> {
|
||||||
|
// One parameter goes via register/registerpair.
|
||||||
|
// this avoids repeated code for every caller to store the value in the subroutine's argument variable.
|
||||||
|
// (that store is still done, but only coded once at the start at the subroutine itself rather than at every call site).
|
||||||
|
val paramConv = when(val paramType = actualParamTypes[0]) {
|
||||||
|
BaseDataType.UBYTE, BaseDataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
|
||||||
|
BaseDataType.UWORD, BaseDataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
|
||||||
|
BaseDataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) // NOTE: for builtin functions, floating point arguments are passed by reference (so you get a pointer in AY)
|
||||||
|
in IterableDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false)
|
||||||
|
else -> ParamConvention(paramType, null, false)
|
||||||
|
}
|
||||||
|
CallConvention(listOf(paramConv), returns)
|
||||||
|
}
|
||||||
|
actualParamTypes.size==2 && (actualParamTypes[0] in ByteDatatypes && actualParamTypes[1].isWord) -> {
|
||||||
|
TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet")
|
||||||
|
}
|
||||||
|
actualParamTypes.size==2 && (actualParamTypes[0].isWord && actualParamTypes[1].isByte) -> {
|
||||||
|
TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet")
|
||||||
|
}
|
||||||
|
actualParamTypes.size==3 && actualParamTypes.all { it.isByte } -> {
|
||||||
|
TODO("opportunity to pass 3 byte arguments in A,Y and X registers but not implemented yet")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// multiple parameters go via variables
|
||||||
|
val paramConvs = actualParamTypes.map { ParamConvention(it, null, true) }
|
||||||
|
CallConvention(paramConvs, returns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val BuiltinFunctions: Map<String, FSignature> = mapOf(
|
||||||
|
"setlsb" to FSignature(false, null, FParam("variable", BaseDataType.WORD, BaseDataType.UWORD), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
|
||||||
|
"setmsb" to FSignature(false, null, FParam("variable", BaseDataType.WORD, BaseDataType.UWORD), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
|
||||||
|
"rol" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||||
|
"ror" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||||
|
"rol2" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||||
|
"ror2" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||||
|
"cmp" to FSignature(false, null, FParam("value1", *IntegerDatatypes), FParam("value2", *NumericDatatypes)), // cmp returns a status in the carry flag, but not a proper return value
|
||||||
|
"prog8_lib_stringcompare" to FSignature(true, BaseDataType.BYTE, FParam("str1", BaseDataType.STR), FParam("str2", BaseDataType.STR)),
|
||||||
|
"prog8_lib_square_byte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
|
||||||
|
"prog8_lib_square_word" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.WORD, BaseDataType.UWORD)),
|
||||||
|
"prog8_ifelse_bittest_set" to FSignature(true, BaseDataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", BaseDataType.UBYTE)),
|
||||||
|
"prog8_ifelse_bittest_notset" to FSignature(true, BaseDataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", BaseDataType.UBYTE)),
|
||||||
|
"abs" to FSignature(true, null, FParam("value", *NumericDatatypes)),
|
||||||
|
"abs__byte" to FSignature(true, BaseDataType.BYTE, FParam("value", BaseDataType.BYTE)),
|
||||||
|
"abs__word" to FSignature(true, BaseDataType.WORD, FParam("value", BaseDataType.WORD)),
|
||||||
|
"abs__float" to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)),
|
||||||
|
"len" to FSignature(true, BaseDataType.UWORD, FParam("values", *IterableDatatypes)),
|
||||||
|
"sizeof" to FSignature(true, BaseDataType.UBYTE, FParam("object", *BaseDataType.entries.toTypedArray())),
|
||||||
|
"sgn" to FSignature(true, BaseDataType.BYTE, FParam("value", *NumericDatatypes)),
|
||||||
|
"sqrt" to FSignature(true, null, FParam("value", *NumericDatatypes)),
|
||||||
|
"sqrt__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE)),
|
||||||
|
"sqrt__uword" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD)),
|
||||||
|
"sqrt__float" to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)),
|
||||||
|
"divmod" to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("divisor", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("quotient", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("remainder", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||||
|
"divmod__ubyte" to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE), FParam("divisor", BaseDataType.UBYTE), FParam("quotient", BaseDataType.UBYTE), FParam("remainder", BaseDataType.UBYTE)),
|
||||||
|
"divmod__uword" to FSignature(false, null, FParam("dividend", BaseDataType.UWORD), FParam("divisor", BaseDataType.UWORD), FParam("quotient", BaseDataType.UWORD), FParam("remainder", BaseDataType.UWORD)),
|
||||||
|
"lsb" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||||
|
"lsw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||||
|
"msb" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||||
|
"msw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||||
|
"mkword" to FSignature(true, BaseDataType.UWORD, FParam("msb", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)),
|
||||||
|
"clamp" to FSignature(true, null, FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)),
|
||||||
|
"clamp__byte" to FSignature(true, BaseDataType.BYTE, FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)),
|
||||||
|
"clamp__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE), FParam("minimum", BaseDataType.UBYTE), FParam("maximum", BaseDataType.UBYTE)),
|
||||||
|
"clamp__word" to FSignature(true, BaseDataType.WORD, FParam("value", BaseDataType.WORD), FParam("minimum", BaseDataType.WORD), FParam("maximum", BaseDataType.WORD)),
|
||||||
|
"clamp__uword" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD), FParam("minimum", BaseDataType.UWORD), FParam("maximum", BaseDataType.UWORD)),
|
||||||
|
"min" to FSignature(true, null, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||||
|
"min__byte" to FSignature(true, BaseDataType.BYTE, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||||
|
"min__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)),
|
||||||
|
"min__word" to FSignature(true, BaseDataType.WORD, FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)),
|
||||||
|
"min__uword" to FSignature(true, BaseDataType.UWORD, FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)),
|
||||||
|
"max" to FSignature(true, null, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||||
|
"max__byte" to FSignature(true, BaseDataType.BYTE, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||||
|
"max__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)),
|
||||||
|
"max__word" to FSignature(true, BaseDataType.WORD, FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)),
|
||||||
|
"max__uword" to FSignature(true, BaseDataType.UWORD, FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)),
|
||||||
|
"peek" to FSignature(true, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD)),
|
||||||
|
"peekw" to FSignature(true, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)),
|
||||||
|
"peekf" to FSignature(true, BaseDataType.FLOAT, FParam("address", BaseDataType.UWORD)),
|
||||||
|
"poke" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)),
|
||||||
|
"pokew" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UWORD)),
|
||||||
|
"pokef" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.FLOAT)),
|
||||||
|
"pokemon" to FSignature(false, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)),
|
||||||
|
"rsave" to FSignature(false, null),
|
||||||
|
"rrestore" to FSignature(false, null),
|
||||||
|
"memory" to FSignature(true, BaseDataType.UWORD, FParam("name", BaseDataType.STR), FParam("size", BaseDataType.UWORD), FParam("alignment", BaseDataType.UWORD)),
|
||||||
|
"callfar" to FSignature(false, BaseDataType.UWORD, FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD), FParam("arg", BaseDataType.UWORD)),
|
||||||
|
"callfar2" to FSignature(false, BaseDataType.UWORD, FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD), FParam("argA", BaseDataType.UBYTE), FParam("argX", BaseDataType.UBYTE), FParam("argY", BaseDataType.UBYTE), FParam("argC", BaseDataType.BOOL)),
|
||||||
|
"call" to FSignature(false, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)),
|
||||||
|
)
|
||||||
|
|
||||||
|
val InplaceModifyingBuiltinFunctions = setOf(
|
||||||
|
"setlsb", "setmsb",
|
||||||
|
"rol", "ror", "rol2", "ror2",
|
||||||
|
"divmod", "divmod__ubyte", "divmod__uword"
|
||||||
|
)
|
@ -8,20 +8,36 @@ class CompilationOptions(val output: OutputType,
|
|||||||
val launcher: CbmPrgLauncherType,
|
val launcher: CbmPrgLauncherType,
|
||||||
val zeropage: ZeropageType,
|
val zeropage: ZeropageType,
|
||||||
val zpReserved: List<UIntRange>,
|
val zpReserved: List<UIntRange>,
|
||||||
|
val zpAllowed: List<UIntRange>,
|
||||||
val floats: Boolean,
|
val floats: Boolean,
|
||||||
val noSysInit: Boolean,
|
val noSysInit: Boolean,
|
||||||
val compTarget: ICompilationTarget,
|
val compTarget: ICompilationTarget,
|
||||||
// these are set later, based on command line arguments or options in the source code:
|
// these are set later, based on command line arguments or options in the source code:
|
||||||
var loadAddress: UInt,
|
var loadAddress: UInt,
|
||||||
var slowCodegenWarnings: Boolean = false,
|
var memtopAddress: UInt,
|
||||||
|
var warnSymbolShadowing: Boolean = false,
|
||||||
var optimize: Boolean = false,
|
var optimize: Boolean = false,
|
||||||
var optimizeFloatExpressions: Boolean = false,
|
|
||||||
var dontReinitGlobals: Boolean = false,
|
|
||||||
var asmQuiet: Boolean = false,
|
var asmQuiet: Boolean = false,
|
||||||
var asmListfile: Boolean = false,
|
var asmListfile: Boolean = false,
|
||||||
|
var includeSourcelines: Boolean = false,
|
||||||
|
var dumpVariables: Boolean = false,
|
||||||
|
var dumpSymbols: Boolean = false,
|
||||||
var experimentalCodegen: Boolean = false,
|
var experimentalCodegen: Boolean = false,
|
||||||
var keepIR: Boolean = false,
|
var varsHighBank: Int? = null,
|
||||||
var evalStackBaseAddress: UInt? = null,
|
var varsGolden: Boolean = false,
|
||||||
|
var slabsHighBank: Int? = null,
|
||||||
|
var slabsGolden: Boolean = false,
|
||||||
|
var dontSplitWordArrays: Boolean = false,
|
||||||
|
var breakpointCpuInstruction: String? = null,
|
||||||
|
var ignoreFootguns: Boolean = false,
|
||||||
var outputDir: Path = Path(""),
|
var outputDir: Path = Path(""),
|
||||||
var symbolDefs: Map<String, String> = emptyMap()
|
var symbolDefs: Map<String, String> = emptyMap()
|
||||||
)
|
) {
|
||||||
|
init {
|
||||||
|
compTarget.machine.initializeMemoryAreas(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val AllZeropageAllowed: List<UIntRange> = listOf(0u..255u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
package prog8.code.core
|
package prog8.code.core
|
||||||
|
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
val powersOfTwoFloat = (0..16).map { (2.0).pow(it) }.toTypedArray()
|
||||||
|
val negativePowersOfTwoFloat = powersOfTwoFloat.map { -it }.toTypedArray()
|
||||||
|
val powersOfTwoInt = (0..16).map { 2.0.pow(it).toInt() }.toTypedArray()
|
||||||
|
|
||||||
fun Number.toHex(): String {
|
fun Number.toHex(): String {
|
||||||
// 0..15 -> "0".."15"
|
// 0..15 -> "0".."15"
|
||||||
// 16..255 -> "$10".."$ff"
|
// 16..255 -> "$10".."$ff"
|
||||||
// 256..65536 -> "$0100".."$ffff"
|
// 256..65536 -> "$0100".."$ffff"
|
||||||
|
// larger -> "$12345678"
|
||||||
// negative values are prefixed with '-'.
|
// negative values are prefixed with '-'.
|
||||||
val integer = this.toInt()
|
val integer = this.toInt()
|
||||||
if(integer<0)
|
if(integer<0)
|
||||||
@ -14,7 +20,7 @@ fun Number.toHex(): String {
|
|||||||
in 0 until 16 -> integer.toString()
|
in 0 until 16 -> integer.toString()
|
||||||
in 0 until 0x100 -> "$"+integer.toString(16).padStart(2,'0')
|
in 0 until 0x100 -> "$"+integer.toString(16).padStart(2,'0')
|
||||||
in 0 until 0x10000 -> "$"+integer.toString(16).padStart(4,'0')
|
in 0 until 0x10000 -> "$"+integer.toString(16).padStart(4,'0')
|
||||||
else -> throw IllegalArgumentException("number too large for 16 bits $this")
|
else -> "$"+integer.toString(16).padStart(8,'0')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,11 +28,12 @@ fun UInt.toHex(): String {
|
|||||||
// 0..15 -> "0".."15"
|
// 0..15 -> "0".."15"
|
||||||
// 16..255 -> "$10".."$ff"
|
// 16..255 -> "$10".."$ff"
|
||||||
// 256..65536 -> "$0100".."$ffff"
|
// 256..65536 -> "$0100".."$ffff"
|
||||||
|
// larger -> "$12345678"
|
||||||
return when (this) {
|
return when (this) {
|
||||||
in 0u until 16u -> this.toString()
|
in 0u until 16u -> this.toString()
|
||||||
in 0u until 0x100u -> "$"+this.toString(16).padStart(2,'0')
|
in 0u until 0x100u -> "$"+this.toString(16).padStart(2,'0')
|
||||||
in 0u until 0x10000u -> "$"+this.toString(16).padStart(4,'0')
|
in 0u until 0x10000u -> "$"+this.toString(16).padStart(4,'0')
|
||||||
else -> throw IllegalArgumentException("number too large for 16 bits $this")
|
else -> "$"+this.toString(16).padStart(8,'0')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +65,7 @@ fun String.unescape(): String {
|
|||||||
'\\' -> '\\'
|
'\\' -> '\\'
|
||||||
'n' -> '\n'
|
'n' -> '\n'
|
||||||
'r' -> '\r'
|
'r' -> '\r'
|
||||||
|
't' -> '\t'
|
||||||
'"' -> '"'
|
'"' -> '"'
|
||||||
'\'' -> '\''
|
'\'' -> '\''
|
||||||
'u' -> {
|
'u' -> {
|
||||||
|
@ -1,58 +1,255 @@
|
|||||||
package prog8.code.core
|
package prog8.code.core
|
||||||
|
|
||||||
enum class DataType {
|
import java.util.Objects
|
||||||
UBYTE, // pass by value
|
|
||||||
BYTE, // pass by value
|
enum class BaseDataType {
|
||||||
UWORD, // pass by value
|
UBYTE, // pass by value 8 bits unsigned
|
||||||
WORD, // pass by value
|
BYTE, // pass by value 8 bits signed
|
||||||
FLOAT, // pass by value
|
UWORD, // pass by value 16 bits unsigned
|
||||||
BOOL, // pass by value
|
WORD, // pass by value 16 bits signed
|
||||||
|
LONG, // pass by value 32 bits signed
|
||||||
|
FLOAT, // pass by value machine dependent
|
||||||
|
BOOL, // pass by value bit 0 of an 8-bit byte
|
||||||
STR, // pass by reference
|
STR, // pass by reference
|
||||||
ARRAY_UB, // pass by reference
|
ARRAY, // pass by reference, subtype is the element type
|
||||||
ARRAY_B, // pass by reference
|
ARRAY_SPLITW, // pass by reference, split word layout, subtype is the element type (restricted to word types)
|
||||||
ARRAY_UW, // pass by reference
|
|
||||||
ARRAY_W, // pass by reference
|
|
||||||
ARRAY_F, // pass by reference
|
|
||||||
ARRAY_BOOL, // pass by reference
|
|
||||||
UNDEFINED;
|
UNDEFINED;
|
||||||
|
|
||||||
/**
|
|
||||||
* is the type assignable to the given other type (perhaps via a typecast) without loss of precision?
|
|
||||||
*/
|
|
||||||
infix fun isAssignableTo(targetType: DataType) =
|
|
||||||
when(this) {
|
|
||||||
BOOL -> targetType.oneOf(BOOL, BYTE, UBYTE, WORD, UWORD, FLOAT)
|
|
||||||
UBYTE -> targetType.oneOf(UBYTE, WORD, UWORD, FLOAT, BOOL)
|
|
||||||
BYTE -> targetType.oneOf(BYTE, WORD, FLOAT)
|
|
||||||
UWORD -> targetType.oneOf(UWORD, FLOAT)
|
|
||||||
WORD -> targetType.oneOf(WORD, FLOAT)
|
|
||||||
FLOAT -> targetType.oneOf(FLOAT)
|
|
||||||
STR -> targetType.oneOf(STR, UWORD)
|
|
||||||
in ArrayDatatypes -> targetType == this
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun oneOf(vararg types: DataType) = this in types
|
fun largerSizeThan(other: BaseDataType) =
|
||||||
|
|
||||||
infix fun largerThan(other: DataType) =
|
|
||||||
when {
|
when {
|
||||||
this == other -> false
|
this == other -> false
|
||||||
this in ByteDatatypes -> false
|
this.isByteOrBool -> false
|
||||||
this in WordDatatypes -> other in ByteDatatypes
|
this.isWord -> other.isByteOrBool
|
||||||
this== STR && other== UWORD || this== UWORD && other== STR -> false
|
this == LONG -> other.isByteOrBool || other.isWord
|
||||||
|
this == STR && other == UWORD || this == UWORD && other == STR -> false
|
||||||
|
this.isArray -> other != FLOAT
|
||||||
|
this == STR -> other != FLOAT
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun equalsSize(other: DataType) =
|
fun equalsSize(other: BaseDataType) =
|
||||||
when {
|
when {
|
||||||
this == other -> true
|
this == other -> true
|
||||||
this in ByteDatatypes -> other in ByteDatatypes
|
this.isByteOrBool -> other.isByteOrBool
|
||||||
this in WordDatatypes -> other in WordDatatypes
|
this.isWord -> other.isWord
|
||||||
this== STR && other== UWORD || this== UWORD && other== STR -> true
|
this == STR && other== UWORD || this== UWORD && other== STR -> true
|
||||||
|
this == STR && other.isArray -> true
|
||||||
|
this.isArray && other == STR -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val BaseDataType.isByte get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE)
|
||||||
|
val BaseDataType.isByteOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.BOOL)
|
||||||
|
val BaseDataType.isWord get() = this in arrayOf(BaseDataType.UWORD, BaseDataType.WORD)
|
||||||
|
val BaseDataType.isInteger get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)
|
||||||
|
val BaseDataType.isIntegerOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.BOOL)
|
||||||
|
val BaseDataType.isNumeric get() = this == BaseDataType.FLOAT || this.isInteger
|
||||||
|
val BaseDataType.isNumericOrBool get() = this == BaseDataType.BOOL || this.isNumeric
|
||||||
|
val BaseDataType.isSigned get() = this in arrayOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||||
|
val BaseDataType.isArray get() = this == BaseDataType.ARRAY || this == BaseDataType.ARRAY_SPLITW
|
||||||
|
val BaseDataType.isSplitWordArray get() = this == BaseDataType.ARRAY_SPLITW
|
||||||
|
val BaseDataType.isIterable get() = this in arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
|
||||||
|
val BaseDataType.isPassByRef get() = this.isIterable
|
||||||
|
val BaseDataType.isPassByValue get() = !this.isIterable
|
||||||
|
|
||||||
|
|
||||||
|
sealed class SubType(val dt: BaseDataType) {
|
||||||
|
companion object {
|
||||||
|
private val types by lazy {
|
||||||
|
// lazy because of static initialization order
|
||||||
|
mapOf(
|
||||||
|
BaseDataType.UBYTE to SubUnsignedByte,
|
||||||
|
BaseDataType.BYTE to SubSignedByte,
|
||||||
|
BaseDataType.UWORD to SubUnsignedWord,
|
||||||
|
BaseDataType.WORD to SubSignedWord,
|
||||||
|
BaseDataType.FLOAT to SubFloat,
|
||||||
|
BaseDataType.BOOL to SubBool
|
||||||
|
)}
|
||||||
|
|
||||||
|
fun forDt(dt: BaseDataType) = types.getValue(dt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data object SubUnsignedByte: SubType(BaseDataType.UBYTE)
|
||||||
|
data object SubSignedByte: SubType(BaseDataType.BYTE)
|
||||||
|
data object SubUnsignedWord: SubType(BaseDataType.UWORD)
|
||||||
|
data object SubSignedWord: SubType(BaseDataType.WORD)
|
||||||
|
data object SubBool: SubType(BaseDataType.BOOL)
|
||||||
|
data object SubFloat: SubType(BaseDataType.FLOAT)
|
||||||
|
|
||||||
|
|
||||||
|
class DataType private constructor(val base: BaseDataType, val sub: SubType?) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
if(base.isArray) {
|
||||||
|
require(sub != null)
|
||||||
|
if(base.isSplitWordArray)
|
||||||
|
require(sub.dt == BaseDataType.UWORD || sub.dt == BaseDataType.WORD)
|
||||||
|
}
|
||||||
|
else if(base==BaseDataType.STR)
|
||||||
|
require(sub?.dt==BaseDataType.UBYTE) { "STR subtype should be ubyte" }
|
||||||
|
else
|
||||||
|
require(sub == null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other !is DataType) return false
|
||||||
|
return base == other.base && sub == other.sub
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int = Objects.hash(base, sub)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val simpletypes = mapOf(
|
||||||
|
BaseDataType.UBYTE to DataType(BaseDataType.UBYTE, null),
|
||||||
|
BaseDataType.BYTE to DataType(BaseDataType.BYTE, null),
|
||||||
|
BaseDataType.UWORD to DataType(BaseDataType.UWORD, null),
|
||||||
|
BaseDataType.WORD to DataType(BaseDataType.WORD, null),
|
||||||
|
BaseDataType.LONG to DataType(BaseDataType.LONG, null),
|
||||||
|
BaseDataType.FLOAT to DataType(BaseDataType.FLOAT, null),
|
||||||
|
BaseDataType.BOOL to DataType(BaseDataType.BOOL, null),
|
||||||
|
BaseDataType.STR to DataType(BaseDataType.STR, SubUnsignedByte),
|
||||||
|
BaseDataType.UNDEFINED to DataType(BaseDataType.UNDEFINED, null)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun forDt(dt: BaseDataType) = simpletypes.getValue(dt)
|
||||||
|
|
||||||
|
fun arrayFor(elementDt: BaseDataType, splitwordarray: Boolean=true): DataType {
|
||||||
|
val actualElementDt = if(elementDt==BaseDataType.STR) BaseDataType.UWORD else elementDt // array of strings is actually just an array of UWORD pointers
|
||||||
|
return if(splitwordarray && elementDt.isWord)
|
||||||
|
DataType(BaseDataType.ARRAY_SPLITW, SubType.forDt(actualElementDt))
|
||||||
|
else
|
||||||
|
DataType(BaseDataType.ARRAY, SubType.forDt(actualElementDt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun elementToArray(splitwords: Boolean = true): DataType {
|
||||||
|
return if (base == BaseDataType.UWORD || base == BaseDataType.WORD || base == BaseDataType.STR) arrayFor(base, splitwords)
|
||||||
|
else arrayFor(base, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun elementType(): DataType =
|
||||||
|
if(base.isArray || base==BaseDataType.STR)
|
||||||
|
forDt(sub!!.dt)
|
||||||
|
else
|
||||||
|
throw IllegalArgumentException("not an array")
|
||||||
|
|
||||||
|
override fun toString(): String = when(base) {
|
||||||
|
BaseDataType.ARRAY -> {
|
||||||
|
when(sub) {
|
||||||
|
SubBool -> "bool[]"
|
||||||
|
SubFloat -> "float[]"
|
||||||
|
SubSignedByte -> "byte[]"
|
||||||
|
SubSignedWord -> "word[]"
|
||||||
|
SubUnsignedByte -> "ubyte[]"
|
||||||
|
SubUnsignedWord -> "uword[]"
|
||||||
|
null -> throw IllegalArgumentException("invalid sub type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BaseDataType.ARRAY_SPLITW -> {
|
||||||
|
when(sub) {
|
||||||
|
SubSignedWord -> "word[] (split)"
|
||||||
|
SubUnsignedWord -> "uword[] (split)"
|
||||||
|
else -> throw IllegalArgumentException("invalid sub type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> base.name.lowercase()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sourceString(): String = when (base) {
|
||||||
|
BaseDataType.BOOL -> "bool"
|
||||||
|
BaseDataType.UBYTE -> "ubyte"
|
||||||
|
BaseDataType.BYTE -> "byte"
|
||||||
|
BaseDataType.UWORD -> "uword"
|
||||||
|
BaseDataType.WORD -> "word"
|
||||||
|
BaseDataType.LONG -> "long"
|
||||||
|
BaseDataType.FLOAT -> "float"
|
||||||
|
BaseDataType.STR -> "str"
|
||||||
|
BaseDataType.ARRAY -> {
|
||||||
|
when(sub) {
|
||||||
|
SubUnsignedByte -> "ubyte["
|
||||||
|
SubUnsignedWord -> "@nosplit uword["
|
||||||
|
SubBool -> "bool["
|
||||||
|
SubSignedByte -> "byte["
|
||||||
|
SubSignedWord -> "@nosplit word["
|
||||||
|
SubFloat -> "float["
|
||||||
|
null -> throw IllegalArgumentException("invalid sub type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BaseDataType.ARRAY_SPLITW -> {
|
||||||
|
when(sub) {
|
||||||
|
SubUnsignedWord -> "uword["
|
||||||
|
SubSignedWord -> "word["
|
||||||
|
else -> throw IllegalArgumentException("invalid sub type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BaseDataType.UNDEFINED -> throw IllegalArgumentException("wrong dt")
|
||||||
|
}
|
||||||
|
|
||||||
|
// is the type assignable to the given other type (perhaps via a typecast) without loss of precision?
|
||||||
|
infix fun isAssignableTo(targetType: DataType) =
|
||||||
|
when(base) {
|
||||||
|
BaseDataType.BOOL -> targetType.base == BaseDataType.BOOL
|
||||||
|
BaseDataType.UBYTE -> targetType.base in arrayOf(BaseDataType.UBYTE, BaseDataType.WORD, BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||||
|
BaseDataType.BYTE -> targetType.base in arrayOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||||
|
BaseDataType.UWORD -> targetType.base in arrayOf(BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||||
|
BaseDataType.WORD -> targetType.base in arrayOf(BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||||
|
BaseDataType.LONG -> targetType.base in arrayOf(BaseDataType.LONG, BaseDataType.FLOAT)
|
||||||
|
BaseDataType.FLOAT -> targetType.base in arrayOf(BaseDataType.FLOAT)
|
||||||
|
BaseDataType.STR -> targetType.base in arrayOf(BaseDataType.STR, BaseDataType.UWORD)
|
||||||
|
BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW -> targetType.base in arrayOf(BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW) && targetType.sub == sub
|
||||||
|
BaseDataType.UNDEFINED -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun largerSizeThan(other: DataType): Boolean {
|
||||||
|
if(isArray) throw IllegalArgumentException("cannot compare size of array types")
|
||||||
|
return base.largerSizeThan(other.base)
|
||||||
|
}
|
||||||
|
fun equalsSize(other: DataType): Boolean {
|
||||||
|
if(isArray) throw IllegalArgumentException("cannot compare size of array types")
|
||||||
|
return base.equalsSize(other.base)
|
||||||
|
}
|
||||||
|
|
||||||
|
val isUndefined = base == BaseDataType.UNDEFINED
|
||||||
|
val isByte = base.isByte
|
||||||
|
val isUnsignedByte = base == BaseDataType.UBYTE
|
||||||
|
val isSignedByte = base == BaseDataType.BYTE
|
||||||
|
val isByteOrBool = base.isByteOrBool
|
||||||
|
val isWord = base.isWord
|
||||||
|
val isUnsignedWord = base == BaseDataType.UWORD
|
||||||
|
val isSignedWord = base == BaseDataType.WORD
|
||||||
|
val isInteger = base.isInteger
|
||||||
|
val isIntegerOrBool = base.isIntegerOrBool
|
||||||
|
val isNumeric = base.isNumeric
|
||||||
|
val isNumericOrBool = base.isNumericOrBool
|
||||||
|
val isSigned = base.isSigned
|
||||||
|
val isUnsigned = !base.isSigned
|
||||||
|
val isArray = base.isArray
|
||||||
|
val isBoolArray = base.isArray && sub?.dt == BaseDataType.BOOL
|
||||||
|
val isByteArray = base.isArray && (sub?.dt == BaseDataType.UBYTE || sub?.dt == BaseDataType.BYTE)
|
||||||
|
val isUnsignedByteArray = base.isArray && sub?.dt == BaseDataType.UBYTE
|
||||||
|
val isSignedByteArray = base.isArray && sub?.dt == BaseDataType.BYTE
|
||||||
|
val isWordArray = base.isArray && (sub?.dt == BaseDataType.UWORD || sub?.dt == BaseDataType.WORD)
|
||||||
|
val isUnsignedWordArray = base.isArray && sub?.dt == BaseDataType.UWORD
|
||||||
|
val isSignedWordArray = base.isArray && sub?.dt == BaseDataType.WORD
|
||||||
|
val isFloatArray = base.isArray && sub?.dt == BaseDataType.FLOAT
|
||||||
|
val isString = base == BaseDataType.STR
|
||||||
|
val isBool = base == BaseDataType.BOOL
|
||||||
|
val isFloat = base == BaseDataType.FLOAT
|
||||||
|
val isLong = base == BaseDataType.LONG
|
||||||
|
val isStringly = base == BaseDataType.STR || base == BaseDataType.UWORD || (base == BaseDataType.ARRAY && (sub?.dt == BaseDataType.UBYTE || sub?.dt == BaseDataType.BYTE))
|
||||||
|
val isSplitWordArray = base.isSplitWordArray
|
||||||
|
val isSplitUnsignedWordArray = base.isSplitWordArray && sub?.dt == BaseDataType.UWORD
|
||||||
|
val isSplitSignedWordArray = base.isSplitWordArray && sub?.dt == BaseDataType.WORD
|
||||||
|
val isIterable = base.isIterable
|
||||||
|
val isPassByRef = base.isPassByRef
|
||||||
|
val isPassByValue = base.isPassByValue
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum class CpuRegister {
|
enum class CpuRegister {
|
||||||
A,
|
A,
|
||||||
X,
|
X,
|
||||||
@ -73,7 +270,14 @@ enum class RegisterOrPair {
|
|||||||
R8, R9, R10, R11, R12, R13, R14, R15;
|
R8, R9, R10, R11, R12, R13, R14, R15;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val names by lazy { values().map { it.toString()} }
|
val names by lazy { entries.map { it.toString()} }
|
||||||
|
fun fromCpuRegister(cpu: CpuRegister): RegisterOrPair {
|
||||||
|
return when(cpu) {
|
||||||
|
CpuRegister.A -> A
|
||||||
|
CpuRegister.X -> X
|
||||||
|
CpuRegister.Y -> Y
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun asCpuRegister(): CpuRegister = when(this) {
|
fun asCpuRegister(): CpuRegister = when(this) {
|
||||||
@ -83,6 +287,17 @@ enum class RegisterOrPair {
|
|||||||
else -> throw IllegalArgumentException("no cpu hardware register for $this")
|
else -> throw IllegalArgumentException("no cpu hardware register for $this")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun asScopedNameVirtualReg(type: DataType?): List<String> {
|
||||||
|
require(this in Cx16VirtualRegisters)
|
||||||
|
val suffix = when(type?.base) {
|
||||||
|
BaseDataType.UBYTE, BaseDataType.BOOL -> "L"
|
||||||
|
BaseDataType.BYTE -> "sL"
|
||||||
|
BaseDataType.WORD -> "s"
|
||||||
|
BaseDataType.UWORD, null -> ""
|
||||||
|
else -> throw kotlin.IllegalArgumentException("invalid register param type")
|
||||||
|
}
|
||||||
|
return listOf("cx16", name.lowercase()+suffix)
|
||||||
|
}
|
||||||
} // only used in parameter and return value specs in asm subroutines
|
} // only used in parameter and return value specs in asm subroutines
|
||||||
|
|
||||||
enum class Statusflag {
|
enum class Statusflag {
|
||||||
@ -92,7 +307,7 @@ enum class Statusflag {
|
|||||||
Pn; // don't use
|
Pn; // don't use
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val names by lazy { values().map { it.toString()} }
|
val names by lazy { entries.map { it.toString()} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,44 +323,9 @@ enum class BranchCondition {
|
|||||||
PL, // PL == POS
|
PL, // PL == POS
|
||||||
POS,
|
POS,
|
||||||
VS,
|
VS,
|
||||||
VC,
|
VC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val ByteDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.BOOL)
|
|
||||||
val WordDatatypes = arrayOf(DataType.UWORD, DataType.WORD)
|
|
||||||
val IntegerDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.BOOL)
|
|
||||||
val IntegerDatatypesNoBool = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD)
|
|
||||||
val NumericDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT, DataType.BOOL)
|
|
||||||
val NumericDatatypesNoBool = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT)
|
|
||||||
val SignedDatatypes = arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
|
|
||||||
val ArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F, DataType.ARRAY_BOOL)
|
|
||||||
val StringlyDatatypes = arrayOf(DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.UWORD)
|
|
||||||
val IterableDatatypes = arrayOf(
|
|
||||||
DataType.STR,
|
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_B,
|
|
||||||
DataType.ARRAY_UW, DataType.ARRAY_W,
|
|
||||||
DataType.ARRAY_F, DataType.ARRAY_BOOL
|
|
||||||
)
|
|
||||||
val PassByValueDatatypes = NumericDatatypes
|
|
||||||
val PassByReferenceDatatypes = IterableDatatypes
|
|
||||||
val ArrayToElementTypes = mapOf(
|
|
||||||
DataType.STR to DataType.UBYTE,
|
|
||||||
DataType.ARRAY_B to DataType.BYTE,
|
|
||||||
DataType.ARRAY_UB to DataType.UBYTE,
|
|
||||||
DataType.ARRAY_W to DataType.WORD,
|
|
||||||
DataType.ARRAY_UW to DataType.UWORD,
|
|
||||||
DataType.ARRAY_F to DataType.FLOAT,
|
|
||||||
DataType.ARRAY_BOOL to DataType.BOOL
|
|
||||||
)
|
|
||||||
val ElementToArrayTypes = mapOf(
|
|
||||||
DataType.BYTE to DataType.ARRAY_B,
|
|
||||||
DataType.UBYTE to DataType.ARRAY_UB,
|
|
||||||
DataType.WORD to DataType.ARRAY_W,
|
|
||||||
DataType.UWORD to DataType.ARRAY_UW,
|
|
||||||
DataType.FLOAT to DataType.ARRAY_F,
|
|
||||||
DataType.BOOL to DataType.ARRAY_BOOL
|
|
||||||
)
|
|
||||||
val Cx16VirtualRegisters = arrayOf(
|
val Cx16VirtualRegisters = arrayOf(
|
||||||
RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, RegisterOrPair.R3,
|
RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, RegisterOrPair.R3,
|
||||||
RegisterOrPair.R4, RegisterOrPair.R5, RegisterOrPair.R6, RegisterOrPair.R7,
|
RegisterOrPair.R4, RegisterOrPair.R5, RegisterOrPair.R6, RegisterOrPair.R7,
|
||||||
@ -153,6 +333,10 @@ val Cx16VirtualRegisters = arrayOf(
|
|||||||
RegisterOrPair.R12, RegisterOrPair.R13, RegisterOrPair.R14, RegisterOrPair.R15
|
RegisterOrPair.R12, RegisterOrPair.R13, RegisterOrPair.R14, RegisterOrPair.R15
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val CpuRegisters = arrayOf(
|
||||||
|
RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y,
|
||||||
|
RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
enum class OutputType {
|
enum class OutputType {
|
||||||
@ -180,3 +364,9 @@ enum class ZeropageWish {
|
|||||||
DONTCARE,
|
DONTCARE,
|
||||||
NOT_IN_ZEROPAGE
|
NOT_IN_ZEROPAGE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class SplitWish {
|
||||||
|
DONTCARE,
|
||||||
|
SPLIT,
|
||||||
|
NOSPLIT
|
||||||
|
}
|
@ -1,12 +0,0 @@
|
|||||||
package prog8.code.core
|
|
||||||
|
|
||||||
interface IAssemblyGenerator {
|
|
||||||
fun compileToAssembly(): IAssemblyProgram?
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IAssemblyProgram {
|
|
||||||
val name: String
|
|
||||||
fun assemble(options: CompilationOptions): Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list"
|
|
17
codeCore/src/prog8/code/core/ICodeGeneratorBackend.kt
Normal file
17
codeCore/src/prog8/code/core/ICodeGeneratorBackend.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package prog8.code.core
|
||||||
|
|
||||||
|
import prog8.code.SymbolTable
|
||||||
|
import prog8.code.ast.PtProgram
|
||||||
|
|
||||||
|
interface ICodeGeneratorBackend {
|
||||||
|
fun generate(program: PtProgram,
|
||||||
|
symbolTable: SymbolTable,
|
||||||
|
options: CompilationOptions,
|
||||||
|
errors: IErrorReporter): IAssemblyProgram?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface IAssemblyProgram {
|
||||||
|
val name: String
|
||||||
|
fun assemble(options: CompilationOptions, errors: IErrorReporter): Boolean
|
||||||
|
}
|
@ -3,9 +3,7 @@ package prog8.code.core
|
|||||||
interface ICompilationTarget: IStringEncoding, IMemSizer {
|
interface ICompilationTarget: IStringEncoding, IMemSizer {
|
||||||
val name: String
|
val name: String
|
||||||
val machine: IMachineDefinition
|
val machine: IMachineDefinition
|
||||||
val supportedEncodings: Set<Encoding>
|
|
||||||
val defaultEncoding: Encoding
|
|
||||||
|
|
||||||
override fun encodeString(str: String, encoding: Encoding): List<UByte>
|
override fun encodeString(str: String, encoding: Encoding): List<UByte>
|
||||||
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String
|
override fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,14 @@ package prog8.code.core
|
|||||||
interface IErrorReporter {
|
interface IErrorReporter {
|
||||||
fun err(msg: String, position: Position)
|
fun err(msg: String, position: Position)
|
||||||
fun warn(msg: String, position: Position)
|
fun warn(msg: String, position: Position)
|
||||||
|
fun info(msg: String, position: Position)
|
||||||
|
fun undefined(symbol: List<String>, position: Position)
|
||||||
fun noErrors(): Boolean
|
fun noErrors(): Boolean
|
||||||
fun report()
|
fun report()
|
||||||
fun finalizeNumErrors(numErrors: Int, numWarnings: Int) {
|
fun finalizeNumErrors(numErrors: Int, numWarnings: Int, numInfos: Int) {
|
||||||
if(numErrors>0)
|
if(numErrors>0)
|
||||||
throw ErrorsReportedException("There are $numErrors errors and $numWarnings warnings.")
|
throw ErrorsReportedException("There are $numErrors errors, $numWarnings warnings, and $numInfos infos.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun noErrorForLine(position: Position): Boolean
|
||||||
}
|
}
|
||||||
|
@ -13,23 +13,24 @@ interface IMachineDefinition {
|
|||||||
val FLOAT_MAX_NEGATIVE: Double
|
val FLOAT_MAX_NEGATIVE: Double
|
||||||
val FLOAT_MAX_POSITIVE: Double
|
val FLOAT_MAX_POSITIVE: Double
|
||||||
val FLOAT_MEM_SIZE: Int
|
val FLOAT_MEM_SIZE: Int
|
||||||
var ESTACK_LO: UInt
|
val STARTUP_CODE_RESERVED_SIZE: UInt // this is here, so that certain compiler targets are able to tune this
|
||||||
var ESTACK_HI: UInt
|
|
||||||
val PROGRAM_LOAD_ADDRESS : UInt
|
val PROGRAM_LOAD_ADDRESS : UInt
|
||||||
|
val PROGRAM_MEMTOP_ADDRESS: UInt
|
||||||
|
val BSSHIGHRAM_START: UInt
|
||||||
|
val BSSHIGHRAM_END: UInt
|
||||||
|
val BSSGOLDENRAM_START: UInt
|
||||||
|
val BSSGOLDENRAM_END: UInt
|
||||||
|
|
||||||
val opcodeNames: Set<String>
|
|
||||||
var zeropage: Zeropage
|
|
||||||
val cpu: CpuType
|
val cpu: CpuType
|
||||||
|
var zeropage: Zeropage
|
||||||
|
var golden: GoldenRam
|
||||||
|
|
||||||
fun initializeZeropage(compilerOptions: CompilationOptions)
|
fun initializeMemoryAreas(compilerOptions: CompilationOptions)
|
||||||
fun getFloatAsmBytes(num: Number): String
|
fun getFloatAsmBytes(num: Number): String
|
||||||
|
|
||||||
fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List<String>
|
fun convertFloatToBytes(num: Double): List<UByte>
|
||||||
|
fun convertBytesToFloat(bytes: List<UByte>): Double
|
||||||
|
|
||||||
fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path)
|
fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path)
|
||||||
fun isIOAddress(address: UInt): Boolean
|
fun isIOAddress(address: UInt): Boolean
|
||||||
fun overrideEvalStack(evalStackBaseAddress: UInt) {
|
|
||||||
require(evalStackBaseAddress and 255u == 0u)
|
|
||||||
ESTACK_LO = evalStackBaseAddress
|
|
||||||
ESTACK_HI = evalStackBaseAddress + 256u
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package prog8.code.core
|
package prog8.code.core
|
||||||
|
|
||||||
interface IMemSizer {
|
interface IMemSizer {
|
||||||
fun memorySize(dt: DataType): Int
|
fun memorySize(dt: DataType, numElements: Int?): Int
|
||||||
fun memorySize(arrayDt: DataType, numElements: Int): Int
|
fun memorySize(dt: SubType): Int
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,16 @@ enum class Encoding(val prefix: String) {
|
|||||||
PETSCII("petscii"), // c64/c128/cx16
|
PETSCII("petscii"), // c64/c128/cx16
|
||||||
SCREENCODES("sc"), // c64/c128/cx16
|
SCREENCODES("sc"), // c64/c128/cx16
|
||||||
ATASCII("atascii"), // atari
|
ATASCII("atascii"), // atari
|
||||||
ISO("iso") // cx16
|
ISO("iso"), // cx16 (iso-8859-15)
|
||||||
|
ISO5("iso5"), // cx16 (iso-8859-5, cyrillic)
|
||||||
|
ISO16("iso16"), // cx16 (iso-8859-16, eastern european)
|
||||||
|
CP437("cp437"), // cx16 (ibm pc, codepage 437)
|
||||||
|
KATAKANA("kata") // cx16 (katakana)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IStringEncoding {
|
interface IStringEncoding {
|
||||||
|
val defaultEncoding: Encoding
|
||||||
|
|
||||||
fun encodeString(str: String, encoding: Encoding): List<UByte>
|
fun encodeString(str: String, encoding: Encoding): List<UByte>
|
||||||
fun decodeString(bytes: List<UByte>, encoding: Encoding): String
|
fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String
|
||||||
}
|
}
|
||||||
|
172
codeCore/src/prog8/code/core/MemoryRegions.kt
Normal file
172
codeCore/src/prog8/code/core/MemoryRegions.kt
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
package prog8.code.core
|
||||||
|
|
||||||
|
import com.github.michaelbull.result.Err
|
||||||
|
import com.github.michaelbull.result.Ok
|
||||||
|
import com.github.michaelbull.result.Result
|
||||||
|
|
||||||
|
|
||||||
|
class MemAllocationError(message: String) : Exception(message)
|
||||||
|
|
||||||
|
|
||||||
|
abstract class MemoryAllocator(protected val options: CompilationOptions) {
|
||||||
|
data class VarAllocation(val address: UInt, val dt: DataType, val size: Int)
|
||||||
|
|
||||||
|
abstract fun allocate(name: String,
|
||||||
|
datatype: DataType,
|
||||||
|
numElements: Int?,
|
||||||
|
position: Position?,
|
||||||
|
errors: IErrorReporter): Result<VarAllocation, MemAllocationError>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
|
||||||
|
|
||||||
|
abstract val SCRATCH_B1 : UInt // temp storage for a single byte
|
||||||
|
abstract val SCRATCH_REG : UInt // temp storage for a register, must be B1+1
|
||||||
|
abstract val SCRATCH_W1 : UInt // temp storage 1 for a word $fb+$fc
|
||||||
|
abstract val SCRATCH_W2 : UInt // temp storage 2 for a word $fb+$fc
|
||||||
|
|
||||||
|
|
||||||
|
// the variables allocated into Zeropage.
|
||||||
|
// name (scoped) ==> pair of address to (Datatype + bytesize)
|
||||||
|
val allocatedVariables = mutableMapOf<String, VarAllocation>()
|
||||||
|
|
||||||
|
val free = mutableListOf<UInt>() // subclasses must set this to the appropriate free locations.
|
||||||
|
|
||||||
|
fun removeReservedFromFreePool() {
|
||||||
|
synchronized(this) {
|
||||||
|
for (reserved in options.zpReserved)
|
||||||
|
reserve(reserved)
|
||||||
|
|
||||||
|
free.removeAll(arrayOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun retainAllowed() {
|
||||||
|
synchronized(this) {
|
||||||
|
for(allowed in options.zpAllowed)
|
||||||
|
free.retainAll { it in allowed }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun availableBytes() = if(options.zeropage== ZeropageType.DONTUSE) 0 else free.size
|
||||||
|
fun hasByteAvailable() = if(options.zeropage== ZeropageType.DONTUSE) false else free.isNotEmpty()
|
||||||
|
fun hasWordAvailable(): Boolean {
|
||||||
|
if(options.zeropage== ZeropageType.DONTUSE)
|
||||||
|
return false
|
||||||
|
|
||||||
|
return free.windowed(2).any { it[0] == it[1] - 1u }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun allocate(name: String,
|
||||||
|
datatype: DataType,
|
||||||
|
numElements: Int?,
|
||||||
|
position: Position?,
|
||||||
|
errors: IErrorReporter): Result<VarAllocation, MemAllocationError> {
|
||||||
|
|
||||||
|
require(name.isEmpty() || name !in allocatedVariables) {"name can't be allocated twice"}
|
||||||
|
|
||||||
|
if(options.zeropage== ZeropageType.DONTUSE)
|
||||||
|
return Err(MemAllocationError("zero page usage has been disabled"))
|
||||||
|
|
||||||
|
val size: Int =
|
||||||
|
when {
|
||||||
|
datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null)
|
||||||
|
datatype.isString || datatype.isArray -> {
|
||||||
|
val memsize = options.compTarget.memorySize(datatype, numElements!!)
|
||||||
|
if(position!=null)
|
||||||
|
errors.warn("allocating a large value in zeropage; str/array $memsize bytes", position)
|
||||||
|
else
|
||||||
|
errors.warn("$name: allocating a large value in zeropage; str/array $memsize bytes", Position.DUMMY)
|
||||||
|
memsize
|
||||||
|
}
|
||||||
|
datatype.isFloat -> {
|
||||||
|
if (options.floats) {
|
||||||
|
val memsize = options.compTarget.memorySize(DataType.forDt(BaseDataType.FLOAT), null)
|
||||||
|
if(position!=null)
|
||||||
|
errors.warn("allocating a large value in zeropage; float $memsize bytes", position)
|
||||||
|
else
|
||||||
|
errors.warn("$name: allocating a large value in zeropage; float $memsize bytes", Position.DUMMY)
|
||||||
|
memsize
|
||||||
|
} else return Err(MemAllocationError("floating point option not enabled"))
|
||||||
|
}
|
||||||
|
else -> throw MemAllocationError("weird dt")
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized(this) {
|
||||||
|
if(free.isNotEmpty()) {
|
||||||
|
if(size==1) {
|
||||||
|
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
||||||
|
if(oneSeparateByteFree(candidate))
|
||||||
|
return Ok(VarAllocation(makeAllocation(candidate, 1, datatype, name), datatype,1))
|
||||||
|
}
|
||||||
|
return Ok(VarAllocation(makeAllocation(free[0], 1, datatype, name), datatype,1))
|
||||||
|
}
|
||||||
|
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
||||||
|
if (sequentialFree(candidate, size))
|
||||||
|
return Ok(VarAllocation(makeAllocation(candidate, size, datatype, name), datatype, size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(MemAllocationError("no more free space in ZP to allocate $size sequential bytes"))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reserve(range: UIntRange) = free.removeAll(range)
|
||||||
|
|
||||||
|
private fun makeAllocation(address: UInt, size: Int, datatype: DataType, name: String): UInt {
|
||||||
|
require(size>=0)
|
||||||
|
free.removeAll(address until address+size.toUInt())
|
||||||
|
if(name.isNotEmpty()) {
|
||||||
|
allocatedVariables[name] = when {
|
||||||
|
datatype.isNumericOrBool -> VarAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
|
||||||
|
datatype.isString -> VarAllocation(address, datatype, size)
|
||||||
|
datatype.isArray -> VarAllocation(address, datatype, size)
|
||||||
|
else -> throw AssemblyError("invalid dt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return address
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun oneSeparateByteFree(address: UInt) = address in free && address-1u !in free && address+1u !in free
|
||||||
|
private fun sequentialFree(address: UInt, size: Int): Boolean {
|
||||||
|
require(size>0)
|
||||||
|
return free.containsAll((address until address+size.toUInt()).toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun allocateCx16VirtualRegisters()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: this class is not yet used
|
||||||
|
class GoldenRam(options: CompilationOptions, val region: UIntRange): MemoryAllocator(options) {
|
||||||
|
private var nextLocation: UInt = region.first
|
||||||
|
|
||||||
|
override fun allocate(
|
||||||
|
name: String,
|
||||||
|
datatype: DataType,
|
||||||
|
numElements: Int?,
|
||||||
|
position: Position?,
|
||||||
|
errors: IErrorReporter): Result<VarAllocation, MemAllocationError> {
|
||||||
|
|
||||||
|
val size: Int =
|
||||||
|
when {
|
||||||
|
datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null)
|
||||||
|
datatype.isString -> numElements!!
|
||||||
|
datatype.isArray -> options.compTarget.memorySize(datatype, numElements!!)
|
||||||
|
datatype.isFloat -> {
|
||||||
|
if (options.floats) {
|
||||||
|
options.compTarget.memorySize(DataType.forDt(BaseDataType.FLOAT), null)
|
||||||
|
} else return Err(MemAllocationError("floating point option not enabled"))
|
||||||
|
}
|
||||||
|
else -> throw MemAllocationError("weird dt")
|
||||||
|
}
|
||||||
|
|
||||||
|
return if(nextLocation<=region.last && (region.last + 1u - nextLocation) >= size.toUInt()) {
|
||||||
|
val result = Ok(VarAllocation(nextLocation, datatype, size))
|
||||||
|
nextLocation += size.toUInt()
|
||||||
|
result
|
||||||
|
} else
|
||||||
|
Err(MemAllocationError("no more free space in Golden RAM to allocate $size sequential bytes"))
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,10 @@
|
|||||||
package prog8.code.core
|
package prog8.code.core
|
||||||
|
|
||||||
val AssociativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=")
|
val AssociativeOperators = arrayOf("+", "*", "&", "|", "^", "==", "!=", "xor") // note: and,or are not associative because of Shortcircuit/McCarthy evaluation
|
||||||
val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
|
val ComparisonOperators = arrayOf("==", "!=", "<", ">", "<=", ">=")
|
||||||
val LogicalOperators = setOf("and", "or", "xor", "not")
|
val LogicalOperators = arrayOf("and", "or", "xor", "not", "in")
|
||||||
val AugmentAssignmentOperators = setOf("+", "-", "/", "*", "&", "|", "^", "<<", ">>", "%", "and", "or", "xor")
|
val BitwiseOperators = arrayOf("&", "|", "^", "~")
|
||||||
val BitwiseOperators = setOf("&", "|", "^", "~")
|
val PrefixOperators = arrayOf("+", "-", "~", "not")
|
||||||
// val InvalidOperatorsForBoolean = setOf("+", "-", "*", "/", "%", "<<", ">>") + BitwiseOperators
|
|
||||||
|
|
||||||
fun invertedComparisonOperator(operator: String) =
|
fun invertedComparisonOperator(operator: String) =
|
||||||
when (operator) {
|
when (operator) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package prog8.code.core
|
package prog8.code.core
|
||||||
|
|
||||||
|
import prog8.code.source.SourceCode
|
||||||
import java.nio.file.InvalidPathException
|
import java.nio.file.InvalidPathException
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
import kotlin.io.path.absolute
|
import kotlin.io.path.absolute
|
||||||
@ -7,10 +8,14 @@ import kotlin.io.path.absolute
|
|||||||
data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) {
|
data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) {
|
||||||
override fun toString(): String = "[$file: line $line col ${startCol+1}-${endCol+1}]"
|
override fun toString(): String = "[$file: line $line col ${startCol+1}-${endCol+1}]"
|
||||||
fun toClickableStr(): String {
|
fun toClickableStr(): String {
|
||||||
|
if(this===DUMMY)
|
||||||
|
return ""
|
||||||
|
if(SourceCode.isLibraryResource(file))
|
||||||
|
return "$file:$line:$startCol:"
|
||||||
return try {
|
return try {
|
||||||
val path = Path(file).absolute().normalize().toString()
|
val path = Path(file).absolute().normalize().toString()
|
||||||
"file://$path:$line:$startCol:"
|
"file://$path:$line:$startCol:"
|
||||||
} catch(x: InvalidPathException) {
|
} catch(_: InvalidPathException) {
|
||||||
// this can occur on Windows when the source origin contains "invalid" characters such as ':'
|
// this can occur on Windows when the source origin contains "invalid" characters such as ':'
|
||||||
"file://$file:$line:$startCol:"
|
"file://$file:$line:$startCol:"
|
||||||
}
|
}
|
||||||
|
@ -1,122 +0,0 @@
|
|||||||
package prog8.code.core
|
|
||||||
|
|
||||||
import com.github.michaelbull.result.Err
|
|
||||||
import com.github.michaelbull.result.Ok
|
|
||||||
import com.github.michaelbull.result.Result
|
|
||||||
|
|
||||||
|
|
||||||
class ZeropageAllocationError(message: String) : Exception(message)
|
|
||||||
|
|
||||||
|
|
||||||
abstract class Zeropage(protected val options: CompilationOptions) {
|
|
||||||
|
|
||||||
abstract val SCRATCH_B1 : UInt // temp storage for a single byte
|
|
||||||
abstract val SCRATCH_REG : UInt // temp storage for a register, must be B1+1
|
|
||||||
abstract val SCRATCH_W1 : UInt // temp storage 1 for a word $fb+$fc
|
|
||||||
abstract val SCRATCH_W2 : UInt // temp storage 2 for a word $fb+$fc
|
|
||||||
|
|
||||||
data class ZpAllocation(val address: UInt, val dt: DataType, val size: Int)
|
|
||||||
|
|
||||||
// the variables allocated into Zeropage.
|
|
||||||
// name (scoped) ==> pair of address to (Datatype + bytesize)
|
|
||||||
val allocatedVariables = mutableMapOf<List<String>, ZpAllocation>()
|
|
||||||
|
|
||||||
val free = mutableListOf<UInt>() // subclasses must set this to the appropriate free locations.
|
|
||||||
|
|
||||||
fun removeReservedFromFreePool() {
|
|
||||||
synchronized(this) {
|
|
||||||
for (reserved in options.zpReserved)
|
|
||||||
reserve(reserved)
|
|
||||||
|
|
||||||
free.removeAll(setOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun availableBytes() = if(options.zeropage== ZeropageType.DONTUSE) 0 else free.size
|
|
||||||
fun hasByteAvailable() = if(options.zeropage== ZeropageType.DONTUSE) false else free.isNotEmpty()
|
|
||||||
fun hasWordAvailable(): Boolean {
|
|
||||||
if(options.zeropage== ZeropageType.DONTUSE)
|
|
||||||
return false
|
|
||||||
|
|
||||||
return free.windowed(2).any { it[0] == it[1] - 1u }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun allocate(name: List<String>,
|
|
||||||
datatype: DataType,
|
|
||||||
numElements: Int?,
|
|
||||||
position: Position?,
|
|
||||||
errors: IErrorReporter
|
|
||||||
): Result<Pair<UInt, Int>, ZeropageAllocationError> {
|
|
||||||
|
|
||||||
require(name.isEmpty() || name !in allocatedVariables) {"name can't be allocated twice"}
|
|
||||||
|
|
||||||
if(options.zeropage== ZeropageType.DONTUSE)
|
|
||||||
return Err(ZeropageAllocationError("zero page usage has been disabled"))
|
|
||||||
|
|
||||||
val size: Int =
|
|
||||||
when (datatype) {
|
|
||||||
in IntegerDatatypes -> options.compTarget.memorySize(datatype)
|
|
||||||
DataType.STR, in ArrayDatatypes -> {
|
|
||||||
val memsize = options.compTarget.memorySize(datatype, numElements!!)
|
|
||||||
if(position!=null)
|
|
||||||
errors.warn("allocating a large value in zeropage; str/array $memsize bytes", position)
|
|
||||||
else
|
|
||||||
errors.warn("$name: allocating a large value in zeropage; str/array $memsize bytes", Position.DUMMY)
|
|
||||||
memsize
|
|
||||||
}
|
|
||||||
DataType.FLOAT -> {
|
|
||||||
if (options.floats) {
|
|
||||||
val memsize = options.compTarget.memorySize(DataType.FLOAT)
|
|
||||||
if(position!=null)
|
|
||||||
errors.warn("allocating a large value in zeropage; float $memsize bytes", position)
|
|
||||||
else
|
|
||||||
errors.warn("$name: allocating a large value in zeropage; float $memsize bytes", Position.DUMMY)
|
|
||||||
memsize
|
|
||||||
} else return Err(ZeropageAllocationError("floating point option not enabled"))
|
|
||||||
}
|
|
||||||
else -> return Err(ZeropageAllocationError("cannot put datatype $datatype in zeropage"))
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized(this) {
|
|
||||||
if(free.size > 0) {
|
|
||||||
if(size==1) {
|
|
||||||
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
|
||||||
if(oneSeparateByteFree(candidate))
|
|
||||||
return Ok(Pair(makeAllocation(candidate, 1, datatype, name), 1))
|
|
||||||
}
|
|
||||||
return Ok(Pair(makeAllocation(free[0], 1, datatype, name), 1))
|
|
||||||
}
|
|
||||||
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
|
||||||
if (sequentialFree(candidate, size))
|
|
||||||
return Ok(Pair(makeAllocation(candidate, size, datatype, name), size))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err(ZeropageAllocationError("no more free space in ZP to allocate $size sequential bytes"))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reserve(range: UIntRange) = free.removeAll(range)
|
|
||||||
|
|
||||||
private fun makeAllocation(address: UInt, size: Int, datatype: DataType, name: List<String>): UInt {
|
|
||||||
require(size>=0)
|
|
||||||
free.removeAll(address until address+size.toUInt())
|
|
||||||
if(name.isNotEmpty()) {
|
|
||||||
allocatedVariables[name] = when(datatype) {
|
|
||||||
in NumericDatatypes -> ZpAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
|
|
||||||
DataType.STR -> ZpAllocation(address, datatype, size)
|
|
||||||
in ArrayDatatypes -> ZpAllocation(address, datatype, size)
|
|
||||||
else -> throw AssemblyError("invalid dt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return address
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun oneSeparateByteFree(address: UInt) = address in free && address-1u !in free && address+1u !in free
|
|
||||||
private fun sequentialFree(address: UInt, size: Int): Boolean {
|
|
||||||
require(size>0)
|
|
||||||
return free.containsAll((address until address+size.toUInt()).toList())
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun allocateCx16VirtualRegisters()
|
|
||||||
}
|
|
180
codeCore/src/prog8/code/optimize/Optimizer.kt
Normal file
180
codeCore/src/prog8/code/optimize/Optimizer.kt
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
package prog8.code.optimize
|
||||||
|
|
||||||
|
import prog8.code.StExtSub
|
||||||
|
import prog8.code.SymbolTable
|
||||||
|
import prog8.code.ast.*
|
||||||
|
import prog8.code.core.*
|
||||||
|
|
||||||
|
|
||||||
|
fun optimizeIntermediateAst(program: PtProgram, options: CompilationOptions, st: SymbolTable, errors: IErrorReporter) {
|
||||||
|
if (!options.optimize)
|
||||||
|
return
|
||||||
|
while (errors.noErrors() &&
|
||||||
|
(optimizeBitTest(program, options)
|
||||||
|
+ optimizeAssignTargets(program, st)) > 0
|
||||||
|
) {
|
||||||
|
// keep rolling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun walkAst(root: PtNode, act: (node: PtNode, depth: Int) -> Boolean) {
|
||||||
|
fun recurse(node: PtNode, depth: Int) {
|
||||||
|
if(act(node, depth))
|
||||||
|
node.children.forEach { recurse(it, depth+1) }
|
||||||
|
}
|
||||||
|
recurse(root, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun optimizeAssignTargets(program: PtProgram, st: SymbolTable): Int {
|
||||||
|
var changes = 0
|
||||||
|
walkAst(program) { node: PtNode, depth: Int ->
|
||||||
|
if(node is PtAssignment) {
|
||||||
|
val value = node.value
|
||||||
|
val functionName = when(value) {
|
||||||
|
is PtBuiltinFunctionCall -> value.name
|
||||||
|
is PtFunctionCall -> value.name
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
if(functionName!=null) {
|
||||||
|
val stNode = st.lookup(functionName)
|
||||||
|
if (stNode is StExtSub) {
|
||||||
|
require(node.children.size==stNode.returns.size+1) {
|
||||||
|
"number of targets must match return values"
|
||||||
|
}
|
||||||
|
node.children.zip(stNode.returns).withIndex().forEach { (index, xx) ->
|
||||||
|
val target = xx.first as PtAssignTarget
|
||||||
|
val returnedRegister = xx.second.register.registerOrPair
|
||||||
|
if(returnedRegister!=null && !target.void && target.identifier!=null) {
|
||||||
|
if(isSame(target.identifier!!, xx.second.type, returnedRegister)) {
|
||||||
|
// output register is already identical to target register, so it can become void
|
||||||
|
val voidTarget = PtAssignTarget(true, target.position)
|
||||||
|
node.children[index] = voidTarget
|
||||||
|
voidTarget.parent = node
|
||||||
|
changes++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.children.dropLast(1).all { (it as PtAssignTarget).void }) {
|
||||||
|
// all targets are now void, the whole assignment can be discarded and replaced by just a (void) call to the subroutine
|
||||||
|
val index = node.parent.children.indexOf(node)
|
||||||
|
val voidCall = PtFunctionCall(functionName, true, DataType.forDt(BaseDataType.UNDEFINED), value.position)
|
||||||
|
value.children.forEach { voidCall.add(it) }
|
||||||
|
node.parent.children[index] = voidCall
|
||||||
|
voidCall.parent = node.parent
|
||||||
|
changes++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
return changes
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun optimizeBitTest(program: PtProgram, options: CompilationOptions): Int {
|
||||||
|
if(options.compTarget.machine.cpu == CpuType.VIRTUAL)
|
||||||
|
return 0 // the special bittest optimization is not yet valid for the IR
|
||||||
|
|
||||||
|
fun makeBittestCall(condition: PtBinaryExpression, and: PtBinaryExpression, variable: PtIdentifier, bitmask: Int): PtBuiltinFunctionCall {
|
||||||
|
require(bitmask==128 || bitmask==64)
|
||||||
|
val setOrNot = if(condition.operator=="!=") "set" else "notset"
|
||||||
|
val bittestCall = PtBuiltinFunctionCall("prog8_ifelse_bittest_$setOrNot", false, true, DataType.forDt(BaseDataType.BOOL), condition.position)
|
||||||
|
bittestCall.add(variable)
|
||||||
|
if(bitmask==128)
|
||||||
|
bittestCall.add(PtNumber(BaseDataType.UBYTE, 7.0, and.right.position))
|
||||||
|
else
|
||||||
|
bittestCall.add(PtNumber(BaseDataType.UBYTE, 6.0, and.right.position))
|
||||||
|
return bittestCall
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAndByteCondition(condition: PtBinaryExpression?): Triple<PtBinaryExpression, PtIdentifier, Int>? {
|
||||||
|
if(condition!=null && (condition.operator=="==" || condition.operator=="!=")) {
|
||||||
|
if (condition.right.asConstInteger() == 0) {
|
||||||
|
val and = condition.left as? PtBinaryExpression
|
||||||
|
if (and != null && and.operator == "&" && and.type.isUnsignedByte) {
|
||||||
|
val bitmask = and.right.asConstInteger()
|
||||||
|
if(bitmask==128 || bitmask==64) {
|
||||||
|
val variable = and.left as? PtIdentifier
|
||||||
|
if (variable != null && variable.type.isByte) {
|
||||||
|
return Triple(and, variable, bitmask)
|
||||||
|
}
|
||||||
|
val typecast = and.left as? PtTypeCast
|
||||||
|
if (typecast != null && typecast.type.isUnsignedByte) {
|
||||||
|
val castedVariable = typecast.value as? PtIdentifier
|
||||||
|
if(castedVariable!=null && castedVariable.type.isByte)
|
||||||
|
return Triple(and, castedVariable, bitmask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
var changes = 0
|
||||||
|
var recurse = true
|
||||||
|
walkAst(program) { node: PtNode, depth: Int ->
|
||||||
|
if(node is PtIfElse) {
|
||||||
|
val condition = node.condition as? PtBinaryExpression
|
||||||
|
val check = isAndByteCondition(condition)
|
||||||
|
if(check!=null) {
|
||||||
|
val (and, variable, bitmask) = check
|
||||||
|
val bittestCall = makeBittestCall(condition!!, and, variable, bitmask)
|
||||||
|
val ifElse = PtIfElse(node.position)
|
||||||
|
ifElse.add(bittestCall)
|
||||||
|
ifElse.add(node.ifScope)
|
||||||
|
if (node.hasElse())
|
||||||
|
ifElse.add(node.elseScope)
|
||||||
|
val index = node.parent.children.indexOf(node)
|
||||||
|
node.parent.children[index] = ifElse
|
||||||
|
ifElse.parent = node.parent
|
||||||
|
changes++
|
||||||
|
recurse = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node is PtIfExpression) {
|
||||||
|
val condition = node.condition as? PtBinaryExpression
|
||||||
|
val check = isAndByteCondition(condition)
|
||||||
|
if(check!=null) {
|
||||||
|
val (and, variable, bitmask) = check
|
||||||
|
val bittestCall = makeBittestCall(condition!!, and, variable, bitmask)
|
||||||
|
node.children[0] = bittestCall
|
||||||
|
bittestCall.parent = node
|
||||||
|
changes++
|
||||||
|
recurse = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recurse
|
||||||
|
}
|
||||||
|
return changes
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal fun isSame(identifier: PtIdentifier, type: DataType, returnedRegister: RegisterOrPair): Boolean {
|
||||||
|
if(returnedRegister in Cx16VirtualRegisters) {
|
||||||
|
val regname = returnedRegister.name.lowercase()
|
||||||
|
val identifierRegName = identifier.name.substringAfterLast('.')
|
||||||
|
/*
|
||||||
|
cx16.r? UWORD
|
||||||
|
cx16.r?s WORD
|
||||||
|
cx16.r?L UBYTE
|
||||||
|
cx16.r?H UBYTE
|
||||||
|
cx16.r?sL BYTE
|
||||||
|
cx16.r?sH BYTE
|
||||||
|
*/
|
||||||
|
if(identifier.type.isByte && type.isByte) {
|
||||||
|
if(identifier.name.startsWith("cx16.$regname") && identifierRegName.startsWith(regname)) {
|
||||||
|
return identifierRegName.substring(2) in arrayOf("", "L", "sL") // note: not the -H (msb) variants!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(identifier.type.isWord && type.isWord) {
|
||||||
|
if(identifier.name.startsWith("cx16.$regname") && identifierRegName.startsWith(regname)) {
|
||||||
|
return identifierRegName.substring(2) in arrayOf("", "s")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false // there are no identifiers directly corresponding to cpu registers
|
||||||
|
}
|
60
codeCore/src/prog8/code/source/ImportFileSystem.kt
Normal file
60
codeCore/src/prog8/code/source/ImportFileSystem.kt
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package prog8.code.source
|
||||||
|
|
||||||
|
import prog8.code.core.Position
|
||||||
|
import java.nio.file.Path
|
||||||
|
import kotlin.io.path.Path
|
||||||
|
|
||||||
|
|
||||||
|
// Resource caching "filesystem".
|
||||||
|
// Note that it leaves the decision to load a resource or an actual disk file to the caller.
|
||||||
|
|
||||||
|
object ImportFileSystem {
|
||||||
|
fun getFile(path: Path): SourceCode {
|
||||||
|
val cached = cache[path.toString()]
|
||||||
|
if (cached != null) return cached
|
||||||
|
val file = SourceCode.File(path)
|
||||||
|
cache[path.toString()] = file
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getResource(name: String): SourceCode {
|
||||||
|
val cached = cache[name]
|
||||||
|
if (cached != null) return cached
|
||||||
|
val resource = SourceCode.Resource(name)
|
||||||
|
cache[name] = resource
|
||||||
|
return resource
|
||||||
|
}
|
||||||
|
|
||||||
|
fun retrieveSourceLine(position: Position): String {
|
||||||
|
if(SourceCode.isLibraryResource(position.file)) {
|
||||||
|
val cached = cache[SourceCode.withoutPrefix(position.file)]
|
||||||
|
if(cached != null)
|
||||||
|
return getLine(cached, position.line)
|
||||||
|
}
|
||||||
|
val cached = cache[position.file]
|
||||||
|
if(cached != null)
|
||||||
|
return getLine(cached, position.line)
|
||||||
|
val path = Path(position.file).toAbsolutePath().normalize()
|
||||||
|
val cached2 = cache[path.toString()]
|
||||||
|
if(cached2 != null)
|
||||||
|
return getLine(cached2, position.line)
|
||||||
|
throw NoSuchElementException("cannot get source line $position")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLine(code: SourceCode, lineIndex: Int): String {
|
||||||
|
var spans = lineSpanCache[code]
|
||||||
|
if(spans==null) {
|
||||||
|
val lineSpans = Regex("^", RegexOption.MULTILINE).findAll(code.text).map { it.range.first }
|
||||||
|
val ends = lineSpans.drop(1) + code.text.length
|
||||||
|
spans = lineSpans.zip(ends).map { (start, end) -> LineSpan(start, end) }.toList().toTypedArray()
|
||||||
|
lineSpanCache[code] = spans
|
||||||
|
}
|
||||||
|
val span = spans[lineIndex - 1]
|
||||||
|
return code.text.substring(span.start, span.end).trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LineSpan(val start: Int, val end: Int)
|
||||||
|
|
||||||
|
private val cache = mutableMapOf<String, SourceCode>()
|
||||||
|
private val lineSpanCache = mutableMapOf<SourceCode, Array<LineSpan>>()
|
||||||
|
}
|
@ -1,15 +1,11 @@
|
|||||||
package prog8.code.core
|
package prog8.code.source
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import java.text.Normalizer
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
import kotlin.io.path.readText
|
import kotlin.io.path.readText
|
||||||
|
|
||||||
|
|
||||||
const val internedStringsModuleName = "prog8_interned_strings"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates - and ties together - actual source code (=text) and its [origin].
|
* Encapsulates - and ties together - actual source code (=text) and its [origin].
|
||||||
*/
|
*/
|
||||||
@ -54,34 +50,45 @@ sealed class SourceCode {
|
|||||||
/**
|
/**
|
||||||
* filename prefix to designate library files that will be retreived from internal resources rather than disk
|
* filename prefix to designate library files that will be retreived from internal resources rather than disk
|
||||||
*/
|
*/
|
||||||
const val libraryFilePrefix = "library:"
|
private const val LIBRARYFILEPREFIX = "library:"
|
||||||
const val stringSourcePrefix = "string:"
|
private const val STRINGSOURCEPREFIX = "string:"
|
||||||
val curdir: Path = Path(".").toAbsolutePath()
|
val curdir: Path = Path(".").toAbsolutePath()
|
||||||
fun relative(path: Path): Path = curdir.relativize(path.toAbsolutePath())
|
fun relative(path: Path): Path = curdir.relativize(path.toAbsolutePath())
|
||||||
fun isRegularFilesystemPath(pathString: String) =
|
fun isRegularFilesystemPath(pathString: String) = !isLibraryResource(pathString) && !isStringResource(pathString)
|
||||||
!(pathString.startsWith(libraryFilePrefix) || pathString.startsWith(stringSourcePrefix))
|
fun isLibraryResource(path: String) = path.startsWith(LIBRARYFILEPREFIX)
|
||||||
|
fun isStringResource(path: String) = path.startsWith(STRINGSOURCEPREFIX)
|
||||||
|
fun withoutPrefix(path: String): String {
|
||||||
|
return if(isLibraryResource(path))
|
||||||
|
path.removePrefix(LIBRARYFILEPREFIX)
|
||||||
|
else if(isStringResource(path))
|
||||||
|
path.removePrefix(STRINGSOURCEPREFIX)
|
||||||
|
else
|
||||||
|
path
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turn a plain String into a [SourceCode] object.
|
* Turn a plain String into a [SourceCode] object.
|
||||||
* [origin] will be something like `string:44c56085`.
|
* [origin] will be something like `string:44c56085`.
|
||||||
*/
|
*/
|
||||||
class Text(override val text: String): SourceCode() {
|
class Text(origText: String): SourceCode() {
|
||||||
|
override val text = origText.replace("\\R".toRegex(), "\n") // normalize line endings
|
||||||
override val isFromResources = false
|
override val isFromResources = false
|
||||||
override val isFromFilesystem = false
|
override val isFromFilesystem = false
|
||||||
override val origin = "$stringSourcePrefix${System.identityHashCode(text).toString(16)}"
|
override val origin = "$STRINGSOURCEPREFIX${System.identityHashCode(text).toString(16)}"
|
||||||
override val name = "<unnamed-text>"
|
override val name = "<unnamed-text>"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get [SourceCode] from the file represented by the specified Path.
|
* Get [SourceCode] from the file represented by the specified Path.
|
||||||
* This immediately reads the file fully into memory.
|
* This immediately reads the file fully into memory.
|
||||||
|
* You can only get an instance of this via the ImportFileSystem object.
|
||||||
*
|
*
|
||||||
* [origin] will be the given path in absolute and normalized form.
|
* [origin] will be the given path in absolute and normalized form.
|
||||||
* @throws NoSuchFileException if the file does not exist
|
* @throws NoSuchFileException if the file does not exist
|
||||||
* @throws FileSystemException if the file cannot be read
|
* @throws FileSystemException if the file cannot be read
|
||||||
*/
|
*/
|
||||||
class File(path: Path): SourceCode() {
|
internal class File(path: Path): SourceCode() {
|
||||||
override val text: String
|
override val text: String
|
||||||
override val origin: String
|
override val origin: String
|
||||||
override val name: String
|
override val name: String
|
||||||
@ -92,7 +99,8 @@ sealed class SourceCode {
|
|||||||
val normalized = path.normalize()
|
val normalized = path.normalize()
|
||||||
origin = relative(normalized).toString()
|
origin = relative(normalized).toString()
|
||||||
try {
|
try {
|
||||||
text = normalized.readText()
|
val contents = Normalizer.normalize(normalized.readText(), Normalizer.Form.NFC)
|
||||||
|
text = contents.replace("\\R".toRegex(), "\n") // normalize line endings
|
||||||
name = normalized.toFile().nameWithoutExtension
|
name = normalized.toFile().nameWithoutExtension
|
||||||
} catch (nfx: java.nio.file.NoSuchFileException) {
|
} catch (nfx: java.nio.file.NoSuchFileException) {
|
||||||
throw NoSuchFileException(normalized.toFile()).also { it.initCause(nfx) }
|
throw NoSuchFileException(normalized.toFile()).also { it.initCause(nfx) }
|
||||||
@ -104,13 +112,14 @@ sealed class SourceCode {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* [origin]: `library:/x/y/z.p8` for a given `pathString` of "x/y/z.p8"
|
* [origin]: `library:/x/y/z.p8` for a given `pathString` of "x/y/z.p8"
|
||||||
|
* You can only get an instance of this via the ImportFileSystem object.
|
||||||
*/
|
*/
|
||||||
class Resource(pathString: String): SourceCode() {
|
internal class Resource(pathString: String): SourceCode() {
|
||||||
private val normalized = "/" + Path(pathString).normalize().toMutableList().joinToString("/")
|
private val normalized = "/" + Path(pathString).normalize().toMutableList().joinToString("/")
|
||||||
|
|
||||||
override val isFromResources = true
|
override val isFromResources = true
|
||||||
override val isFromFilesystem = false
|
override val isFromFilesystem = false
|
||||||
override val origin = "$libraryFilePrefix$normalized"
|
override val origin = "$LIBRARYFILEPREFIX$normalized"
|
||||||
override val text: String
|
override val text: String
|
||||||
override val name: String
|
override val name: String
|
||||||
|
|
||||||
@ -119,12 +128,13 @@ sealed class SourceCode {
|
|||||||
if (rscURL == null) {
|
if (rscURL == null) {
|
||||||
val rscRoot = object {}.javaClass.getResource("/")
|
val rscRoot = object {}.javaClass.getResource("/")
|
||||||
throw NoSuchFileException(
|
throw NoSuchFileException(
|
||||||
File(normalized),
|
java.io.File(normalized),
|
||||||
reason = "looked in resources rooted at $rscRoot"
|
reason = "looked in resources rooted at $rscRoot"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val stream = object {}.javaClass.getResourceAsStream(normalized)
|
val stream = object {}.javaClass.getResourceAsStream(normalized)
|
||||||
text = stream!!.reader().use { it.readText() }
|
val contents = stream!!.reader().use { Normalizer.normalize(it.readText(), Normalizer.Form.NFC) }
|
||||||
|
text = contents.replace("\\R".toRegex(), "\n") // normalize line endings
|
||||||
name = Path(pathString).toFile().nameWithoutExtension
|
name = Path(pathString).toFile().nameWithoutExtension
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,4 +148,4 @@ sealed class SourceCode {
|
|||||||
override val origin: String = name
|
override val origin: String = name
|
||||||
override val text: String = "<generated code node, no text representation>"
|
override val text: String = "<generated code node, no text representation>"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,22 +7,31 @@ import prog8.code.target.atari.AtariMachineDefinition
|
|||||||
class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
||||||
override val name = NAME
|
override val name = NAME
|
||||||
override val machine = AtariMachineDefinition()
|
override val machine = AtariMachineDefinition()
|
||||||
override val supportedEncodings = setOf(Encoding.ATASCII)
|
|
||||||
override val defaultEncoding = Encoding.ATASCII
|
override val defaultEncoding = Encoding.ATASCII
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val NAME = "atari"
|
const val NAME = "atari"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun memorySize(dt: DataType): Int {
|
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||||
return when(dt) {
|
if(dt.isArray) {
|
||||||
in ByteDatatypes -> 1
|
require(numElements!=null)
|
||||||
in WordDatatypes, in PassByReferenceDatatypes -> 2
|
return when(dt.sub?.dt) {
|
||||||
DataType.FLOAT -> machine.FLOAT_MEM_SIZE
|
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||||
else -> Int.MIN_VALUE
|
BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2
|
||||||
|
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE
|
||||||
|
else -> throw IllegalArgumentException("invalid sub type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return when {
|
||||||
|
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||||
|
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||||
|
else -> 2 * (numElements ?: 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun memorySize(arrayDt: DataType, numElements: Int) =
|
override fun memorySize(dt: SubType): Int {
|
||||||
memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
|
return memorySize(DataType.forDt(dt.dt), null)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import prog8.code.target.cbm.CbmMemorySizer
|
|||||||
class C128Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
class C128Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
||||||
override val name = NAME
|
override val name = NAME
|
||||||
override val machine = C128MachineDefinition()
|
override val machine = C128MachineDefinition()
|
||||||
override val supportedEncodings = setOf(Encoding.PETSCII, Encoding.SCREENCODES)
|
|
||||||
override val defaultEncoding = Encoding.PETSCII
|
override val defaultEncoding = Encoding.PETSCII
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -11,10 +11,33 @@ import prog8.code.target.cbm.CbmMemorySizer
|
|||||||
class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
||||||
override val name = NAME
|
override val name = NAME
|
||||||
override val machine = C64MachineDefinition()
|
override val machine = C64MachineDefinition()
|
||||||
override val supportedEncodings = setOf(Encoding.PETSCII, Encoding.SCREENCODES)
|
|
||||||
override val defaultEncoding = Encoding.PETSCII
|
override val defaultEncoding = Encoding.PETSCII
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val NAME = "c64"
|
const val NAME = "c64"
|
||||||
|
|
||||||
|
fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val CompilationTargets = listOf(
|
||||||
|
C64Target.NAME,
|
||||||
|
C128Target.NAME,
|
||||||
|
Cx16Target.NAME,
|
||||||
|
PETTarget.NAME,
|
||||||
|
AtariTarget.NAME,
|
||||||
|
Neo6502Target.NAME,
|
||||||
|
VMTarget.NAME
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getCompilationTargetByName(name: String) = when(name.lowercase()) {
|
||||||
|
C64Target.NAME -> C64Target()
|
||||||
|
C128Target.NAME -> C128Target()
|
||||||
|
Cx16Target.NAME -> Cx16Target()
|
||||||
|
PETTarget.NAME -> PETTarget()
|
||||||
|
AtariTarget.NAME -> AtariTarget()
|
||||||
|
VMTarget.NAME -> VMTarget()
|
||||||
|
Neo6502Target.NAME -> Neo6502Target()
|
||||||
|
else -> throw IllegalArgumentException("invalid compilation target")
|
||||||
|
}
|
||||||
|
@ -11,7 +11,6 @@ import prog8.code.target.cx16.CX16MachineDefinition
|
|||||||
class Cx16Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
class Cx16Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
||||||
override val name = NAME
|
override val name = NAME
|
||||||
override val machine = CX16MachineDefinition()
|
override val machine = CX16MachineDefinition()
|
||||||
override val supportedEncodings = setOf(Encoding.PETSCII, Encoding.SCREENCODES, Encoding.ISO)
|
|
||||||
override val defaultEncoding = Encoding.PETSCII
|
override val defaultEncoding = Encoding.PETSCII
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -4,18 +4,22 @@ import com.github.michaelbull.result.fold
|
|||||||
import prog8.code.core.Encoding
|
import prog8.code.core.Encoding
|
||||||
import prog8.code.core.IStringEncoding
|
import prog8.code.core.IStringEncoding
|
||||||
import prog8.code.core.InternalCompilerException
|
import prog8.code.core.InternalCompilerException
|
||||||
import prog8.code.target.cbm.AtasciiEncoding
|
import prog8.code.target.encodings.*
|
||||||
import prog8.code.target.cbm.IsoEncoding
|
|
||||||
import prog8.code.target.cbm.PetsciiEncoding
|
|
||||||
|
|
||||||
|
|
||||||
object Encoder: IStringEncoding {
|
object Encoder: IStringEncoding {
|
||||||
|
override val defaultEncoding: Encoding = Encoding.ISO
|
||||||
|
|
||||||
override fun encodeString(str: String, encoding: Encoding): List<UByte> {
|
override fun encodeString(str: String, encoding: Encoding): List<UByte> {
|
||||||
val coded = when(encoding) {
|
val coded = when(encoding) {
|
||||||
Encoding.PETSCII -> PetsciiEncoding.encodePetscii(str, true)
|
Encoding.PETSCII -> PetsciiEncoding.encodePetscii(str, true)
|
||||||
Encoding.SCREENCODES -> PetsciiEncoding.encodeScreencode(str, true)
|
Encoding.SCREENCODES -> PetsciiEncoding.encodeScreencode(str, true)
|
||||||
Encoding.ISO -> IsoEncoding.encode(str)
|
Encoding.ISO -> IsoEncoding.encode(str)
|
||||||
Encoding.ATASCII -> AtasciiEncoding.encode(str)
|
Encoding.ATASCII -> AtasciiEncoding.encode(str)
|
||||||
|
Encoding.ISO5 -> IsoCyrillicEncoding.encode(str)
|
||||||
|
Encoding.ISO16 -> IsoEasternEncoding.encode(str)
|
||||||
|
Encoding.CP437 -> Cp437Encoding.encode(str)
|
||||||
|
Encoding.KATAKANA -> KatakanaEncoding.encode(str)
|
||||||
else -> throw InternalCompilerException("unsupported encoding $encoding")
|
else -> throw InternalCompilerException("unsupported encoding $encoding")
|
||||||
}
|
}
|
||||||
return coded.fold(
|
return coded.fold(
|
||||||
@ -23,12 +27,16 @@ object Encoder: IStringEncoding {
|
|||||||
success = { it }
|
success = { it }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String {
|
override fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String {
|
||||||
val decoded = when(encoding) {
|
val decoded = when(encoding) {
|
||||||
Encoding.PETSCII -> PetsciiEncoding.decodePetscii(bytes, true)
|
Encoding.PETSCII -> PetsciiEncoding.decodePetscii(bytes, true)
|
||||||
Encoding.SCREENCODES -> PetsciiEncoding.decodeScreencode(bytes, true)
|
Encoding.SCREENCODES -> PetsciiEncoding.decodeScreencode(bytes, true)
|
||||||
Encoding.ISO -> IsoEncoding.decode(bytes)
|
Encoding.ISO -> IsoEncoding.decode(bytes)
|
||||||
Encoding.ATASCII -> AtasciiEncoding.decode(bytes)
|
Encoding.ATASCII -> AtasciiEncoding.decode(bytes)
|
||||||
|
Encoding.ISO5 -> IsoCyrillicEncoding.decode(bytes)
|
||||||
|
Encoding.ISO16 -> IsoEasternEncoding.decode(bytes)
|
||||||
|
Encoding.CP437 -> Cp437Encoding.decode(bytes)
|
||||||
|
Encoding.KATAKANA -> KatakanaEncoding.decode(bytes)
|
||||||
else -> throw InternalCompilerException("unsupported encoding $encoding")
|
else -> throw InternalCompilerException("unsupported encoding $encoding")
|
||||||
}
|
}
|
||||||
return decoded.fold(
|
return decoded.fold(
|
||||||
|
37
codeCore/src/prog8/code/target/Neo6502Target.kt
Normal file
37
codeCore/src/prog8/code/target/Neo6502Target.kt
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package prog8.code.target
|
||||||
|
|
||||||
|
import prog8.code.core.*
|
||||||
|
import prog8.code.target.neo6502.Neo6502MachineDefinition
|
||||||
|
|
||||||
|
|
||||||
|
class Neo6502Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
||||||
|
override val name = NAME
|
||||||
|
override val machine = Neo6502MachineDefinition()
|
||||||
|
override val defaultEncoding = Encoding.ISO
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "neo"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||||
|
if(dt.isArray) {
|
||||||
|
require(numElements!=null)
|
||||||
|
return when(dt.sub?.dt) {
|
||||||
|
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||||
|
BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2
|
||||||
|
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE
|
||||||
|
else -> throw IllegalArgumentException("invalid sub type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return when {
|
||||||
|
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||||
|
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||||
|
else -> 2 * (numElements ?: 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun memorySize(dt: SubType): Int {
|
||||||
|
return memorySize(DataType.forDt(dt.dt), null)
|
||||||
|
}
|
||||||
|
}
|
19
codeCore/src/prog8/code/target/PETTarget.kt
Normal file
19
codeCore/src/prog8/code/target/PETTarget.kt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package prog8.code.target
|
||||||
|
|
||||||
|
import prog8.code.core.Encoding
|
||||||
|
import prog8.code.core.ICompilationTarget
|
||||||
|
import prog8.code.core.IMemSizer
|
||||||
|
import prog8.code.core.IStringEncoding
|
||||||
|
import prog8.code.target.cbm.CbmMemorySizer
|
||||||
|
import prog8.code.target.pet.PETMachineDefinition
|
||||||
|
|
||||||
|
|
||||||
|
class PETTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
||||||
|
override val name = NAME
|
||||||
|
override val machine = PETMachineDefinition()
|
||||||
|
override val defaultEncoding = Encoding.PETSCII
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "pet32"
|
||||||
|
}
|
||||||
|
}
|
@ -6,22 +6,31 @@ import prog8.code.target.virtual.VirtualMachineDefinition
|
|||||||
class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
||||||
override val name = NAME
|
override val name = NAME
|
||||||
override val machine = VirtualMachineDefinition()
|
override val machine = VirtualMachineDefinition()
|
||||||
override val supportedEncodings = setOf(Encoding.ISO)
|
|
||||||
override val defaultEncoding = Encoding.ISO
|
override val defaultEncoding = Encoding.ISO
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val NAME = "virtual"
|
const val NAME = "virtual"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun memorySize(dt: DataType): Int {
|
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||||
return when(dt) {
|
if(dt.isArray) {
|
||||||
in ByteDatatypes -> 1
|
require(numElements!=null)
|
||||||
in WordDatatypes, in PassByReferenceDatatypes -> 2
|
return when(dt.sub?.dt) {
|
||||||
DataType.FLOAT -> machine.FLOAT_MEM_SIZE
|
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||||
else -> Int.MIN_VALUE
|
BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2
|
||||||
|
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE
|
||||||
|
else -> throw IllegalArgumentException("invalid sub type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return when {
|
||||||
|
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||||
|
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||||
|
else -> 2 * (numElements ?: 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun memorySize(arrayDt: DataType, numElements: Int) =
|
override fun memorySize(dt: SubType): Int {
|
||||||
memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
|
return memorySize(DataType.forDt(dt.dt), null)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package prog8.code.target.atari
|
package prog8.code.target.atari
|
||||||
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.code.target.c64.normal6502instructions
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
|
||||||
@ -12,22 +11,21 @@ class AtariMachineDefinition: IMachineDefinition {
|
|||||||
override val FLOAT_MAX_POSITIVE = 9.999999999e97
|
override val FLOAT_MAX_POSITIVE = 9.999999999e97
|
||||||
override val FLOAT_MAX_NEGATIVE = -9.999999999e97
|
override val FLOAT_MAX_NEGATIVE = -9.999999999e97
|
||||||
override val FLOAT_MEM_SIZE = 6
|
override val FLOAT_MEM_SIZE = 6
|
||||||
|
override val STARTUP_CODE_RESERVED_SIZE = 20u
|
||||||
override val PROGRAM_LOAD_ADDRESS = 0x2000u
|
override val PROGRAM_LOAD_ADDRESS = 0x2000u
|
||||||
|
override val PROGRAM_MEMTOP_ADDRESS = 0xffffu // TODO what's memtop?
|
||||||
|
|
||||||
// the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations)
|
override val BSSHIGHRAM_START = 0u // TODO
|
||||||
override var ESTACK_LO = 0x1a00u // $1a00-$1aff inclusive // TODO
|
override val BSSHIGHRAM_END = 0u // TODO
|
||||||
override var ESTACK_HI = 0x1b00u // $1b00-$1bff inclusive // TODO
|
override val BSSGOLDENRAM_START = 0u // TODO
|
||||||
|
override val BSSGOLDENRAM_END = 0u // TODO
|
||||||
|
|
||||||
override lateinit var zeropage: Zeropage
|
override lateinit var zeropage: Zeropage
|
||||||
|
override lateinit var golden: GoldenRam
|
||||||
|
|
||||||
override fun getFloatAsmBytes(num: Number) = TODO("float asm bytes from number")
|
override fun getFloatAsmBytes(num: Number) = TODO("atari float asm bytes from number")
|
||||||
|
override fun convertFloatToBytes(num: Double): List<UByte> = TODO("atari float to bytes")
|
||||||
override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List<String> {
|
override fun convertBytesToFloat(bytes: List<UByte>): Double = TODO("atari bytes to float")
|
||||||
return if (compilerOptions.output == OutputType.XEX)
|
|
||||||
listOf("syslib")
|
|
||||||
else
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||||
val emulatorName: String
|
val emulatorName: String
|
||||||
@ -57,9 +55,8 @@ class AtariMachineDefinition: IMachineDefinition {
|
|||||||
|
|
||||||
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu // TODO
|
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu // TODO
|
||||||
|
|
||||||
override fun initializeZeropage(compilerOptions: CompilationOptions) {
|
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||||
zeropage = AtariZeropage(compilerOptions)
|
zeropage = AtariZeropage(compilerOptions)
|
||||||
|
golden = GoldenRam(compilerOptions, UIntRange.EMPTY)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val opcodeNames = normal6502instructions
|
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,10 @@ class AtariZeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
override val SCRATCH_W2 = 0xcfu // temp storage 2 for a word $cf+$d0 TODO is $d0 okay to use?
|
override val SCRATCH_W2 = 0xcfu // temp storage 2 for a word $cf+$d0 TODO is $d0 okay to use?
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
if (options.floats) {
|
||||||
|
throw InternalCompilerException("Atari target doesn't yet support floating point routines")
|
||||||
|
}
|
||||||
|
|
||||||
if (options.floats && options.zeropage !in arrayOf(
|
if (options.floats && options.zeropage !in arrayOf(
|
||||||
ZeropageType.FLOATSAFE,
|
ZeropageType.FLOATSAFE,
|
||||||
ZeropageType.BASICSAFE,
|
ZeropageType.BASICSAFE,
|
||||||
@ -24,7 +28,7 @@ class AtariZeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
ZeropageType.FULL -> {
|
ZeropageType.FULL -> {
|
||||||
// TODO all atari usable zero page locations, except the ones used by the system's IRQ routine
|
// TODO all atari usable zero page locations, except the ones used by the system's IRQ routine
|
||||||
free.addAll(0x00u..0xffu)
|
free.addAll(0x00u..0xffu)
|
||||||
// TODO atari free.removeAll(setOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
// TODO atari free.removeAll(arrayOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
||||||
}
|
}
|
||||||
ZeropageType.KERNALSAFE -> {
|
ZeropageType.KERNALSAFE -> {
|
||||||
free.addAll(0x80u..0xffu) // TODO
|
free.addAll(0x80u..0xffu) // TODO
|
||||||
@ -39,11 +43,12 @@ class AtariZeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val distictFree = free.distinct()
|
val distinctFree = free.distinct()
|
||||||
free.clear()
|
free.clear()
|
||||||
free.addAll(distictFree)
|
free.addAll(distinctFree)
|
||||||
|
|
||||||
removeReservedFromFreePool()
|
removeReservedFromFreePool()
|
||||||
|
retainAllowed()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun allocateCx16VirtualRegisters() {
|
override fun allocateCx16VirtualRegisters() {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package prog8.code.target.c128
|
package prog8.code.target.c128
|
||||||
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.code.target.c64.normal6502instructions
|
import prog8.code.target.C64Target
|
||||||
import prog8.code.target.cbm.Mflpt5
|
import prog8.code.target.cbm.Mflpt5
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
@ -13,21 +13,29 @@ class C128MachineDefinition: IMachineDefinition {
|
|||||||
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
|
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
|
||||||
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
|
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
|
||||||
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
||||||
|
override val STARTUP_CODE_RESERVED_SIZE = 20u
|
||||||
override val PROGRAM_LOAD_ADDRESS = 0x1c01u
|
override val PROGRAM_LOAD_ADDRESS = 0x1c01u
|
||||||
|
override val PROGRAM_MEMTOP_ADDRESS = 0xff00u
|
||||||
|
|
||||||
// the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations)
|
override val BSSHIGHRAM_START = 0u // TODO
|
||||||
override var ESTACK_LO = 0x1a00u // $1a00-$1aff inclusive
|
override val BSSHIGHRAM_END = 0u // TODO
|
||||||
override var ESTACK_HI = 0x1b00u // $1b00-$1bff inclusive
|
override val BSSGOLDENRAM_START = 0u // TODO
|
||||||
|
override val BSSGOLDENRAM_END = 0u // TODO
|
||||||
|
|
||||||
override lateinit var zeropage: Zeropage
|
override lateinit var zeropage: Zeropage
|
||||||
|
override lateinit var golden: GoldenRam
|
||||||
|
|
||||||
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
|
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
|
||||||
|
|
||||||
override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List<String> {
|
override fun convertFloatToBytes(num: Double): List<UByte> {
|
||||||
return if (compilerOptions.launcher == CbmPrgLauncherType.BASIC || compilerOptions.output == OutputType.PRG)
|
val m5 = Mflpt5.fromNumber(num)
|
||||||
listOf("syslib")
|
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||||
else
|
}
|
||||||
emptyList()
|
|
||||||
|
override fun convertBytesToFloat(bytes: List<UByte>): Double {
|
||||||
|
require(bytes.size==5) { "need 5 bytes" }
|
||||||
|
val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
|
||||||
|
return m5.toDouble()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||||
@ -37,7 +45,7 @@ class C128MachineDefinition: IMachineDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
println("\nStarting C-128 emulator x128...")
|
println("\nStarting C-128 emulator x128...")
|
||||||
val viceMonlist = viceMonListName(programNameWithPath.toString())
|
val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString())
|
||||||
val cmdline = listOf("x128", "-silent", "-moncommands", viceMonlist,
|
val cmdline = listOf("x128", "-silent", "-moncommands", viceMonlist,
|
||||||
"-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
|
"-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
|
||||||
val processb = ProcessBuilder(cmdline).inheritIO()
|
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||||
@ -47,9 +55,8 @@ class C128MachineDefinition: IMachineDefinition {
|
|||||||
|
|
||||||
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
|
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
|
||||||
|
|
||||||
override fun initializeZeropage(compilerOptions: CompilationOptions) {
|
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||||
zeropage = C128Zeropage(compilerOptions)
|
zeropage = C128Zeropage(compilerOptions)
|
||||||
|
golden = GoldenRam(compilerOptions, UIntRange.EMPTY) // TODO does the c128 have some of this somewhere?
|
||||||
}
|
}
|
||||||
|
|
||||||
override val opcodeNames = normal6502instructions
|
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,22 @@ import prog8.code.core.Zeropage
|
|||||||
import prog8.code.core.ZeropageType
|
import prog8.code.core.ZeropageType
|
||||||
|
|
||||||
|
|
||||||
|
// reference: "Mapping the C128" zeropage chapter.
|
||||||
|
|
||||||
class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
|
class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||||
|
|
||||||
override val SCRATCH_B1 = 0x9bu // temp storage for a single byte
|
override val SCRATCH_B1 = 0x74u // temp storage for a single byte
|
||||||
override val SCRATCH_REG = 0x9cu // temp storage for a register, must be B1+1
|
override val SCRATCH_REG = 0x75u // temp storage for a register, must be B1+1
|
||||||
override val SCRATCH_W1 = 0xfbu // temp storage 1 for a word $fb+$fc
|
override val SCRATCH_W1 = 0xfbu // temp storage 1 for a word $fb+$fc
|
||||||
override val SCRATCH_W2 = 0xfdu // temp storage 2 for a word $fd+$fe
|
override val SCRATCH_W2 = 0xfdu // temp storage 2 for a word $fd+$fe
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
if (options.floats) {
|
||||||
|
throw InternalCompilerException("C128 target doesn't yet support floating point routines")
|
||||||
|
// note: in git commit labeled 'c128: remove floats module' the floats.p8 and floats.asm files are removed,
|
||||||
|
// they could be retrieved again at a later time if the compiler somehow *does* store the fp variables in bank1.
|
||||||
|
}
|
||||||
|
|
||||||
if (options.floats && options.zeropage !in arrayOf(
|
if (options.floats && options.zeropage !in arrayOf(
|
||||||
ZeropageType.FLOATSAFE,
|
ZeropageType.FLOATSAFE,
|
||||||
ZeropageType.BASICSAFE,
|
ZeropageType.BASICSAFE,
|
||||||
@ -24,25 +31,45 @@ class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
|
|
||||||
when (options.zeropage) {
|
when (options.zeropage) {
|
||||||
ZeropageType.FULL -> {
|
ZeropageType.FULL -> {
|
||||||
// TODO all c128 usable zero page locations, except the ones used by the system's IRQ routine
|
// $00/$01 are data port IO registers, // $02-$09 are storage locations for JSRFAR and such
|
||||||
free.addAll(0x0au..0xffu) // TODO c128 what about $02-$09?
|
free.addAll(0x0au..0xffu)
|
||||||
// TODO c128 free.removeAll(setOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
free.removeAll(arrayOf(0x90u, 0x91u, 0xa0u, 0xa1u, 0xa2u, 0xc0u, 0xccu, 0xcdu, 0xd0u, 0xd1u, 0xd2u, 0xd3u, 0xd4u, 0xd5u, 0xf7u)) // these are updated/used by IRQ
|
||||||
|
}
|
||||||
|
ZeropageType.KERNALSAFE -> {
|
||||||
|
free.addAll(0x0au..0x8fu) // BASIC variables
|
||||||
|
free.addAll(arrayOf(0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
|
||||||
|
0xb0u, 0xb1u, 0xb4u, 0xb5u, 0xb6u))
|
||||||
}
|
}
|
||||||
ZeropageType.KERNALSAFE,
|
|
||||||
ZeropageType.FLOATSAFE,
|
ZeropageType.FLOATSAFE,
|
||||||
ZeropageType.BASICSAFE -> {
|
ZeropageType.BASICSAFE -> {
|
||||||
free.clear() // TODO c128 usable zero page addresses
|
free.addAll(arrayOf(0x0bu, 0x0cu, 0x0du, 0x0eu, 0x0fu, 0x10u, 0x11u, 0x12u, 0x16u, 0x17u, 0x18u, 0x19u, 0x1au))
|
||||||
|
free.addAll(0x1bu..0x23u)
|
||||||
|
free.addAll(arrayOf(0x3fu, 0x40u, 0x41u, 0x42u, 0x43u, 0x44u, 0x47u, 0x48u, 0x49u, 0x4au, 0x4bu, 0x4cu, 0x4fu,
|
||||||
|
0x55u, 0x56u, 0x57u, 0x58u,
|
||||||
|
0x74u, 0x75u, 0x78u, 0x80u, 0x83u, 0x87u, 0x88u, 0x89u, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu,
|
||||||
|
0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
|
||||||
|
0xb0u, 0xb1u, 0xb4u, 0xb5u, 0xb6u
|
||||||
|
))
|
||||||
|
|
||||||
|
// if(options.zeropage==ZeropageType.BASICSAFE) {
|
||||||
|
// can also clobber the FP locations (unconditionally, because the C128 target doesn't support floating point calculations in prog8 at this time0
|
||||||
|
free.addAll(arrayOf(0x14u, 0x28u, 0x29u, 0x2au, 0x2bu, 0x2cu,
|
||||||
|
0x50u, 0x51u, 0x52u, 0x53u, 0x54u, 0x59u, 0x5au, 0x5bu, 0x5cu, 0x5du, 0x5eu, 0x5fu, 0x60u, 0x61u, 0x62u,
|
||||||
|
0x63u, 0x64u, 0x65u, 0x66u, 0x67u, 0x68u,
|
||||||
|
0x6au, 0x6bu, 0x6cu, 0x6du, 0x6eu, 0x6fu, 0x71u))
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
ZeropageType.DONTUSE -> {
|
ZeropageType.DONTUSE -> {
|
||||||
free.clear() // don't use zeropage at all
|
free.clear() // don't use zeropage at all
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val distictFree = free.distinct()
|
val distinctFree = free.distinct()
|
||||||
free.clear()
|
free.clear()
|
||||||
free.addAll(distictFree)
|
free.addAll(distinctFree)
|
||||||
|
|
||||||
removeReservedFromFreePool()
|
removeReservedFromFreePool()
|
||||||
|
retainAllowed()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun allocateCx16VirtualRegisters() {
|
override fun allocateCx16VirtualRegisters() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package prog8.code.target.c64
|
package prog8.code.target.c64
|
||||||
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
import prog8.code.target.C64Target
|
||||||
import prog8.code.target.cbm.Mflpt5
|
import prog8.code.target.cbm.Mflpt5
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -13,21 +14,30 @@ class C64MachineDefinition: IMachineDefinition {
|
|||||||
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
|
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
|
||||||
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
|
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
|
||||||
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
||||||
|
override val STARTUP_CODE_RESERVED_SIZE = 20u
|
||||||
override val PROGRAM_LOAD_ADDRESS = 0x0801u
|
override val PROGRAM_LOAD_ADDRESS = 0x0801u
|
||||||
|
override val PROGRAM_MEMTOP_ADDRESS = 0xcfe0u // $a000 if floats are used
|
||||||
|
// note that at $cfe0-$cfff are the 16 'virtual registers' R0-R15
|
||||||
|
|
||||||
// the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations)
|
override val BSSHIGHRAM_START = 0xc000u
|
||||||
override var ESTACK_LO = 0xce00u // $ce00-$ceff inclusive
|
override val BSSHIGHRAM_END = 0xcfffu
|
||||||
override var ESTACK_HI = 0xcf00u // $ce00-$ceff inclusive
|
override val BSSGOLDENRAM_START = 0u
|
||||||
|
override val BSSGOLDENRAM_END = 0u
|
||||||
|
|
||||||
override lateinit var zeropage: Zeropage
|
override lateinit var zeropage: Zeropage
|
||||||
|
override lateinit var golden: GoldenRam
|
||||||
|
|
||||||
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
|
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
|
||||||
|
|
||||||
override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List<String> {
|
override fun convertFloatToBytes(num: Double): List<UByte> {
|
||||||
return if (compilerOptions.launcher == CbmPrgLauncherType.BASIC || compilerOptions.output == OutputType.PRG)
|
val m5 = Mflpt5.fromNumber(num)
|
||||||
listOf("syslib")
|
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||||
else
|
}
|
||||||
emptyList()
|
|
||||||
|
override fun convertBytesToFloat(bytes: List<UByte>): Double {
|
||||||
|
require(bytes.size==5) { "need 5 bytes" }
|
||||||
|
val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
|
||||||
|
return m5.toDouble()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||||
@ -38,14 +48,14 @@ class C64MachineDefinition: IMachineDefinition {
|
|||||||
|
|
||||||
for(emulator in listOf("x64sc", "x64")) {
|
for(emulator in listOf("x64sc", "x64")) {
|
||||||
println("\nStarting C-64 emulator $emulator...")
|
println("\nStarting C-64 emulator $emulator...")
|
||||||
val viceMonlist = viceMonListName(programNameWithPath.toString())
|
val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString())
|
||||||
val cmdline = listOf(emulator, "-silent", "-moncommands", viceMonlist,
|
val cmdline = listOf(emulator, "-silent", "-moncommands", viceMonlist,
|
||||||
"-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
|
"-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
|
||||||
val processb = ProcessBuilder(cmdline).inheritIO()
|
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||||
val process: Process
|
val process: Process
|
||||||
try {
|
try {
|
||||||
process=processb.start()
|
process=processb.start()
|
||||||
} catch(x: IOException) {
|
} catch(_: IOException) {
|
||||||
continue // try the next emulator executable
|
continue // try the next emulator executable
|
||||||
}
|
}
|
||||||
process.waitFor()
|
process.waitFor()
|
||||||
@ -55,22 +65,9 @@ class C64MachineDefinition: IMachineDefinition {
|
|||||||
|
|
||||||
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
|
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
|
||||||
|
|
||||||
override fun initializeZeropage(compilerOptions: CompilationOptions) {
|
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||||
zeropage = C64Zeropage(compilerOptions)
|
zeropage = C64Zeropage(compilerOptions)
|
||||||
|
golden = GoldenRam(compilerOptions, 0xc000u until 0xd000u)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val opcodeNames = normal6502instructions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 6502 opcodes (including aliases and illegal opcodes), these cannot be used as variable or label names
|
|
||||||
internal val normal6502instructions = setOf(
|
|
||||||
"adc", "ahx", "alr", "anc", "and", "ane", "arr", "asl", "asr", "axs", "bcc", "bcs",
|
|
||||||
"beq", "bge", "bit", "blt", "bmi", "bne", "bpl", "brk", "bvc", "bvs", "clc",
|
|
||||||
"cld", "cli", "clv", "cmp", "cpx", "cpy", "dcm", "dcp", "dec", "dex", "dey",
|
|
||||||
"eor", "gcc", "gcs", "geq", "gge", "glt", "gmi", "gne", "gpl", "gvc", "gvs",
|
|
||||||
"inc", "ins", "inx", "iny", "isb", "isc", "jam", "jmp", "jsr", "lae", "las",
|
|
||||||
"lax", "lda", "lds", "ldx", "ldy", "lsr", "lxa", "nop", "ora", "pha", "php",
|
|
||||||
"pla", "plp", "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", "sbx",
|
|
||||||
"sec", "sed", "sei", "sha", "shl", "shr", "shs", "shx", "shy", "slo", "sre",
|
|
||||||
"sta", "stx", "sty", "tas", "tax", "tay", "tsx", "txa", "txs", "tya", "xaa")
|
|
@ -21,11 +21,11 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
|
|
||||||
if (options.zeropage == ZeropageType.FULL) {
|
if (options.zeropage == ZeropageType.FULL) {
|
||||||
free.addAll(0x02u..0xffu)
|
free.addAll(0x02u..0xffu)
|
||||||
free.removeAll(setOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1+1u, SCRATCH_W2, SCRATCH_W2+1u))
|
free.removeAll(arrayOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1+1u, SCRATCH_W2, SCRATCH_W2+1u))
|
||||||
free.removeAll(setOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
free.removeAll(arrayOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
||||||
} else {
|
} else {
|
||||||
if (options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
|
if (options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
|
||||||
free.addAll(listOf(
|
free.addAll(arrayOf(
|
||||||
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
||||||
@ -43,8 +43,8 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
|
|
||||||
if (options.zeropage == ZeropageType.FLOATSAFE) {
|
if (options.zeropage == ZeropageType.FLOATSAFE) {
|
||||||
// remove the zeropage locations used for floating point operations from the free list
|
// remove the zeropage locations used for floating point operations from the free list
|
||||||
free.removeAll(listOf(
|
free.removeAll(arrayOf(
|
||||||
0x03, 0x04, 0x10, 0x11, 0x12,
|
0x03, 0x04, 0x05, 0x06, 0x10, 0x11, 0x12,
|
||||||
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
|
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
|
||||||
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
|
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
|
||||||
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
||||||
@ -53,11 +53,11 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
).map{it.toUInt()})
|
).map{it.toUInt()})
|
||||||
}
|
}
|
||||||
|
|
||||||
if(options.zeropage!= ZeropageType.DONTUSE) {
|
if(options.zeropage != ZeropageType.DONTUSE) {
|
||||||
// add the free Zp addresses
|
// add the free Zp addresses
|
||||||
// these are valid for the C-64 but allow BASIC to keep running fully *as long as you don't use tape I/O*
|
// these are valid for the C-64 but allow BASIC to keep running fully *as long as you don't use tape I/O*
|
||||||
free.addAll(listOf(0x02, 0x03, 0x04, 0x05, 0x06, 0x0a, 0x0e,
|
free.addAll(arrayOf(0x02, 0x03, 0x04, 0x05, 0x06, 0x0a, 0x0e,
|
||||||
0x92, 0x96, 0x9b, 0x9c, 0x9e, 0x9f, 0xa5, 0xa6,
|
0x92, 0x96, 0x9b, 0x9c, 0x9e, 0x9f, 0xa6,
|
||||||
0xb0, 0xb1, 0xbe, 0xbf, 0xf9).map{it.toUInt()})
|
0xb0, 0xb1, 0xbe, 0xbf, 0xf9).map{it.toUInt()})
|
||||||
} else {
|
} else {
|
||||||
// don't use the zeropage at all
|
// don't use the zeropage at all
|
||||||
@ -65,9 +65,9 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val distictFree = free.distinct()
|
val distinctFree = free.distinct()
|
||||||
free.clear()
|
free.clear()
|
||||||
free.addAll(distictFree)
|
free.addAll(distinctFree)
|
||||||
|
|
||||||
removeReservedFromFreePool()
|
removeReservedFromFreePool()
|
||||||
|
|
||||||
@ -75,20 +75,22 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
// in these cases there is enough space on the zero page to stick the cx16 virtual registers in there as well.
|
// in these cases there is enough space on the zero page to stick the cx16 virtual registers in there as well.
|
||||||
allocateCx16VirtualRegisters()
|
allocateCx16VirtualRegisters()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retainAllowed()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun allocateCx16VirtualRegisters() {
|
override fun allocateCx16VirtualRegisters() {
|
||||||
// Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
|
// Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
|
||||||
// However, to be able for the compiler to "see" them as zero page variables, we have to register them here as well.
|
// However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well.
|
||||||
// This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
|
// This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
|
||||||
// The base addres is $04. Unfortunately it cannot be the same as on the Commander X16 ($02).
|
// The base addres is $04. Unfortunately it cannot be the same as on the Commander X16 ($02).
|
||||||
for(reg in 0..15) {
|
for(reg in 0..15) {
|
||||||
allocatedVariables[listOf("cx16", "r${reg}")] = ZpAllocation((4+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15
|
allocatedVariables["cx16.r${reg}"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15
|
||||||
allocatedVariables[listOf("cx16", "r${reg}s")] = ZpAllocation((4+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s
|
allocatedVariables["cx16.r${reg}s"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s
|
||||||
allocatedVariables[listOf("cx16", "r${reg}L")] = ZpAllocation((4+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L
|
allocatedVariables["cx16.r${reg}L"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L
|
||||||
allocatedVariables[listOf("cx16", "r${reg}H")] = ZpAllocation((5+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H
|
allocatedVariables["cx16.r${reg}H"] = VarAllocation((5+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H
|
||||||
allocatedVariables[listOf("cx16", "r${reg}sL")] = ZpAllocation((4+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL
|
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL
|
||||||
allocatedVariables[listOf("cx16", "r${reg}sH")] = ZpAllocation((5+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH
|
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((5+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH
|
||||||
free.remove((4+reg*2).toUInt())
|
free.remove((4+reg*2).toUInt())
|
||||||
free.remove((5+reg*2).toUInt())
|
free.remove((5+reg*2).toUInt())
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,30 @@
|
|||||||
package prog8.code.target.cbm
|
package prog8.code.target.cbm
|
||||||
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.BaseDataType
|
||||||
|
import prog8.code.core.DataType
|
||||||
|
import prog8.code.core.IMemSizer
|
||||||
|
import prog8.code.core.SubType
|
||||||
|
|
||||||
|
|
||||||
internal object CbmMemorySizer: IMemSizer {
|
internal object CbmMemorySizer: IMemSizer {
|
||||||
override fun memorySize(dt: DataType): Int {
|
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||||
return when(dt) {
|
if(dt.isArray) {
|
||||||
in ByteDatatypes -> 1
|
require(numElements!=null)
|
||||||
in WordDatatypes, in PassByReferenceDatatypes -> 2
|
return when(dt.sub?.dt) {
|
||||||
DataType.FLOAT -> Mflpt5.FLOAT_MEM_SIZE
|
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||||
else -> Int.MIN_VALUE
|
BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2
|
||||||
|
BaseDataType.FLOAT-> numElements * Mflpt5.FLOAT_MEM_SIZE
|
||||||
|
else -> throw IllegalArgumentException("invalid sub type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return when {
|
||||||
|
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||||
|
dt.isFloat -> Mflpt5.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||||
|
else -> 2 * (numElements ?: 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun memorySize(arrayDt: DataType, numElements: Int) =
|
override fun memorySize(dt: SubType): Int {
|
||||||
memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
|
return memorySize(DataType.forDt(dt.dt), null)
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package prog8.code.target.cx16
|
package prog8.code.target.cx16
|
||||||
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
import prog8.code.target.C64Target
|
||||||
import prog8.code.target.cbm.Mflpt5
|
import prog8.code.target.cbm.Mflpt5
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
@ -12,20 +13,29 @@ class CX16MachineDefinition: IMachineDefinition {
|
|||||||
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
|
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
|
||||||
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
|
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
|
||||||
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
||||||
|
override val STARTUP_CODE_RESERVED_SIZE = 20u
|
||||||
override val PROGRAM_LOAD_ADDRESS = 0x0801u
|
override val PROGRAM_LOAD_ADDRESS = 0x0801u
|
||||||
|
override val PROGRAM_MEMTOP_ADDRESS = 0x9f00u
|
||||||
|
|
||||||
// the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations)
|
override val BSSHIGHRAM_START = 0xa000u // hiram bank 1, 8Kb, assumed to be active
|
||||||
override var ESTACK_LO = 0x0400u // $0400-$04ff inclusive
|
override val BSSHIGHRAM_END = 0xbfffu // Rom starts at $c000
|
||||||
override var ESTACK_HI = 0x0500u // $0500-$05ff inclusive
|
override val BSSGOLDENRAM_START = 0x0400u
|
||||||
|
override val BSSGOLDENRAM_END = 0x07ffu
|
||||||
|
|
||||||
override lateinit var zeropage: Zeropage
|
override lateinit var zeropage: Zeropage
|
||||||
|
override lateinit var golden: GoldenRam
|
||||||
|
|
||||||
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
|
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
|
||||||
override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List<String> {
|
|
||||||
return if (compilerOptions.launcher == CbmPrgLauncherType.BASIC || compilerOptions.output == OutputType.PRG)
|
override fun convertFloatToBytes(num: Double): List<UByte> {
|
||||||
listOf("syslib")
|
val m5 = Mflpt5.fromNumber(num)
|
||||||
else
|
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||||
emptyList()
|
}
|
||||||
|
|
||||||
|
override fun convertBytesToFloat(bytes: List<UByte>): Double {
|
||||||
|
require(bytes.size==5) { "need 5 bytes" }
|
||||||
|
val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
|
||||||
|
return m5.toDouble()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||||
@ -35,11 +45,11 @@ class CX16MachineDefinition: IMachineDefinition {
|
|||||||
when(selectedEmulator) {
|
when(selectedEmulator) {
|
||||||
1 -> {
|
1 -> {
|
||||||
emulator = "x16emu"
|
emulator = "x16emu"
|
||||||
extraArgs = emptyList()
|
extraArgs = listOf("-debug")
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
emulator = "box16"
|
emulator = "box16"
|
||||||
extraArgs = listOf("-sym", viceMonListName(programNameWithPath.toString()))
|
extraArgs = listOf("-sym", C64Target.viceMonListName(programNameWithPath.toString()))
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
System.err.println("Cx16 target only supports x16emu and box16 emulators.")
|
System.err.println("Cx16 target only supports x16emu and box16 emulators.")
|
||||||
@ -48,30 +58,18 @@ class CX16MachineDefinition: IMachineDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
println("\nStarting Commander X16 emulator $emulator...")
|
println("\nStarting Commander X16 emulator $emulator...")
|
||||||
val cmdline = listOf(emulator, "-scale", "2", "-run", "-prg", "${programNameWithPath}.prg") + extraArgs
|
val cmdline = listOf(emulator, "-scale", "2", "-rtc", "-run", "-prg", "${programNameWithPath}.prg") + extraArgs
|
||||||
val processb = ProcessBuilder(cmdline).inheritIO()
|
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||||
|
processb.environment()["PULSE_LATENCY_MSEC"] = "10"
|
||||||
val process: Process = processb.start()
|
val process: Process = processb.start()
|
||||||
process.waitFor()
|
process.waitFor()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0x9f00u..0x9fffu
|
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0x9f00u..0x9fffu
|
||||||
|
|
||||||
override fun initializeZeropage(compilerOptions: CompilationOptions) {
|
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||||
zeropage = CX16Zeropage(compilerOptions)
|
zeropage = CX16Zeropage(compilerOptions)
|
||||||
|
golden = GoldenRam(compilerOptions, 0x0400u until 0x0800u)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 65c02 opcodes, these cannot be used as variable or label names
|
|
||||||
override val opcodeNames = setOf("adc", "and", "asl", "bcc", "bcs",
|
|
||||||
"beq", "bge", "bit", "blt", "bmi", "bne", "bpl", "brk", "bvc", "bvs", "clc",
|
|
||||||
"cld", "cli", "clv", "cmp", "cpx", "cpy", "dec", "dex", "dey",
|
|
||||||
"eor", "gcc", "gcs", "geq", "gge", "glt", "gmi", "gne", "gpl", "gvc", "gvs",
|
|
||||||
"inc", "inx", "iny", "jmp", "jsr",
|
|
||||||
"lda", "ldx", "ldy", "lsr", "nop", "ora", "pha", "php",
|
|
||||||
"pla", "plp", "rol", "ror", "rti", "rts", "sbc",
|
|
||||||
"sec", "sed", "sei",
|
|
||||||
"sta", "stx", "sty", "tax", "tay", "tsx", "txa", "txs", "tya",
|
|
||||||
"bra", "phx", "phy", "plx", "ply", "stz", "trb", "tsb", "bbr", "bbs",
|
|
||||||
"rmb", "smb", "stp", "wai")
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,30 +40,29 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
ZeropageType.DONTUSE -> {
|
ZeropageType.DONTUSE -> {
|
||||||
free.clear() // don't use zeropage at all
|
free.clear() // don't use zeropage at all
|
||||||
}
|
}
|
||||||
else -> throw InternalCompilerException("for this machine target, zero page type 'floatsafe' is not available. ${options.zeropage}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val distictFree = free.distinct()
|
val distinctFree = free.distinct()
|
||||||
free.clear()
|
free.clear()
|
||||||
free.addAll(distictFree)
|
free.addAll(distinctFree)
|
||||||
|
|
||||||
removeReservedFromFreePool()
|
removeReservedFromFreePool()
|
||||||
|
|
||||||
allocateCx16VirtualRegisters()
|
allocateCx16VirtualRegisters()
|
||||||
|
retainAllowed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun allocateCx16VirtualRegisters() {
|
override fun allocateCx16VirtualRegisters() {
|
||||||
// Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
|
// Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
|
||||||
// However, to be able for the compiler to "see" them as zero page variables, we have to register them here as well.
|
// However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well.
|
||||||
// This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
|
// This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
|
||||||
for(reg in 0..15) {
|
for(reg in 0..15) {
|
||||||
allocatedVariables[listOf("cx16", "r${reg}")] = ZpAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15
|
allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15
|
||||||
allocatedVariables[listOf("cx16", "r${reg}s")] = ZpAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s
|
allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s
|
||||||
allocatedVariables[listOf("cx16", "r${reg}L")] = ZpAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L
|
allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L
|
||||||
allocatedVariables[listOf("cx16", "r${reg}H")] = ZpAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H
|
allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H
|
||||||
allocatedVariables[listOf("cx16", "r${reg}sL")] = ZpAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL
|
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL
|
||||||
allocatedVariables[listOf("cx16", "r${reg}sH")] = ZpAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH
|
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package prog8.code.target.cbm
|
package prog8.code.target.encodings
|
||||||
|
|
||||||
import com.github.michaelbull.result.Ok
|
import com.github.michaelbull.result.Ok
|
||||||
import com.github.michaelbull.result.Result
|
import com.github.michaelbull.result.Result
|
||||||
@ -208,7 +208,7 @@ object AtasciiEncoding {
|
|||||||
return Ok(mapped)
|
return Ok(mapped)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decode(bytes: List<UByte>): Result<String, CharConversionException> {
|
fun decode(bytes: Iterable<UByte>): Result<String, CharConversionException> {
|
||||||
return Ok(bytes.map { decodeTable[it.toInt()] }.joinToString(""))
|
return Ok(bytes.map { decodeTable[it.toInt()] }.joinToString(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
69
codeCore/src/prog8/code/target/encodings/Cp437Encoding.kt
Normal file
69
codeCore/src/prog8/code/target/encodings/Cp437Encoding.kt
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package prog8.code.target.encodings
|
||||||
|
|
||||||
|
import com.github.michaelbull.result.Err
|
||||||
|
import com.github.michaelbull.result.Ok
|
||||||
|
import com.github.michaelbull.result.Result
|
||||||
|
import java.io.CharConversionException
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
|
object Cp437Encoding {
|
||||||
|
val charset: Charset = Charset.forName("IBM437")
|
||||||
|
|
||||||
|
fun encode(str: String): Result<List<UByte>, CharConversionException> {
|
||||||
|
return try {
|
||||||
|
val mapped = str.map { chr ->
|
||||||
|
when (chr) {
|
||||||
|
'\u0000' -> 0u
|
||||||
|
'\u00a0' -> 255u
|
||||||
|
'☺' -> 1u
|
||||||
|
'☻' -> 2u
|
||||||
|
'♥' -> 3u
|
||||||
|
'♦' -> 4u
|
||||||
|
'♣' -> 5u
|
||||||
|
'♠' -> 6u
|
||||||
|
'•' -> 7u
|
||||||
|
'◘' -> 8u
|
||||||
|
'○' -> 9u
|
||||||
|
'◙' -> 10u
|
||||||
|
'♂' -> 11u
|
||||||
|
'♀' -> 12u
|
||||||
|
'♪' -> 13u
|
||||||
|
'♫' -> 14u
|
||||||
|
'☼' -> 15u
|
||||||
|
'►' -> 16u
|
||||||
|
'◄' -> 17u
|
||||||
|
'↕' -> 18u
|
||||||
|
'‼' -> 19u
|
||||||
|
'¶' -> 20u
|
||||||
|
'§' -> 21u
|
||||||
|
'▬' -> 22u
|
||||||
|
'↨' -> 23u
|
||||||
|
'↑' -> 24u
|
||||||
|
'↓' -> 25u
|
||||||
|
'→' -> 26u
|
||||||
|
'←' -> 27u
|
||||||
|
'∟' -> 28u
|
||||||
|
'↔' -> 29u
|
||||||
|
'▲' -> 30u
|
||||||
|
'▼' -> 31u
|
||||||
|
in '\u8000'..'\u80ff' -> {
|
||||||
|
// special case: take the lower 8 bit hex value directly
|
||||||
|
(chr.code - 0x8000).toUByte()
|
||||||
|
}
|
||||||
|
else -> charset.encode(chr.toString())[0].toUByte()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(mapped)
|
||||||
|
} catch (ce: CharConversionException) {
|
||||||
|
Err(ce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decode(bytes: Iterable<UByte>): Result<String, CharConversionException> {
|
||||||
|
return try {
|
||||||
|
Ok(String(bytes.map { it.toByte() }.toByteArray(), charset))
|
||||||
|
} catch (ce: CharConversionException) {
|
||||||
|
Err(ce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package prog8.code.target.cbm
|
package prog8.code.target.encodings
|
||||||
|
|
||||||
import com.github.michaelbull.result.Err
|
import com.github.michaelbull.result.Err
|
||||||
import com.github.michaelbull.result.Ok
|
import com.github.michaelbull.result.Ok
|
||||||
@ -6,8 +6,8 @@ import com.github.michaelbull.result.Result
|
|||||||
import java.io.CharConversionException
|
import java.io.CharConversionException
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
object IsoEncoding {
|
open class IsoEncodingBase(charsetName: String) {
|
||||||
val charset: Charset = Charset.forName("ISO-8859-15")
|
val charset: Charset = Charset.forName(charsetName)
|
||||||
|
|
||||||
fun encode(str: String): Result<List<UByte>, CharConversionException> {
|
fun encode(str: String): Result<List<UByte>, CharConversionException> {
|
||||||
return try {
|
return try {
|
||||||
@ -27,7 +27,7 @@ object IsoEncoding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decode(bytes: List<UByte>): Result<String, CharConversionException> {
|
fun decode(bytes: Iterable<UByte>): Result<String, CharConversionException> {
|
||||||
return try {
|
return try {
|
||||||
Ok(String(bytes.map { it.toByte() }.toByteArray(), charset))
|
Ok(String(bytes.map { it.toByte() }.toByteArray(), charset))
|
||||||
} catch (ce: CharConversionException) {
|
} catch (ce: CharConversionException) {
|
||||||
@ -35,3 +35,8 @@ object IsoEncoding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object IsoEncoding: IsoEncodingBase("ISO-8859-15")
|
||||||
|
object IsoCyrillicEncoding: IsoEncodingBase("ISO-8859-5")
|
||||||
|
object IsoEasternEncoding: IsoEncodingBase("ISO-8859-16")
|
122
codeCore/src/prog8/code/target/encodings/KatakanaEncoding.kt
Normal file
122
codeCore/src/prog8/code/target/encodings/KatakanaEncoding.kt
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package prog8.code.target.encodings
|
||||||
|
|
||||||
|
import com.github.michaelbull.result.Err
|
||||||
|
import com.github.michaelbull.result.Ok
|
||||||
|
import com.github.michaelbull.result.Result
|
||||||
|
import java.io.CharConversionException
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
|
|
||||||
|
object JapaneseCharacterConverter {
|
||||||
|
// adapted from https://github.com/raminduw/Japanese-Character-Converter
|
||||||
|
|
||||||
|
private val ZENKAKU_KATAKANA = charArrayOf(
|
||||||
|
'ァ', 'ア', 'ィ', 'イ', 'ゥ',
|
||||||
|
'ウ', 'ェ', 'エ', 'ォ', 'オ', 'カ', 'ガ', 'キ', 'ギ', 'ク', 'グ', 'ケ', 'ゲ',
|
||||||
|
'コ', 'ゴ', 'サ', 'ザ', 'シ', 'ジ', 'ス', 'ズ', 'セ', 'ゼ', 'ソ', 'ゾ', 'タ',
|
||||||
|
'ダ', 'チ', 'ヂ', 'ッ', 'ツ', 'ヅ', 'テ', 'デ', 'ト', 'ド', 'ナ', 'ニ', 'ヌ',
|
||||||
|
'ネ', 'ノ', 'ハ', 'バ', 'パ', 'ヒ', 'ビ', 'ピ', 'フ', 'ブ', 'プ', 'ヘ', 'ベ',
|
||||||
|
'ペ', 'ホ', 'ボ', 'ポ', 'マ', 'ミ', 'ム', 'メ', 'モ', 'ャ', 'ヤ', 'ュ', 'ユ',
|
||||||
|
'ョ', 'ヨ', 'ラ', 'リ', 'ル', 'レ', 'ロ', 'ヮ', 'ワ', 'ヰ', 'ヱ', 'ヲ', 'ン',
|
||||||
|
'ヴ', 'ヵ', 'ヶ'
|
||||||
|
)
|
||||||
|
|
||||||
|
private val HANKAKU_HIRAGANA = charArrayOf(
|
||||||
|
'ぁ', 'あ', 'ぃ', 'い', 'ぅ', 'う', 'ぇ', 'え',
|
||||||
|
'ぉ', 'お', 'か', 'が', 'き', 'ぎ', 'く', 'ぐ',
|
||||||
|
'け', 'げ', 'こ', 'ご', 'さ', 'ざ', 'し', 'じ',
|
||||||
|
'す', 'ず', 'せ', 'ぜ', 'そ', 'ぞ', 'た', 'だ',
|
||||||
|
'ち', 'ぢ', 'っ', 'つ', 'づ', 'て', 'で', 'と',
|
||||||
|
'ど', 'な', 'に', 'ぬ', 'ね', 'の', 'は', 'ば',
|
||||||
|
'ぱ', 'ひ', 'び', 'ぴ', 'ふ', 'ぶ', 'ぷ', 'へ',
|
||||||
|
'べ', 'ぺ', 'ほ', 'ぼ', 'ぽ', 'ま', 'み', 'む',
|
||||||
|
'め', 'も', 'ゃ', 'や', 'ゅ', 'ゆ', 'ょ', 'よ',
|
||||||
|
'ら', 'り', 'る', 'れ', 'ろ', 'ゎ', 'わ', 'ゐ',
|
||||||
|
'ゑ', 'を', 'ん', 'ゔ', 'ゕ', 'ゖ'
|
||||||
|
)
|
||||||
|
|
||||||
|
private val HANKAKU_KATAKANA = arrayOf(
|
||||||
|
"ァ", "ア", "ィ", "イ", "ゥ",
|
||||||
|
"ウ", "ェ", "エ", "ォ", "オ", "カ", "ガ", "キ", "ギ", "ク", "グ", "ケ",
|
||||||
|
"ゲ", "コ", "ゴ", "サ", "ザ", "シ", "ジ", "ス", "ズ", "セ", "ゼ", "ソ",
|
||||||
|
"ゾ", "タ", "ダ", "チ", "ヂ", "ッ", "ツ", "ヅ", "テ", "デ", "ト", "ド",
|
||||||
|
"ナ", "ニ", "ヌ", "ネ", "ノ", "ハ", "バ", "パ", "ヒ", "ビ", "ピ", "フ",
|
||||||
|
"ブ", "プ", "ヘ", "ベ", "ペ", "ホ", "ボ", "ポ", "マ", "ミ", "ム", "メ",
|
||||||
|
"モ", "ャ", "ヤ", "ュ", "ユ", "ョ", "ヨ", "ラ", "リ", "ル", "レ", "ロ", "ワ",
|
||||||
|
"ワ", "イ", "エ", "ヲ", "ン", "ヴ", "カ", "ケ"
|
||||||
|
)
|
||||||
|
|
||||||
|
private val ZENKAKU_KATAKANA_FIRST_CHAR_CODE = ZENKAKU_KATAKANA.first().code
|
||||||
|
private val HANKAKU_HIRAGANA_FIRST_CHAR_CODE = HANKAKU_HIRAGANA.first().code
|
||||||
|
|
||||||
|
private fun zenkakuKatakanaToHankakuKatakana(c: Char): String = if (c in ZENKAKU_KATAKANA) HANKAKU_KATAKANA[c.code - ZENKAKU_KATAKANA_FIRST_CHAR_CODE] else c.toString()
|
||||||
|
private fun hankakuKatakanaToZenkakuKatakana(c: Char): Char = if (c in HANKAKU_HIRAGANA) ZENKAKU_KATAKANA[c.code - HANKAKU_HIRAGANA_FIRST_CHAR_CODE] else c
|
||||||
|
|
||||||
|
fun zenkakuKatakanaToHankakuKatakana(s: String): String = buildString {
|
||||||
|
for (element in s) {
|
||||||
|
val converted = hankakuKatakanaToZenkakuKatakana(element)
|
||||||
|
val convertedChar = zenkakuKatakanaToHankakuKatakana(converted)
|
||||||
|
append(convertedChar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object KatakanaEncoding {
|
||||||
|
val charset: Charset = Charset.forName("JIS_X0201")
|
||||||
|
|
||||||
|
fun encode(str: String): Result<List<UByte>, CharConversionException> {
|
||||||
|
return try {
|
||||||
|
val mapped = str.map { chr ->
|
||||||
|
when (chr) {
|
||||||
|
|
||||||
|
'\u0000' -> 0u
|
||||||
|
'\u00a0' -> 0xa0u // $a0 isn't technically a part of JIS X 0201 spec, and so we need to handle this ourselves
|
||||||
|
|
||||||
|
'♥' -> 0xe3u
|
||||||
|
'♦' -> 0xe4u
|
||||||
|
'♣' -> 0xe5u
|
||||||
|
'♠' -> 0xe6u
|
||||||
|
|
||||||
|
'大' -> 0xeau
|
||||||
|
'中' -> 0xebu
|
||||||
|
'小' -> 0xecu
|
||||||
|
'百' -> 0xedu
|
||||||
|
'千' -> 0xeeu
|
||||||
|
'万' -> 0xefu
|
||||||
|
'♪' -> 0xf0u
|
||||||
|
'土' -> 0xf1u
|
||||||
|
'金' -> 0xf2u
|
||||||
|
'木' -> 0xf3u
|
||||||
|
'水' -> 0xf4u
|
||||||
|
'火' -> 0xf5u
|
||||||
|
'月' -> 0xf6u
|
||||||
|
'日' -> 0xf7u
|
||||||
|
'時' -> 0xf8u
|
||||||
|
'分' -> 0xf9u
|
||||||
|
'秒' -> 0xfau
|
||||||
|
'年' -> 0xfbu
|
||||||
|
'円' -> 0xfcu
|
||||||
|
'人' -> 0xfdu
|
||||||
|
'生' -> 0xfeu
|
||||||
|
'〒' -> 0xffu
|
||||||
|
in '\u8000'..'\u80ff' -> {
|
||||||
|
// special case: take the lower 8 bit hex value directly
|
||||||
|
(chr.code - 0x8000).toUByte()
|
||||||
|
}
|
||||||
|
else -> charset.encode(chr.toString())[0].toUByte()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(mapped)
|
||||||
|
} catch (ce: CharConversionException) {
|
||||||
|
Err(ce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decode(bytes: Iterable<UByte>): Result<String, CharConversionException> {
|
||||||
|
return try {
|
||||||
|
Ok(String(bytes.map { it.toByte() }.toByteArray(), charset))
|
||||||
|
} catch (ce: CharConversionException) {
|
||||||
|
Err(ce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package prog8.code.target.cbm
|
package prog8.code.target.encodings
|
||||||
|
|
||||||
import com.github.michaelbull.result.Err
|
import com.github.michaelbull.result.Err
|
||||||
import com.github.michaelbull.result.Ok
|
import com.github.michaelbull.result.Ok
|
||||||
@ -7,7 +7,7 @@ import java.io.CharConversionException
|
|||||||
|
|
||||||
object PetsciiEncoding {
|
object PetsciiEncoding {
|
||||||
|
|
||||||
// decoding: from Petscii/Screencodes (0-255) to unicode
|
// decoding: from Petscii/Screencodes (0-255) to Unicode
|
||||||
// character tables used from https://github.com/irmen/cbmcodecs2
|
// character tables used from https://github.com/irmen/cbmcodecs2
|
||||||
|
|
||||||
private val decodingPetsciiLowercase = charArrayOf(
|
private val decodingPetsciiLowercase = charArrayOf(
|
||||||
@ -24,7 +24,7 @@ object PetsciiEncoding {
|
|||||||
'\ufffe', // 0x0A -> UNDEFINED
|
'\ufffe', // 0x0A -> UNDEFINED
|
||||||
'\ufffe', // 0x0B -> UNDEFINED
|
'\ufffe', // 0x0B -> UNDEFINED
|
||||||
'\ufffe', // 0x0C -> UNDEFINED
|
'\ufffe', // 0x0C -> UNDEFINED
|
||||||
'\r' , // 0x0D -> CARRIAGE RETURN
|
'\n' , // 0x0D -> LINE FEED (RETURN)
|
||||||
'\u000e', // 0x0E -> SHIFT OUT
|
'\u000e', // 0x0E -> SHIFT OUT
|
||||||
'\ufffe', // 0x0F -> UNDEFINED
|
'\ufffe', // 0x0F -> UNDEFINED
|
||||||
'\ufffe', // 0x10 -> UNDEFINED
|
'\ufffe', // 0x10 -> UNDEFINED
|
||||||
@ -152,7 +152,7 @@ object PetsciiEncoding {
|
|||||||
'\uf113', // 0x8A -> FUNCTION KEY 4 (CUS)
|
'\uf113', // 0x8A -> FUNCTION KEY 4 (CUS)
|
||||||
'\uf115', // 0x8B -> FUNCTION KEY 6 (CUS)
|
'\uf115', // 0x8B -> FUNCTION KEY 6 (CUS)
|
||||||
'\uf117', // 0x8C -> FUNCTION KEY 8 (CUS)
|
'\uf117', // 0x8C -> FUNCTION KEY 8 (CUS)
|
||||||
'\n' , // 0x8D -> LINE FEED
|
'\r' , // 0x8D -> CARRIAGE RETURN (SHIFT-RETURN)
|
||||||
'\u000f', // 0x8E -> SHIFT IN
|
'\u000f', // 0x8E -> SHIFT IN
|
||||||
'\ufffe', // 0x8F -> UNDEFINED
|
'\ufffe', // 0x8F -> UNDEFINED
|
||||||
'\uf105', // 0x90 -> BLACK COLOR SWITCH (CUS)
|
'\uf105', // 0x90 -> BLACK COLOR SWITCH (CUS)
|
||||||
@ -283,7 +283,7 @@ object PetsciiEncoding {
|
|||||||
'\ufffe', // 0x0A -> UNDEFINED
|
'\ufffe', // 0x0A -> UNDEFINED
|
||||||
'\ufffe', // 0x0B -> UNDEFINED
|
'\ufffe', // 0x0B -> UNDEFINED
|
||||||
'\ufffe', // 0x0C -> UNDEFINED
|
'\ufffe', // 0x0C -> UNDEFINED
|
||||||
'\r' , // 0x0D -> CARRIAGE RETURN
|
'\n' , // 0x0D -> LINE FEED (RETURN)
|
||||||
'\u000e', // 0x0E -> SHIFT OUT
|
'\u000e', // 0x0E -> SHIFT OUT
|
||||||
'\ufffe', // 0x0F -> UNDEFINED
|
'\ufffe', // 0x0F -> UNDEFINED
|
||||||
'\ufffe', // 0x10 -> UNDEFINED
|
'\ufffe', // 0x10 -> UNDEFINED
|
||||||
@ -411,7 +411,7 @@ object PetsciiEncoding {
|
|||||||
'\uf113', // 0x8A -> FUNCTION KEY 4 (CUS)
|
'\uf113', // 0x8A -> FUNCTION KEY 4 (CUS)
|
||||||
'\uf115', // 0x8B -> FUNCTION KEY 6 (CUS)
|
'\uf115', // 0x8B -> FUNCTION KEY 6 (CUS)
|
||||||
'\uf117', // 0x8C -> FUNCTION KEY 8 (CUS)
|
'\uf117', // 0x8C -> FUNCTION KEY 8 (CUS)
|
||||||
'\n' , // 0x8D -> LINE FEED
|
'\r' , // 0x8D -> CARRIAGE RETURN (SHIFT-RETURN)
|
||||||
'\u000f', // 0x8E -> SHIFT IN
|
'\u000f', // 0x8E -> SHIFT IN
|
||||||
'\ufffe', // 0x8F -> UNDEFINED
|
'\ufffe', // 0x8F -> UNDEFINED
|
||||||
'\uf105', // 0x90 -> BLACK COLOR SWITCH (CUS)
|
'\uf105', // 0x90 -> BLACK COLOR SWITCH (CUS)
|
||||||
@ -1061,6 +1061,7 @@ object PetsciiEncoding {
|
|||||||
'}' -> '├'
|
'}' -> '├'
|
||||||
'|' -> '│'
|
'|' -> '│'
|
||||||
'\\' -> '╲'
|
'\\' -> '╲'
|
||||||
|
'\r' -> '\n' // to make \r (carriage returrn) equivalent to \n (line feed): RETURN ($0d)
|
||||||
else -> chr
|
else -> chr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1076,7 +1077,10 @@ object PetsciiEncoding {
|
|||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val case = if (lowercase) "lower" else "upper"
|
val case = if (lowercase) "lower" else "upper"
|
||||||
throw CharConversionException("no ${case}Petscii character for '${chr}' (${chr.code})")
|
if(chr.isISOControl())
|
||||||
|
throw CharConversionException("no ${case}Petscii character for char #${chr.code}")
|
||||||
|
else
|
||||||
|
throw CharConversionException("no ${case}Petscii character for char #${chr.code} '${chr}'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1085,7 +1089,7 @@ object PetsciiEncoding {
|
|||||||
Ok(text.map {
|
Ok(text.map {
|
||||||
try {
|
try {
|
||||||
encodeChar(it, lowercase)
|
encodeChar(it, lowercase)
|
||||||
} catch (x: CharConversionException) {
|
} catch (_: CharConversionException) {
|
||||||
encodeChar(it, !lowercase)
|
encodeChar(it, !lowercase)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1119,7 +1123,10 @@ object PetsciiEncoding {
|
|||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val case = if (lowercase) "lower" else "upper"
|
val case = if (lowercase) "lower" else "upper"
|
||||||
throw CharConversionException("no ${case}Screencode character for '${chr}' (${chr.code})")
|
if(chr.isISOControl())
|
||||||
|
throw CharConversionException("no ${case}Screencode character for char #${chr.code}")
|
||||||
|
else
|
||||||
|
throw CharConversionException("no ${case}Screencode character for char #${chr.code} '${chr}'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1128,7 +1135,7 @@ object PetsciiEncoding {
|
|||||||
Ok(text.map {
|
Ok(text.map {
|
||||||
try {
|
try {
|
||||||
encodeChar(it, lowercase)
|
encodeChar(it, lowercase)
|
||||||
} catch (x: CharConversionException) {
|
} catch (_: CharConversionException) {
|
||||||
encodeChar(it, !lowercase)
|
encodeChar(it, !lowercase)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1150,16 +1157,16 @@ object PetsciiEncoding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun petscii2scr(petscii_code: UByte, inverseVideo: Boolean): Result<UByte, CharConversionException> {
|
fun petscii2scr(petsciicode: UByte, inverseVideo: Boolean): Result<UByte, CharConversionException> {
|
||||||
val code: UInt = when {
|
val code: UInt = when {
|
||||||
petscii_code <= 0x1fu -> petscii_code + 128u
|
petsciicode <= 0x1fu -> petsciicode + 128u
|
||||||
petscii_code <= 0x3fu -> petscii_code.toUInt()
|
petsciicode <= 0x3fu -> petsciicode.toUInt()
|
||||||
petscii_code <= 0x5fu -> petscii_code - 64u
|
petsciicode <= 0x5fu -> petsciicode - 64u
|
||||||
petscii_code <= 0x7fu -> petscii_code - 32u
|
petsciicode <= 0x7fu -> petsciicode - 32u
|
||||||
petscii_code <= 0x9fu -> petscii_code + 64u
|
petsciicode <= 0x9fu -> petsciicode + 64u
|
||||||
petscii_code <= 0xbfu -> petscii_code - 64u
|
petsciicode <= 0xbfu -> petsciicode - 64u
|
||||||
petscii_code <= 0xfeu -> petscii_code - 128u
|
petsciicode <= 0xfeu -> petsciicode - 128u
|
||||||
petscii_code == 255.toUByte() -> 95u
|
petsciicode == 255.toUByte() -> 95u
|
||||||
else -> return Err(CharConversionException("petscii code out of range"))
|
else -> return Err(CharConversionException("petscii code out of range"))
|
||||||
}
|
}
|
||||||
if(inverseVideo) {
|
if(inverseVideo) {
|
@ -0,0 +1,50 @@
|
|||||||
|
package prog8.code.target.neo6502
|
||||||
|
|
||||||
|
import prog8.code.core.*
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
|
||||||
|
class Neo6502MachineDefinition: IMachineDefinition {
|
||||||
|
|
||||||
|
override val cpu = CpuType.CPU65c02
|
||||||
|
|
||||||
|
override val FLOAT_MAX_POSITIVE = 9.999999999e97
|
||||||
|
override val FLOAT_MAX_NEGATIVE = -9.999999999e97
|
||||||
|
override val FLOAT_MEM_SIZE = 6
|
||||||
|
override val STARTUP_CODE_RESERVED_SIZE = 20u
|
||||||
|
override val PROGRAM_LOAD_ADDRESS = 0x0800u
|
||||||
|
override val PROGRAM_MEMTOP_ADDRESS = 0xfc00u // kernal starts here
|
||||||
|
|
||||||
|
override val BSSHIGHRAM_START = 0u // TODO
|
||||||
|
override val BSSHIGHRAM_END = 0u // TODO
|
||||||
|
override val BSSGOLDENRAM_START = 0u // TODO
|
||||||
|
override val BSSGOLDENRAM_END = 0u // TODO
|
||||||
|
|
||||||
|
override lateinit var zeropage: Zeropage
|
||||||
|
override lateinit var golden: GoldenRam
|
||||||
|
|
||||||
|
override fun getFloatAsmBytes(num: Number) = TODO("atari float asm bytes from number")
|
||||||
|
override fun convertFloatToBytes(num: Double): List<UByte> = TODO("atari float to bytes")
|
||||||
|
override fun convertBytesToFloat(bytes: List<UByte>): Double = TODO("atari bytes to float")
|
||||||
|
|
||||||
|
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||||
|
if(selectedEmulator!=1) {
|
||||||
|
System.err.println("The neo target only supports the main emulator (neo).")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val cmdline = listOf("neo", "${programNameWithPath}.bin@800", "cold")
|
||||||
|
|
||||||
|
println("\nStarting Neo6502 emulator...")
|
||||||
|
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||||
|
val process: Process = processb.start()
|
||||||
|
process.waitFor()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isIOAddress(address: UInt): Boolean = address in 0xff00u..0xff0fu
|
||||||
|
|
||||||
|
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||||
|
zeropage = Neo6502Zeropage(compilerOptions)
|
||||||
|
golden = GoldenRam(compilerOptions, UIntRange.EMPTY)
|
||||||
|
}
|
||||||
|
}
|
48
codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt
Normal file
48
codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package prog8.code.target.neo6502
|
||||||
|
|
||||||
|
import prog8.code.core.*
|
||||||
|
|
||||||
|
class Neo6502Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||||
|
|
||||||
|
override val SCRATCH_B1 = 0xfau // temp storage for a single byte
|
||||||
|
override val SCRATCH_REG = 0xfbu // temp storage for a register, must be B1+1
|
||||||
|
override val SCRATCH_W1 = 0xfcu // temp storage 1 for a word $fc+$fd
|
||||||
|
override val SCRATCH_W2 = 0xfeu // temp storage 2 for a word $fe+$ff
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (options.floats) {
|
||||||
|
throw InternalCompilerException("Neo6502 target doesn't support floating point routines")
|
||||||
|
}
|
||||||
|
|
||||||
|
when (options.zeropage) {
|
||||||
|
ZeropageType.DONTUSE -> {
|
||||||
|
free.clear() // don't use zeropage at all
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
free.addAll(0x22u..0xffu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val distinctFree = free.distinct()
|
||||||
|
free.clear()
|
||||||
|
free.addAll(distinctFree)
|
||||||
|
|
||||||
|
removeReservedFromFreePool()
|
||||||
|
allocateCx16VirtualRegisters()
|
||||||
|
retainAllowed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun allocateCx16VirtualRegisters() {
|
||||||
|
// Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
|
||||||
|
// However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well.
|
||||||
|
// This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
|
||||||
|
for(reg in 0..15) {
|
||||||
|
allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15
|
||||||
|
allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s
|
||||||
|
allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L
|
||||||
|
allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H
|
||||||
|
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL
|
||||||
|
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
codeCore/src/prog8/code/target/pet/PETMachineDefinition.kt
Normal file
63
codeCore/src/prog8/code/target/pet/PETMachineDefinition.kt
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package prog8.code.target.pet
|
||||||
|
|
||||||
|
import prog8.code.core.*
|
||||||
|
import prog8.code.target.C64Target
|
||||||
|
import prog8.code.target.cbm.Mflpt5
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
|
||||||
|
class PETMachineDefinition: IMachineDefinition {
|
||||||
|
|
||||||
|
override val cpu = CpuType.CPU6502
|
||||||
|
|
||||||
|
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
|
||||||
|
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
|
||||||
|
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
||||||
|
override val STARTUP_CODE_RESERVED_SIZE = 20u
|
||||||
|
override val PROGRAM_LOAD_ADDRESS = 0x0401u
|
||||||
|
override val PROGRAM_MEMTOP_ADDRESS = 0x8000u
|
||||||
|
|
||||||
|
override val BSSHIGHRAM_START = 0u
|
||||||
|
override val BSSHIGHRAM_END = 0u
|
||||||
|
override val BSSGOLDENRAM_START = 0u
|
||||||
|
override val BSSGOLDENRAM_END = 0u
|
||||||
|
|
||||||
|
override lateinit var zeropage: Zeropage
|
||||||
|
override lateinit var golden: GoldenRam
|
||||||
|
|
||||||
|
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
|
||||||
|
|
||||||
|
override fun convertFloatToBytes(num: Double): List<UByte> {
|
||||||
|
val m5 = Mflpt5.fromNumber(num)
|
||||||
|
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun convertBytesToFloat(bytes: List<UByte>): Double {
|
||||||
|
require(bytes.size==5) { "need 5 bytes" }
|
||||||
|
val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
|
||||||
|
return m5.toDouble()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||||
|
if(selectedEmulator!=1) {
|
||||||
|
System.err.println("The pet target only supports the main emulator (Vice).")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
println("\nStarting PET emulator...")
|
||||||
|
val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString())
|
||||||
|
val cmdline = listOf("xpet", "-model", "4032", "-ramsize", "32", "-videosize", "40", "-silent", "-moncommands", viceMonlist,
|
||||||
|
"-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
|
||||||
|
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||||
|
val process=processb.start()
|
||||||
|
process.waitFor()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isIOAddress(address: UInt): Boolean = address in 0xe800u..0xe8ffu
|
||||||
|
|
||||||
|
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||||
|
zeropage = PETZeropage(compilerOptions)
|
||||||
|
// there's no golden ram.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
codeCore/src/prog8/code/target/pet/PETZeropage.kt
Normal file
59
codeCore/src/prog8/code/target/pet/PETZeropage.kt
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package prog8.code.target.pet
|
||||||
|
|
||||||
|
import prog8.code.core.CompilationOptions
|
||||||
|
import prog8.code.core.InternalCompilerException
|
||||||
|
import prog8.code.core.Zeropage
|
||||||
|
import prog8.code.core.ZeropageType
|
||||||
|
|
||||||
|
|
||||||
|
// reference: http://www.zimmers.net/cbmpics/cbm/PETx/petmem.txt
|
||||||
|
|
||||||
|
class PETZeropage(options: CompilationOptions) : Zeropage(options) {
|
||||||
|
|
||||||
|
override val SCRATCH_B1 = 0xb3u // temp storage for a single byte
|
||||||
|
override val SCRATCH_REG = 0xb4u // temp storage for a register, must be B1+1
|
||||||
|
override val SCRATCH_W1 = 0xb6u // temp storage 1 for a word
|
||||||
|
override val SCRATCH_W2 = 0xb8u // temp storage 2 for a word
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (options.floats) {
|
||||||
|
throw InternalCompilerException("PET target doesn't yet support floating point routines")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.floats && options.zeropage !in arrayOf(
|
||||||
|
ZeropageType.FLOATSAFE,
|
||||||
|
ZeropageType.BASICSAFE,
|
||||||
|
ZeropageType.DONTUSE
|
||||||
|
))
|
||||||
|
throw InternalCompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'")
|
||||||
|
|
||||||
|
when (options.zeropage) {
|
||||||
|
ZeropageType.FULL -> {
|
||||||
|
free.addAll(0x00u..0xffu)
|
||||||
|
free.removeAll(listOf(0x8du, 0x8eu, 0x8fu, 0x97u, 0x98u, 0x99u, 0x9au, 0x9bu, 0x9eu, 0xa7u, 0xa8u, 0xa9u, 0xaau)) // these are updated/used by IRQ
|
||||||
|
}
|
||||||
|
ZeropageType.KERNALSAFE -> {
|
||||||
|
free.addAll(0x00u..0xffu)
|
||||||
|
free.removeAll(listOf(0x8du, 0x8eu, 0x8fu, 0x97u, 0x98u, 0x99u, 0x9au, 0x9bu, 0x9eu, 0xa7u, 0xa8u, 0xa9u, 0xaau)) // these are updated/used by IRQ
|
||||||
|
}
|
||||||
|
ZeropageType.FLOATSAFE,
|
||||||
|
ZeropageType.BASICSAFE -> {
|
||||||
|
free.addAll(0xb3u..0xbau) // TODO more?
|
||||||
|
}
|
||||||
|
ZeropageType.DONTUSE -> {
|
||||||
|
free.clear() // don't use zeropage at all
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val distinctFree = free.distinct()
|
||||||
|
free.clear()
|
||||||
|
free.addAll(distinctFree)
|
||||||
|
|
||||||
|
removeReservedFromFreePool()
|
||||||
|
retainAllowed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun allocateCx16VirtualRegisters() {
|
||||||
|
TODO("Not known if PET can put the virtual regs in ZP")
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,6 @@
|
|||||||
package prog8.code.target.virtual
|
package prog8.code.target.virtual
|
||||||
|
|
||||||
import prog8.code.core.CompilationOptions
|
import prog8.code.core.*
|
||||||
import prog8.code.core.CpuType
|
|
||||||
import prog8.code.core.IMachineDefinition
|
|
||||||
import prog8.code.core.Zeropage
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.isReadable
|
import kotlin.io.path.isReadable
|
||||||
import kotlin.io.path.name
|
import kotlin.io.path.name
|
||||||
@ -13,20 +10,46 @@ class VirtualMachineDefinition: IMachineDefinition {
|
|||||||
|
|
||||||
override val cpu = CpuType.VIRTUAL
|
override val cpu = CpuType.VIRTUAL
|
||||||
|
|
||||||
override val FLOAT_MAX_POSITIVE = Float.MAX_VALUE.toDouble()
|
override val FLOAT_MAX_POSITIVE = Double.MAX_VALUE.toDouble()
|
||||||
override val FLOAT_MAX_NEGATIVE = -Float.MAX_VALUE.toDouble()
|
override val FLOAT_MAX_NEGATIVE = -Double.MAX_VALUE.toDouble()
|
||||||
override val FLOAT_MEM_SIZE = 4 // 32-bits floating point
|
override val FLOAT_MEM_SIZE = 8 // 64-bits double
|
||||||
|
override val STARTUP_CODE_RESERVED_SIZE = 0u // not actually used
|
||||||
override val PROGRAM_LOAD_ADDRESS = 0u // not actually used
|
override val PROGRAM_LOAD_ADDRESS = 0u // not actually used
|
||||||
|
override val PROGRAM_MEMTOP_ADDRESS = 0xffffu // not actually used
|
||||||
|
|
||||||
override var ESTACK_LO = 0u // not actually used
|
override val BSSHIGHRAM_START = 0u // not actually used
|
||||||
override var ESTACK_HI = 0u // not actually used
|
override val BSSHIGHRAM_END = 0u // not actually used
|
||||||
|
override val BSSGOLDENRAM_START = 0u // not actually used
|
||||||
|
override val BSSGOLDENRAM_END = 0u // not actually used
|
||||||
|
override lateinit var zeropage: Zeropage // not actually used
|
||||||
|
override lateinit var golden: GoldenRam // not actually used
|
||||||
|
|
||||||
override lateinit var zeropage: Zeropage // not actually used
|
override fun getFloatAsmBytes(num: Number): String {
|
||||||
|
// little endian binary representation
|
||||||
|
val bits = num.toDouble().toBits().toULong()
|
||||||
|
val hexStr = bits.toString(16).padStart(16, '0')
|
||||||
|
val parts = hexStr.chunked(2).map { "\$" + it }
|
||||||
|
return parts.joinToString(", ")
|
||||||
|
}
|
||||||
|
|
||||||
override fun getFloatAsmBytes(num: Number) = TODO("float asm bytes from number")
|
override fun convertFloatToBytes(num: Double): List<UByte> {
|
||||||
|
val bits = num.toBits().toULong()
|
||||||
|
val hexStr = bits.toString(16).padStart(16, '0')
|
||||||
|
val parts = hexStr.chunked(2).map { it.toInt(16).toUByte() }
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
|
||||||
override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List<String> {
|
override fun convertBytesToFloat(bytes: List<UByte>): Double {
|
||||||
return listOf("syslib")
|
require(bytes.size==8) { "need 8 bytes" }
|
||||||
|
val b0 = bytes[0].toLong() shl (8*7)
|
||||||
|
val b1 = bytes[1].toLong() shl (8*6)
|
||||||
|
val b2 = bytes[2].toLong() shl (8*5)
|
||||||
|
val b3 = bytes[3].toLong() shl (8*4)
|
||||||
|
val b4 = bytes[4].toLong() shl (8*3)
|
||||||
|
val b5 = bytes[5].toLong() shl (8*2)
|
||||||
|
val b6 = bytes[6].toLong() shl (8*1)
|
||||||
|
val b7 = bytes[7].toLong() shl (8*0)
|
||||||
|
return Double.fromBits(b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||||
@ -47,11 +70,24 @@ class VirtualMachineDefinition: IMachineDefinition {
|
|||||||
|
|
||||||
override fun isIOAddress(address: UInt): Boolean = false
|
override fun isIOAddress(address: UInt): Boolean = false
|
||||||
|
|
||||||
override fun initializeZeropage(compilerOptions: CompilationOptions) {}
|
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||||
|
zeropage = VirtualZeropage(compilerOptions)
|
||||||
override val opcodeNames = emptySet<String>()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IVirtualMachineRunner {
|
interface IVirtualMachineRunner {
|
||||||
fun runProgram(irSource: CharSequence)
|
fun runProgram(irSource: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class VirtualZeropage(options: CompilationOptions): Zeropage(options) {
|
||||||
|
override val SCRATCH_B1: UInt
|
||||||
|
get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
|
||||||
|
override val SCRATCH_REG: UInt
|
||||||
|
get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
|
||||||
|
override val SCRATCH_W1: UInt
|
||||||
|
get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
|
||||||
|
override val SCRATCH_W2: UInt
|
||||||
|
get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
|
||||||
|
|
||||||
|
override fun allocateCx16VirtualRegisters() { /* there is no actual zero page in this target to allocate thing in */ }
|
||||||
}
|
}
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
|
|
||||||
plugins {
|
|
||||||
id 'java'
|
|
||||||
id 'application'
|
|
||||||
id "org.jetbrains.kotlin.jvm"
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
toolchain {
|
|
||||||
languageVersion = JavaLanguageVersion.of(javaVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileKotlin {
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = javaVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileTestKotlin {
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = javaVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation project(':codeCore')
|
|
||||||
implementation project(':compilerAst')
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
|
||||||
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
|
||||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
java {
|
|
||||||
srcDirs = ["${project.projectDir}/src"]
|
|
||||||
}
|
|
||||||
resources {
|
|
||||||
srcDirs = ["${project.projectDir}/res"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// note: there are no unit tests in this module!
|
|
46
codeGenCpu6502/build.gradle.kts
Normal file
46
codeGenCpu6502/build.gradle.kts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":codeCore"))
|
||||||
|
// implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||||
|
implementation("com.michael-bull.kotlin-result:kotlin-result-jvm:2.0.0")
|
||||||
|
|
||||||
|
testImplementation("io.kotest:kotest-runner-junit5-jvm:5.9.1")
|
||||||
|
testImplementation("io.kotest:kotest-framework-datatest:5.9.1")
|
||||||
|
testImplementation("org.junit.jupiter:junit-jupiter:5.9.1")
|
||||||
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java {
|
||||||
|
setSrcDirs(listOf("$projectDir/src"))
|
||||||
|
}
|
||||||
|
resources {
|
||||||
|
setSrcDirs(listOf("$projectDir/res"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test {
|
||||||
|
java {
|
||||||
|
setSrcDirs(listOf("$projectDir/test"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
// Enable JUnit 5 (Gradle 4.6+).
|
||||||
|
useJUnitPlatform()
|
||||||
|
|
||||||
|
// Always run tests, even when nothing changed.
|
||||||
|
dependsOn("cleanTest")
|
||||||
|
|
||||||
|
// Show test results.
|
||||||
|
testLogging {
|
||||||
|
events("skipped", "failed")
|
||||||
|
}
|
||||||
|
}
|
@ -4,13 +4,16 @@
|
|||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||||
<orderEntry type="module" module-name="codeCore" />
|
<orderEntry type="module" module-name="codeCore" />
|
||||||
<orderEntry type="module" module-name="compilerAst" />
|
|
||||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||||
|
<orderEntry type="library" name="io.kotest.assertions.core.jvm" level="project" />
|
||||||
|
<orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
|
||||||
|
<orderEntry type="library" name="io.kotest.framework.datatest" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user