diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-10-28 00:00:21 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-10-28 00:00:21 +0300 |
| commit | d96b8c7d12fc61ec609d6138627b9d6d18139a9a (patch) | |
| tree | 82bc9a4c2b22de6c021097fb79a57b6d7756a127 | |
| download | tri-d96b8c7d12fc61ec609d6138627b9d6d18139a9a.tar.gz tri-d96b8c7d12fc61ec609d6138627b9d6d18139a9a.zip | |
move to monorepo
+ Will probably have to make some changes to dir layout to make things
make more sense
58 files changed, 16416 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f2feb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +tasm/tasm +triscv/triscv +deps.mk +build diff --git a/core/t9.inc b/core/t9.inc new file mode 100644 index 0000000..4d922ae --- /dev/null +++ b/core/t9.inc @@ -0,0 +1,729 @@ +0, +1, +6, +4, +5, +26, +24, +25, +18, +16, +17, +22, +20, +21, +106, +104, +105, +98, +96, +97, +102, +100, +101, +74, +72, +73, +66, +64, +65, +70, +68, +69, +90, +88, +89, +82, +80, +81, +86, +84, +85, +426, +424, +425, +418, +416, +417, +422, +420, +421, +394, +392, +393, +386, +384, +385, +390, +388, +389, +410, +408, +409, +402, +400, +401, +406, +404, +405, +298, +296, +297, +290, +288, +289, +294, +292, +293, +266, +264, +265, +258, +256, +257, +262, +260, +261, +282, +280, +281, +274, +272, +273, +278, +276, +277, +362, +360, +361, +354, +352, +353, +358, +356, +357, +330, +328, +329, +322, +320, +321, +326, +324, +325, +346, +344, +345, +338, +336, +337, +342, +340, +341, +1706, +1704, +1705, +1698, +1696, +1697, +1702, +1700, +1701, +1674, +1672, +1673, +1666, +1664, +1665, +1670, +1668, +1669, +1690, +1688, +1689, +1682, +1680, +1681, +1686, +1684, +1685, +1578, +1576, +1577, +1570, +1568, +1569, +1574, +1572, +1573, +1546, +1544, +1545, +1538, +1536, +1537, +1542, +1540, +1541, +1562, +1560, +1561, +1554, +1552, +1553, +1558, +1556, +1557, +1642, +1640, +1641, +1634, +1632, +1633, +1638, +1636, +1637, +1610, +1608, +1609, +1602, +1600, +1601, +1606, +1604, +1605, +1626, +1624, +1625, +1618, +1616, +1617, +1622, +1620, +1621, +1194, +1192, +1193, +1186, +1184, +1185, +1190, +1188, +1189, +1162, +1160, +1161, +1154, +1152, +1153, +1158, +1156, +1157, +1178, +1176, +1177, +1170, +1168, +1169, +1174, +1172, +1173, +1066, +1064, +1065, +1058, +1056, +1057, +1062, +1060, +1061, +1034, +1032, +1033, +1026, +1024, +1025, +1030, +1028, +1029, +1050, +1048, +1049, +1042, +1040, +1041, +1046, +1044, +1045, +1130, +1128, +1129, +1122, +1120, +1121, +1126, +1124, +1125, +1098, +1096, +1097, +1090, +1088, +1089, +1094, +1092, +1093, +1114, +1112, +1113, +1106, +1104, +1105, +1110, +1108, +1109, +1450, +1448, +1449, +1442, +1440, +1441, +1446, +1444, +1445, +1418, +1416, +1417, +1410, +1408, +1409, +1414, +1412, +1413, +1434, +1432, +1433, +1426, +1424, +1425, +1430, +1428, +1429, +1322, +1320, +1321, +1314, +1312, +1313, +1318, +1316, +1317, +1290, +1288, +1289, +1282, +1280, +1281, +1286, +1284, +1285, +1306, +1304, +1305, +1298, +1296, +1297, +1302, +1300, +1301, +1386, +1384, +1385, +1378, +1376, +1377, +1382, +1380, +1381, +1354, +1352, +1353, +1346, +1344, +1345, +1350, +1348, +1349, +1370, +1368, +1369, +1362, +1360, +1361, +1366, +1364, +1365, +6826, +6824, +6825, +6818, +6816, +6817, +6822, +6820, +6821, +6794, +6792, +6793, +6786, +6784, +6785, +6790, +6788, +6789, +6810, +6808, +6809, +6802, +6800, +6801, +6806, +6804, +6805, +6698, +6696, +6697, +6690, +6688, +6689, +6694, +6692, +6693, +6666, +6664, +6665, +6658, +6656, +6657, +6662, +6660, +6661, +6682, +6680, +6681, +6674, +6672, +6673, +6678, +6676, +6677, +6762, +6760, +6761, +6754, +6752, +6753, +6758, +6756, +6757, +6730, +6728, +6729, +6722, +6720, +6721, +6726, +6724, +6725, +6746, +6744, +6745, +6738, +6736, +6737, +6742, +6740, +6741, +6314, +6312, +6313, +6306, +6304, +6305, +6310, +6308, +6309, +6282, +6280, +6281, +6274, +6272, +6273, +6278, +6276, +6277, +6298, +6296, +6297, +6290, +6288, +6289, +6294, +6292, +6293, +6186, +6184, +6185, +6178, +6176, +6177, +6182, +6180, +6181, +6154, +6152, +6153, +6146, +6144, +6145, +6150, +6148, +6149, +6170, +6168, +6169, +6162, +6160, +6161, +6166, +6164, +6165, +6250, +6248, +6249, +6242, +6240, +6241, +6246, +6244, +6245, +6218, +6216, +6217, +6210, +6208, +6209, +6214, +6212, +6213, +6234, +6232, +6233, +6226, +6224, +6225, +6230, +6228, +6229, +6570, +6568, +6569, +6562, +6560, +6561, +6566, +6564, +6565, +6538, +6536, +6537, +6530, +6528, +6529, +6534, +6532, +6533, +6554, +6552, +6553, +6546, +6544, +6545, +6550, +6548, +6549, +6442, +6440, +6441, +6434, +6432, +6433, +6438, +6436, +6437, +6410, +6408, +6409, +6402, +6400, +6401, +6406, +6404, +6405, +6426, +6424, +6425, +6418, +6416, +6417, +6422, +6420, +6421, +6506, +6504, +6505, +6498, +6496, +6497, +6502, +6500, +6501, +6474, +6472, +6473, +6466, +6464, +6465, +6470, +6468, +6469, +6490, +6488, +6489, +6482, +6480, +6481, +6486, +6484, +6485, +4778, +4776, +4777, +4770, +4768, +4769, +4774, +4772, +4773, +4746, +4744, +4745, +4738, +4736, +4737, +4742, +4740, +4741, +4762, +4760, +4761, +4754, +4752, +4753, +4758, +4756, +4757, +4650, +4648, +4649, +4642, +4640, +4641, +4646, +4644, +4645, +4618, +4616, +4617, +4610, +4608, +4609, +4614, +4612, +4613, +4634, +4632, +4633, +4626, +4624, +4625, +4630, +4628, +4629, +4714, +4712, +4713, +4706, +4704, +4705, +4710, +4708, +4709, +4682, +4680, +4681, +4674, +4672, +4673, +4678, +4676, +4677, +4698, +4696, +4697, +4690, +4688, +4689, +4694, +4692, +4693, +4266, +4264, +4265, +4258, +4256, +4257, +4262, +4260, +4261, +4234, +4232, +4233, +4226, +4224, +4225, +4230, +4228, +4229, +4250, +4248, +4249, +4242, +4240, +4241, +4246, +4244, +4245, +4138, +4136, +4137, +4130, +4128, +4129, +4134, +4132, +4133, +4106, +4104, +4105, +4098, diff --git a/core/tests/add.c b/core/tests/add.c new file mode 100644 index 0000000..3d733ce --- /dev/null +++ b/core/tests/add.c @@ -0,0 +1,23 @@ +#include <tri.h> +#include <string.h> + +int main(int argc, char *argv[]) +{ + assert(argc == 2); + char *s = argv[1]; + tri_t a = tri_parse_default(s, strlen(s)); + tri_t one = tri_from(1); + + int64_t ba = tri_to(a); + + for (size_t i = 0; i < 1000000000; ++i) { + a = tri_add(a, one); + } + + assert(ba + 1000000000 == tri_to(a)); + + char r[32]; + size_t l = tri_fmt_default(r, 32, a); + r[l] = '\0'; + printf("%s\n", r); +} diff --git a/core/tests/comp.c b/core/tests/comp.c new file mode 100644 index 0000000..b4ac94d --- /dev/null +++ b/core/tests/comp.c @@ -0,0 +1,6 @@ +#include <tri.h> + +int main() +{ + /* test comparisons */ +} diff --git a/core/tests/diop.c b/core/tests/diop.c new file mode 100644 index 0000000..1f9aea4 --- /dev/null +++ b/core/tests/diop.c @@ -0,0 +1,21 @@ +#include <tri.h> + +static tri_t f; + +static tri_t filter(tri_t t) +{ + tri_t r = tri_diop(OON, OOO, OOP, t, f); + return r; +} + +int main() +{ + /* very much not enough testing */ + f = tri_parse_default("111111111", 9); + + tri_t a = tri_parse_default("iii000111", 9); + tri_t b = tri_parse_default("i01i01i01", 9); + + tri_t r = tri_diop(NNN, NNN, NNN, a, b); + assert(tri_eq(filter(r), tri_parse_default("iiiiiiiii", 9))); +} diff --git a/core/tests/div.c b/core/tests/div.c new file mode 100644 index 0000000..07e429d --- /dev/null +++ b/core/tests/div.c @@ -0,0 +1,22 @@ +#include <tri.h> +#include <string.h> + +int main(int argc, char *argv[]) +{ + assert(argc == 2); + char *s = argv[1]; + tri_t a = tri_parse_default(s, strlen(s)); + tri_t one = tri_from(1); + + trival_t ba = tri_to(a); + + for (size_t i = 0; i < 1000000000; ++i) + a = tri_div(a, one); + + assert(ba == tri_to(a)); + + char r[32]; + size_t l = tri_fmt_default(r, 32, a); + r[l] = '\0'; + printf("%s\n", r); +} diff --git a/core/tests/from_to.c b/core/tests/from_to.c new file mode 100644 index 0000000..d6a392d --- /dev/null +++ b/core/tests/from_to.c @@ -0,0 +1,10 @@ +#include <tri.h> + +int main() +{ + /* increment by prime to hopefully somewhat randomly test patterns */ + for (int64_t i = TRI_MIN; i < TRI_MAX; i += 1048009) { + tri_t t = tri_from(i); + assert(tri_to(t) == i); + } +} diff --git a/core/tests/mul.c b/core/tests/mul.c new file mode 100644 index 0000000..55d3af6 --- /dev/null +++ b/core/tests/mul.c @@ -0,0 +1,28 @@ +#include <tri.h> +#include <string.h> + +int main(int argc, char *argv[]) +{ + assert(argc == 2); + char *s = argv[1]; + tri_t a = tri_parse_default(s, strlen(s)); + tri_t one = tri_from(1); + + for (int64_t i = -13; i <= 13; ++i) { + tri_t b = tri_from(i); + b = tri_mul(b, one); + assert(tri_to(b) == i); + } + + int64_t ba = tri_to(a); + + for (size_t i = 0; i < 1000000000; ++i) + a = tri_mul(a, one); + + assert(ba == tri_to(a)); + + char r[32]; + size_t l = tri_fmt_default(r, 32, a); + r[l] = '\0'; + printf("%s\n", r); +} diff --git a/core/tests/sub.c b/core/tests/sub.c new file mode 100644 index 0000000..41c4037 --- /dev/null +++ b/core/tests/sub.c @@ -0,0 +1,22 @@ +#include <tri.h> +#include <string.h> + +int main(int argc, char *argv[]) +{ + assert(argc == 2); + char *s = argv[1]; + tri_t a = tri_parse_default(s, strlen(s)); + tri_t one = tri_from(1); + + int64_t ba = tri_to(a); + + for (size_t i = 0; i < 1000000000; ++i) + a = tri_sub(a, one); + + assert(ba - 1000000000 == tri_to(a)); + + char r[32]; + size_t l = tri_fmt_default(r, 32, a); + r[l] = '\0'; + printf("%s\n", r); +} diff --git a/core/tests/unop.c b/core/tests/unop.c new file mode 100644 index 0000000..a63e420 --- /dev/null +++ b/core/tests/unop.c @@ -0,0 +1,24 @@ +#include <tri.h> + +int main() +{ + /* technically speaking there are only 27 cases to test, and they could + * potentially all checked for manually, but this is good enough for now + */ + tri_t t = tri_parse_default("i01", 3); + + tri_t r = tri_unop(NOP, t); + assert(tri_eq(r, t)); + + r = tri_unop(NNN, t); + assert(tri_eq(r, tri_from(TRI_MIN))); + + r = tri_unop(OOO, t); + assert(tri_eq(r, tri_from(0))); + + r = tri_unop(PPP, t); + assert(tri_eq(r, tri_from(TRI_MAX))); + + r = tri_unop(PON, t); + assert(tri_eq(r, tri_parse_default("10i", 3))); +} diff --git a/core/tri.h b/core/tri.h new file mode 100644 index 0000000..e4336ec --- /dev/null +++ b/core/tri.h @@ -0,0 +1,711 @@ +#ifndef CORE_TRI_H +#define CORE_TRI_H + +#include <inttypes.h> +#include <stdbool.h> +#include <stdint.h> +#include <stddef.h> +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +/* type that can contain the binary value of a tri */ +typedef uint64_t tri_t; + +#define TRI_WIDTH 27 + +/* (3^(27) - 1) / 2 */ +#define TRI_MAX 3812798742493LL +#define TRI_MIN -TRI_MAX + +/* 54 bits */ +#define TRI_BMASK 0x7fffffffffffff +/* alternating ...0101 */ +#define TRI_PMASK 0x15555555555555 +/* alternating ...1010 */ +#define TRI_NMASK 0x2aaaaaaaaaaaaa + +/** + * fairly trivial mapping, + * where operations are mapped as N/O/P, where + * N means that negative values are mapped, + * O means neutral and P means positive. + * + * So for example NOP means N is mapped to N, + * O is mapped to O, P is mapped to P. + */ +enum triop { + N = 1, + O = 2, + P = 3, +}; +typedef enum triop triop_t; + +/* syntactic sugar around passing arguments to TRIOP3 and TRIOP9 */ +#define NNN N, N, N +#define NNO N, N, O +#define NNP N, N, P +#define NON N, O, N +#define NOO N, O, O +#define NOP N, O, P +#define NPN N, P, N +#define NPO N, P, O +#define NPP N, P, P + +#define ONN O, N, N +#define ONO O, N, O +#define ONP O, N, P +#define OON O, O, N +#define OOO O, O, O +#define OOP O, O, P +#define OPN O, P, N +#define OPO O, P, O +#define OPP O, P, P + +#define PNN P, N, N +#define PNO P, N, O +#define PNP P, N, P +#define PON P, O, N +#define POO P, O, O +#define POP P, O, P +#define PPN P, P, N +#define PPO P, P, O +#define PPP P, P, P + +#define GET_TRIOP(t, x)\ + (((t) >> ((x) * 2)) & 0x3) + +#define _SET_TRIOP(t, x)\ + ((t) << ((x) * 2)) + +#define _TRIOP3(a, b, c, i) \ + (_SET_TRIOP((a), (i) + 0) | _SET_TRIOP((b), (i) + 1) | _SET_TRIOP((c), (i) + 2)) + +#define TRIOP3(a) \ + _TRIOP3(a, 0) + +#define _TRIOP9(a, b, c, d, e, f, g, h, i) \ + (_TRIOP3(a, b, c, 0) | _TRIOP3(d, e, f, 3) | _TRIOP3(g, h, i, 6)) + +#define TRIOP9(a, b, c) \ + _TRIOP9(a, b, c) + +static inline int tri_get_trit(tri_t t, size_t i) +{ + bool p = (t >> ((2 * i) + 0)) & 1; + bool n = (t >> ((2 * i) + 1)) & 1; + + /* assume normalized */ + if (!p && !n) + return 0; + + if (p) + return 1; + + if (n) + return -1; + + /* shouldn't be possible */ + return 0; +} + +static inline tri_t tri_set_trit(tri_t t, size_t i, int f) +{ + /* preclear area */ + t &= ~(0x3ULL << (i * 2)); + if (f == 0) + return t; + + if (f < 0) + return t | (0x2ULL << (i * 2)); + + return t | (0x1ULL << (i * 2)); +} + +/* keep n lowest trits */ +static inline tri_t tri_mask(tri_t t, size_t n) +{ + return t & ((1ULL << (n * 2)) - 1); +} + +/* discard n lowest trits */ +static inline tri_t tri_discard(tri_t t, size_t n) +{ + return t & ~((1ULL << (n * 2)) - 1); +} + +static inline tri_t tri_ns(tri_t t) +{ + tri_t n = ( t & TRI_NMASK) >> 1; + tri_t p = (~t & TRI_PMASK) >> 0; + + tri_t ns = (n & p); + ns |= ns << 1; + + return ns; +} + +static inline tri_t tri_ps(tri_t t) +{ + tri_t n = (~t & TRI_NMASK) >> 1; + tri_t p = ( t & TRI_PMASK) >> 0; + + tri_t ps = (n & p); + ps |= ps << 1; + + return ps; +} + +static inline tri_t tri_zs(tri_t t) +{ + tri_t n = (~t & TRI_NMASK) >> 1; + tri_t p = (~t & TRI_PMASK) >> 0; + + tri_t z = (n & p); + z |= z << 1; + + return z; +} + +static inline tri_t tri_us(tri_t t) +{ + tri_t n = ( t & TRI_NMASK) >> 1; + tri_t p = ( t & TRI_PMASK) >> 0; + + tri_t u = (n & p); + u |= u << 1; + + return u; +} + +static inline tri_t tri_normalize(tri_t t) +{ + /* convert binary ones in both positive and negative trits to zero */ + tri_t t0 = ((t & TRI_PMASK) << 1) & t; + t0 |= t0 << 1; + return (t & ~t0) & TRI_BMASK; +} + +static inline tri_t tri_bias(tri_t a) +{ + tri_t z = tri_zs(a); + tri_t p = tri_ps(a); + return (TRI_PMASK & z) | (TRI_NMASK & p); +} + +static inline tri_t tri_unbias(tri_t a) +{ + tri_t n = tri_ns(a); + tri_t z = tri_zs(a); + return (TRI_PMASK & n) | (TRI_NMASK & z); +} + +static inline tri_t tri_neg(tri_t t) +{ + tri_t p = t & TRI_PMASK; + tri_t n = t & TRI_NMASK; + return (p << 1) | (n >> 1); +} + +static inline tri_t tri_from(int64_t v) +{ + static const uint16_t tbl[] = { +#include "t9.inc" + }; + + bool neg = false; + if (v < 0) { + neg = true; + v = - v; + } + + tri_t s = 0; + for (size_t i = 0; i < 5; ++i) { + int64_t d = v / 729; + int64_t r = v - (d * 729); + + tri_t t = tbl[r]; + s |= (t & 0xfff) << (i * 12); + + v = d; + + tri_t c = t >> 12; + if (c == 1) v += 1; + else if (c == 2) v -= 1; + } + + if (neg) + s = tri_neg(s); + + return s & TRI_BMASK; +} + +static inline int64_t tri_to(tri_t t) +{ + /* apparently an algorithm that a superoptimizer found so I'm not even + * going to try to understand what's going on */ + tri_t acc = tri_bias(t); + + acc = acc - (((acc >> 2) & 0x3333333333333333) * ( 4 - 3)); + acc = acc - (((acc >> 4) & 0x0F0F0F0F0F0F0F0F) * ( 16 - 9)); + acc = acc - (((acc >> 8) & 0x00FF00FF00FF00FF) * ( 256 - 81)); + acc = acc - (((acc >> 16) & 0x0000FFFF0000FFFF) * ( 65536 - 6561)); + acc = acc - (((acc >> 32) & 0x00000000FFFFFFFF) * (4294967296 - 43046721)); + + return (int64_t)acc - TRI_MAX; +} + +static inline tri_t tri_parse(const char *s, size_t len, char n, char o, char p) +{ + int64_t r = 1; + int64_t sum = 0; + size_t l = len < TRI_WIDTH ? len : TRI_WIDTH; + for (size_t i = 0; i < l; r *= 3, ++i) { + char t = s[len - 1 - i]; + if (t == n) { sum -= r; continue; } + if (t == p) { sum += r; continue; } + if (t == o) continue; + + /* not pretty but good enough for now */ + fprintf(stderr, "invalid trinary digit: %c\n", t); + abort(); + } + + return tri_from(sum); +} + +static inline tri_t tri_parse_default(const char *s, size_t len) +{ + return tri_parse(s, len, 'i', '0', '1'); +} + +/* does not append trailing NULL */ +/* could be useful to add how many zeroes to print out? */ +static inline size_t tri_fmt(char *s, size_t len, tri_t t, char n, char o, char p) +{ + int64_t v = tri_to(t); + if (v == 0) { + s[0] = '0'; + return 1; + } + + /* naive conversion to trinary is pretty nifty as it automatically stops + * once we reach zero, but I still need to add padding and possibly base + * as well */ + size_t i = 0; + while (v) { + if (i >= len) + break; + + int d = v % 3; + + switch (d) { + case +2: + case -1: s[i] = n; v += 1; break; + + case -2: + case +1: s[i] = p; v -= 1; break; + + default: s[i] = o; + } + + v /= 3; + i++; + } + + /* reverse string */ + for (size_t j = 0; j < i / 2; ++j) { + size_t k = i - j - 1; + char tmp = s[j]; + s[j] = s[k]; + s[k] = tmp; + } + return i; +} + +static inline size_t tri_fmt_default(char *s, size_t len, tri_t t) +{ + return tri_fmt(s, len, t, 'i', '0', '1'); +} + +static inline tri_t tri_sl(tri_t t, size_t i) +{ + return t << (i * 2); +} + +static inline tri_t tri_sr(tri_t t, size_t i) +{ + return t >> (i * 2); +} + +/* bias happends to be used in several places */ +#define BIAS 0x5555555555555555ULL +static inline tri_t tri_bsum(tri_t a, tri_t b) +{ + /* directly lifted from libter27, + * http://homepage.cs.uiowa.edu/~dwjones/ternary/libtern.shtml + * added comments to help myself understand what's going on */ + + /* Really cool algorithm, first `a` is mapped to another number system, + * where 00 is invalid, and the trinary values look like + * 00 "0" => 01 + * 01 "1" => 10 + * 10 "2" => 11 + * + * This is so our hardware addition functions according to + * + * c+b | 00 | 01 | 10 + * ----+----+----+--- + * 01 | 01 | 10 | 11 + * 10 | 10 | 11 |+00 + * 11 | 11 |+00 |+01 + * + * + means carry. Note how similar the above table is to unbalanced + * trinary: + * + * a+b | 0 | 1 | 2 + * ----+---+---+-- + * 0 | 0 | 1 | 2 + * 1 | 1 | 2 |+0 + * 2 | 2 |+0 |+1 + * + * Ignoring carries for the moment, we can map 01 => 0, 10 => 1 and + * 11 => 2. To get back to our normal number system, we can subtract the + * bias again, except for where carries happen. However, notice that the + * number that is left behind IS the number we want! So we just need to + * detect when a carry has occured, and we don't have to fix up that + * location. + * + * Getting the carry occurences is done with b ^ c ^ d. + * b^c is the standard way to compute the sum of two bits and discarding + * the carry. Therefore, if (b^c) is different from d, we know that the + * previous stage must have sent us a carry! + */ + + /* add bias to make binary addition in hardware more closely + * match unbalanced trinary addition */ + tri_t c = a + BIAS; + + /* caclulate biased sum with errors */ + tri_t d = b + c; + + /* detect if a carry happened in the previous stage, if one is detected + * then that region shouldn't be subtracted in the final step */ + tri_t e = (~(b ^ c ^ d) & BIAS) >> 2; + + /* subtract to counter adding bias in first step and fix errors that + * show up in second stage */ + return (d - e) & TRI_BMASK; +} + +static inline tri_t tri_bneg(tri_t a) +{ + return 0x2aaaaaaaaaaaaaaaULL - a; +} + +#define TRI_B0 0x1540000000000000ULL +static inline tri_t tri_bsl(tri_t a, int i) +{ + return (a << (2 * i)) | (TRI_B0 >> (2 * (31 - i))); +} + +static inline tri_t tri_bsr(tri_t a, int i) +{ + return (a >> (2 * i)) | (TRI_B0 << (2 * (31 - i))); +} + +static inline tri_t tri_badd(tri_t a, tri_t b) +{ + /* do some biased number magic for partial sum */ + tri_t bsum = tri_bsum(a, b); + + /* subtract bias for full sum. note that bias + 1 is the same as -bias */ + tri_t sum = tri_bsum(bsum, BIAS + 1); + return sum; +} + +static inline tri_t tri_bsub(tri_t a, tri_t b) +{ + return tri_badd(a, tri_bneg(b)); +} + +static inline tri_t tri_add(tri_t a, tri_t b) +{ + /* convert to biased numbers */ + tri_t ab = tri_bias(a); + tri_t bb = tri_bias(b); + + /* internal helper */ + tri_t sum = tri_badd(ab, bb); + + /* convert back to balanced numbers */ + tri_t r = tri_unbias(sum); + return r; +} +#undef BIAS + +static inline tri_t tri_sub(tri_t a, tri_t b) +{ + return tri_add(a, tri_neg(b)); +} + +#define TRI_N13 0b101010 +#define TRI_N12 0b101000 +#define TRI_N11 0b101001 +#define TRI_N10 0b100010 +#define TRI_N9 0b100000 +#define TRI_N8 0b100001 +#define TRI_N7 0b100110 +#define TRI_N6 0b100100 +#define TRI_N5 0b100101 +#define TRI_N4 0b001010 +#define TRI_N3 0b001000 +#define TRI_N2 0b001001 +#define TRI_N1 0b000010 +#define TRI_0 0b000000 +#define TRI_P1 0b000001 +#define TRI_P2 0b000110 +#define TRI_P3 0b000100 +#define TRI_P4 0b000101 +#define TRI_P5 0b011010 +#define TRI_P6 0b011000 +#define TRI_P7 0b011001 +#define TRI_P8 0b010010 +#define TRI_P9 0b010000 +#define TRI_P10 0b010001 +#define TRI_P11 0b010110 +#define TRI_P12 0b010100 +#define TRI_P13 0b010101 + +static inline tri_t tri_mul(tri_t a, tri_t b) +{ + /* probably needs a little bit more testing */ + tri_t pa = tri_bias(a); + tri_t na = tri_bneg(a); + tri_t p = tri_bias(0); + + for (int i = 0; i < 9; ++i) { + tri_t m = b & 0x3f; + b >>= 6; + + switch (m) { + case TRI_N2: p = tri_badd(p, na); /* fallthru */ + case TRI_N1: p = tri_badd(p, na); + break; + + case TRI_N5: p = tri_badd(p, na); /* fallthru */ + case TRI_N4: p = tri_badd(p, na); /* fallthru */ + case TRI_N3: p = tri_badd(p, tri_bsl(na, 1)); + break; + + case TRI_N8: p = tri_badd(p, na); /* fallthru */ + case TRI_N7: p = tri_badd(p, na); /* fallthru */ + case TRI_N6: p = tri_badd(p, tri_bsl(na, 1)); + p = tri_badd(p, tri_bsl(na, 1)); + break; + + case TRI_N11: p = tri_badd(p, na); /* fallthru */ + case TRI_N10: p = tri_badd(p, na); /* fallthru */ + case TRI_N9: p = tri_badd(p, tri_bsl(na, 2)); + break; + + case TRI_N13: p = tri_badd(p, na); /* fallthru */ + case TRI_N12: p = tri_badd(p, tri_bsl(na, 2)); + p = tri_badd(p, tri_bsl(na, 1)); + break; + + case TRI_0: break; + case TRI_P2: p = tri_badd(p, pa); /* fallthru */ + case TRI_P1: p = tri_badd(p, pa); + break; + + case TRI_P5: p = tri_badd(p, pa); /* fallthru */ + case TRI_P4: p = tri_badd(p, pa); /* fallthru */ + case TRI_P3: p = tri_badd(p, tri_bsl(pa, 1)); + break; + + case TRI_P8: p = tri_badd(p, pa); /* fallthru */ + case TRI_P7: p = tri_badd(p, pa); /* fallthru */ + case TRI_P6: p = tri_badd(p, tri_bsl(pa, 1)); + p = tri_badd(p, tri_bsl(pa, 1)); + break; + + case TRI_P11: p = tri_badd(p, pa); /* fallthru */ + case TRI_P10: p = tri_badd(p, pa); /* fallthru */ + case TRI_P9: p = tri_badd(p, tri_bsl(pa, 2)); + break; + + case TRI_P13: p = tri_badd(p, pa); /* fallthru */ + case TRI_P12: p = tri_badd(p, tri_bsl(pa, 2)); + p = tri_badd(p, tri_bsl(pa, 1)); + break; + + default: printf("misshandled 0x%lx\n", m); + abort(); + } + } + + return tri_unbias(p); +} + +#if 0 +/* I'll deal with division later, turns out hardware and software division + * differs */ +static inline tri_t tri_div(tri_t a, tri_t b) +{ + /* ditto */ + trival_t ba = tri_to(a); + trival_t bb = tri_to(b); + return tri_from(ba / bb); +} + +static inline tri_t tri_rem(tri_t a, tri_t b) +{ + trival_t ba = tri_to(a); + trival_t bb = tri_to(b); + return tri_from(ba % bb); +} +#endif + +/* return sign of whole tri, -1 for negative, 0 for zero, 1 for positive */ +static inline int tri_sign(tri_t t) +{ + if (t == 0) + return 0; + + int lz = __builtin_clzll(t); + if (lz % 2 == 0) + return 1; + + return -1; +} + +static inline bool tri_eq(tri_t a, tri_t b) +{ + return a == b; +} + +static inline bool tri_lt(tri_t a, tri_t b) +{ + tri_t r = tri_sub(a, b); + int s = tri_sign(r); + if (s >= 0) + return false; + + return true; +} + +static inline bool tri_le(tri_t a, tri_t b) +{ + return tri_eq(a, b) || tri_lt(a, b); +} + +static inline bool tri_gt(tri_t a, tri_t b) +{ + return tri_le(b, a); +} + +static inline bool tri_ge(tri_t a, tri_t b) +{ + return tri_lt(b, a); +} + +#define tri_illegal_op()\ + do { fprintf(stderr, "illegal op, aborting\n"); abort(); } while (0) + +#define tri_unop(o, a)\ + tri_unop_do(_TRIOP3(o, 0), a) + +static inline tri_t tri_unop_do(triop_t op, tri_t a) +{ + + tri_t n = 0; + tri_t p = 0; + + tri_t an = tri_ns(a); + tri_t ap = tri_ps(a); + tri_t az = tri_zs(a); + + /* handle mapping n */ + switch (GET_TRIOP(op, 0)) { + case N: n |= an; break; + case P: p |= an; break; + case O: /* noop */ break; + default: tri_illegal_op(); + } + + /* map o */ + switch (GET_TRIOP(op, 1)) { + case N: n |= az; break; + case P: p |= az; break; + case O: /* noop */ break; + default: tri_illegal_op(); + } + + /* map p */ + switch (GET_TRIOP(op, 2)) { + case N: n |= ap; break; + case P: p |= ap; break; + case O: /* noop */ break; + default: tri_illegal_op(); + } + + return (TRI_PMASK & p) | (TRI_NMASK & n); +} + +#define tri_diop(o0, o1, o2, a, b)\ + tri_diop_do(_TRIOP9(o0, o1, o2), a, b) + +static inline tri_t tri_diop_do(triop_t op, tri_t a, tri_t b) +{ + tri_t n = 0; + tri_t p = 0; + + tri_t an = tri_ns(a); + tri_t ap = tri_ps(a); + tri_t az = tri_zs(a); + + tri_t bn = tri_ns(b); + tri_t bp = tri_ps(b); + tri_t bz = tri_zs(b); + + for (int i = 0; i < 9; i += 3) { + /* select map */ + tri_t r = 0; + switch (i) { + case 0: r = an; break; + case 3: r = az; break; + case 6: r = ap; break; + } + + /* map n */ + switch (GET_TRIOP(op, i + 0)) { + case N: n |= r & bn; break; + case P: p |= r & bn; break; + case O: /* noop */ break; + default: tri_illegal_op(); + } + + /* map o */ + switch (GET_TRIOP(op, i + 1)) { + case N: n |= r & bz; break; + case P: p |= r & bz; break; + case O: /* noop */ break; + default: tri_illegal_op(); + } + + /* map p */ + switch (GET_TRIOP(op, i + 2)) { + case N: n |= r & bp; break; + case P: p |= r & bp; break; + case O: /* noop */ break; + default: tri_illegal_op(); + } + } + + return (TRI_PMASK & p) | (TRI_NMASK & n); +} + +#undef tri_illegal_op +#endif diff --git a/tasm/Makefile b/tasm/Makefile new file mode 100644 index 0000000..e5c54c1 --- /dev/null +++ b/tasm/Makefile @@ -0,0 +1,56 @@ +.PHONY: all +all: setup + $(MAKE) -f scripts/makefile + +# this kicks all unrecognised targets to the client script. +# note that trying to compile individual files, e.g. +# +# make kernel.elf +# +# will not work, you would need +# +# make -f scripts/makefile kernel.elf +# +# instead +.DEFAULT: setup + $(MAKE) -f scripts/makefile $< + +.PHONY: +setup: + @echo -n > deps.mk + @./scripts/gen-deps -p TASM -c COMPILE_TASM -b tasm "${TASM_SOURCES}" + +CLEANUP := build deps.mk tasm +CLEANUP_CMD := +TASM_SOURCES := + +include src/source.mk + +.PHONY: format +format: + find arch lib common include -iname '*.[ch]' |\ + xargs uncrustify -c uncrustify.conf --no-backup -F - + +.PHONY: license +license: + find arch lib common include -iname '*.[ch]' |\ + xargs ./scripts/license + +.PHONY: docs +docs: + find arch lib common include -iname '*.[ch]' -not -path */gen/* |\ + xargs ./scripts/warn-undocumented + doxygen docs/doxygen.conf + +RM = rm + +.PHONY: clean +clean: + $(RM) -rf $(CLEANUP) + +.PHONY: clean_docs +clean_docs: + $(RM) -rf docs/output + +.PHONY: clean_all +clean_all: clean clean_docs diff --git a/tasm/gen/gen_lexer.inc b/tasm/gen/gen_lexer.inc new file mode 100644 index 0000000..be2fc6b --- /dev/null +++ b/tasm/gen/gen_lexer.inc @@ -0,0 +1,2970 @@ +#line 2 "gen/gen_lexer.inc" + +#line 4 "gen/gen_lexer.inc" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 145 +#define YY_END_OF_BUFFER 146 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[234] = + { 0, + 0, 0, 0, 0, 146, 144, 143, 143, 144, 140, + 141, 142, 144, 144, 144, 2, 2, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 136, 138, 135, 137, 143, 0, 3, + 0, 2, 0, 0, 132, 131, 0, 0, 0, 139, + 1, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 120, 112, 119, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 113, 139, + 139, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 136, 135, 134, 133, 0, 0, 131, 2, 2, + + 98, 139, 108, 111, 110, 109, 127, 139, 125, 139, + 122, 139, 139, 126, 139, 106, 104, 121, 118, 139, + 123, 102, 101, 96, 100, 103, 97, 124, 99, 139, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + + 86, 0, 4, 87, 139, 139, 93, 139, 139, 139, + 107, 139, 90, 89, 94, 88, 91, 95, 92, 0, + 105, 130, 129, 128, 139, 114, 117, 116, 0, 115, + 0, 5, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 1, 1, 1, 1, 1, 5, + 6, 7, 1, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 1, 1, + 1, 1, 1, 1, 23, 23, 23, 23, 23, 23, + 23, 23, 24, 24, 23, 24, 23, 23, 24, 23, + 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, + 1, 25, 1, 1, 24, 1, 26, 27, 28, 29, + + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 24, 23, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[50] = + { 0, + 1, 2, 3, 1, 1, 1, 4, 1, 1, 1, + 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 2, 6, 2, 1, 6, 6, 6, 6, 6, + 6, 6, 6, 2, 2, 6, 2, 6, 6, 2, + 6, 2, 6, 2, 6, 2, 6, 2, 6 + } ; + +static const flex_int16_t yy_base[241] = + { 0, + 0, 0, 47, 48, 144, 991, 50, 54, 56, 991, + 991, 991, 0, 27, 55, 30, 0, 62, 65, 67, + 70, 76, 80, 83, 98, 113, 115, 123, 126, 119, + 162, 128, 207, 0, 991, 69, 136, 88, 70, 991, + 137, 0, 99, 106, 991, 0, 0, 121, 149, 154, + 991, 166, 178, 171, 176, 194, 212, 215, 228, 230, + 233, 241, 243, 246, 256, 180, 259, 272, 277, 280, + 284, 287, 293, 298, 302, 305, 316, 319, 326, 331, + 333, 341, 362, 372, 382, 392, 402, 412, 422, 442, + 444, 0, 116, 991, 991, 104, 67, 0, 0, 177, + + 446, 448, 450, 453, 455, 457, 459, 471, 480, 482, + 484, 488, 493, 495, 497, 505, 509, 518, 530, 532, + 534, 536, 539, 541, 543, 557, 564, 578, 580, 582, + 585, 587, 590, 592, 594, 603, 608, 615, 617, 619, + 624, 626, 629, 631, 633, 640, 642, 647, 654, 656, + 658, 663, 665, 668, 670, 672, 679, 681, 686, 693, + 695, 697, 702, 704, 707, 709, 711, 718, 720, 725, + 732, 734, 736, 741, 743, 746, 748, 750, 757, 759, + 764, 771, 773, 775, 780, 782, 785, 787, 789, 796, + 798, 803, 810, 812, 814, 819, 821, 824, 826, 828, + + 835, 72, 991, 837, 842, 849, 851, 853, 858, 860, + 863, 865, 881, 886, 889, 896, 898, 902, 904, 57, + 907, 910, 912, 914, 919, 925, 928, 935, 64, 937, + 58, 991, 991, 959, 965, 72, 970, 976, 982, 984 + } ; + +static const flex_int16_t yy_def[241] = + { 0, + 233, 1, 234, 234, 233, 233, 233, 233, 235, 233, + 233, 233, 236, 233, 233, 236, 236, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 238, 233, 233, 233, 233, 235, 233, + 235, 236, 233, 233, 233, 239, 240, 233, 233, 237, + 233, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 33, 33, 33, 33, 33, 33, 33, 237, + 237, 238, 233, 233, 233, 233, 233, 239, 240, 233, + + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + + 237, 233, 233, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 233, + 237, 237, 237, 237, 237, 237, 237, 237, 233, 237, + 233, 233, 0, 233, 233, 233, 233, 233, 233, 233 + } ; + +static const flex_int16_t yy_nxt[1041] = + { 0, + 6, 7, 8, 9, 10, 11, 6, 12, 13, 14, + 15, 16, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 6, 18, 18, 6, 19, 20, 21, 22, 23, + 24, 18, 18, 18, 25, 18, 26, 27, 28, 18, + 29, 18, 30, 31, 18, 32, 18, 18, 33, 35, + 35, 38, 38, 36, 36, 38, 38, 37, 37, 40, + 43, 45, 47, 49, 49, 46, 49, 49, 49, 49, + 44, 49, 49, 40, 48, 93, 42, 49, 49, 94, + 41, 49, 49, 51, 49, 49, 51, 232, 51, 38, + 38, 51, 231, 52, 41, 58, 54, 51, 55, 49, + + 49, 51, 229, 56, 51, 57, 61, 62, 220, 60, + 53, 203, 64, 59, 49, 49, 49, 49, 63, 51, + 49, 49, 93, 65, 49, 49, 94, 49, 49, 49, + 49, 202, 100, 100, 51, 97, 51, 96, 66, 233, + 51, 67, 95, 233, 51, 233, 68, 51, 73, 51, + 49, 49, 233, 72, 100, 49, 49, 233, 69, 233, + 70, 233, 71, 49, 49, 233, 81, 49, 49, 233, + 51, 233, 49, 49, 233, 51, 233, 49, 49, 49, + 49, 49, 49, 51, 233, 233, 233, 51, 100, 100, + 233, 74, 51, 75, 101, 49, 49, 51, 76, 51, + + 77, 51, 233, 233, 78, 104, 79, 80, 49, 49, + 100, 102, 103, 49, 49, 51, 49, 49, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 51, 49, + 49, 49, 49, 51, 49, 49, 51, 233, 105, 233, + 233, 106, 49, 49, 49, 49, 233, 49, 49, 51, + 233, 51, 233, 233, 51, 233, 233, 49, 49, 107, + 49, 49, 51, 233, 51, 233, 113, 51, 233, 110, + 108, 233, 109, 49, 49, 112, 111, 51, 49, 49, + 51, 49, 49, 233, 115, 49, 49, 114, 49, 49, + 233, 233, 116, 51, 49, 49, 233, 233, 51, 49, + + 49, 51, 233, 49, 49, 51, 49, 49, 51, 233, + 117, 233, 120, 233, 51, 233, 118, 49, 49, 51, + 49, 49, 233, 51, 119, 233, 51, 49, 49, 233, + 121, 123, 49, 49, 49, 49, 233, 51, 233, 122, + 51, 124, 49, 49, 233, 126, 233, 51, 233, 125, + 233, 233, 51, 233, 51, 127, 233, 129, 233, 233, + 233, 233, 51, 233, 233, 233, 233, 233, 233, 233, + 128, 233, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 201, 49, 49, 49, 49, 49, 49, + 49, 49, 233, 51, 233, 51, 233, 51, 233, 51, + 233, 51, 49, 49, 51, 233, 51, 233, 51, 204, + 51, 49, 49, 49, 49, 49, 49, 233, 205, 49, + 49, 233, 51, 233, 49, 49, 49, 49, 49, 49, + + 233, 51, 233, 51, 233, 51, 49, 49, 233, 51, + 49, 49, 233, 206, 51, 233, 51, 208, 51, 49, + 49, 233, 207, 233, 210, 233, 51, 233, 233, 209, + 51, 49, 49, 49, 49, 49, 49, 49, 49, 51, + 49, 49, 49, 49, 49, 49, 233, 211, 233, 233, + 233, 51, 233, 51, 233, 51, 233, 51, 49, 49, + 51, 233, 51, 233, 51, 49, 49, 233, 212, 213, + 233, 233, 214, 233, 215, 233, 216, 233, 51, 49, + 49, 49, 49, 49, 49, 51, 49, 49, 49, 49, + 217, 49, 49, 49, 49, 49, 49, 218, 233, 51, + + 233, 51, 233, 51, 49, 49, 51, 233, 51, 49, + 49, 51, 233, 51, 233, 51, 49, 49, 49, 49, + 49, 49, 219, 233, 51, 49, 49, 49, 49, 51, + 49, 49, 49, 49, 49, 49, 51, 233, 51, 233, + 51, 49, 49, 49, 49, 51, 233, 51, 49, 49, + 51, 233, 51, 233, 51, 49, 49, 49, 49, 49, + 49, 51, 233, 51, 49, 49, 49, 49, 51, 49, + 49, 49, 49, 49, 49, 51, 233, 51, 233, 51, + 49, 49, 49, 49, 51, 233, 51, 49, 49, 51, + 233, 51, 233, 51, 49, 49, 49, 49, 49, 49, + + 51, 233, 51, 49, 49, 49, 49, 51, 49, 49, + 49, 49, 49, 49, 51, 233, 51, 233, 51, 49, + 49, 49, 49, 51, 233, 51, 49, 49, 51, 233, + 51, 233, 51, 49, 49, 49, 49, 49, 49, 51, + 233, 51, 49, 49, 49, 49, 51, 49, 49, 49, + 49, 49, 49, 51, 233, 51, 233, 51, 49, 49, + 49, 49, 51, 233, 51, 49, 49, 51, 233, 51, + 233, 51, 49, 49, 49, 49, 49, 49, 51, 233, + 51, 49, 49, 49, 49, 51, 49, 49, 49, 49, + 49, 49, 51, 233, 51, 233, 51, 49, 49, 49, + + 49, 51, 233, 51, 49, 49, 51, 233, 51, 233, + 51, 49, 49, 49, 49, 49, 49, 51, 233, 51, + 49, 49, 49, 49, 51, 49, 49, 49, 49, 49, + 49, 51, 233, 51, 233, 51, 49, 49, 49, 49, + 51, 233, 51, 49, 49, 51, 233, 51, 233, 51, + 49, 49, 49, 49, 49, 49, 51, 233, 51, 49, + 49, 49, 49, 51, 49, 49, 49, 49, 233, 221, + 51, 233, 51, 233, 51, 233, 222, 233, 225, 51, + 233, 51, 49, 49, 51, 233, 51, 49, 49, 227, + 49, 49, 223, 233, 226, 233, 224, 49, 49, 49, + + 49, 228, 51, 49, 49, 49, 49, 51, 49, 49, + 51, 49, 49, 49, 49, 49, 49, 51, 233, 51, + 49, 49, 233, 51, 233, 51, 49, 49, 51, 49, + 49, 51, 233, 51, 233, 51, 49, 49, 49, 49, + 51, 233, 233, 233, 233, 233, 51, 233, 233, 51, + 233, 233, 233, 233, 230, 233, 51, 233, 51, 34, + 34, 34, 34, 34, 34, 39, 39, 39, 39, 39, + 39, 50, 50, 233, 50, 50, 92, 92, 233, 233, + 92, 92, 98, 98, 233, 98, 98, 98, 99, 99, + 5, 233, 233, 233, 233, 233, 233, 233, 233, 233, + + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233 + } ; + +static const flex_int16_t yy_chk[1041] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, + 4, 7, 7, 3, 4, 8, 8, 3, 4, 9, + 14, 15, 16, 18, 18, 15, 19, 19, 20, 20, + 14, 21, 21, 39, 16, 36, 236, 22, 22, 36, + 9, 23, 23, 18, 24, 24, 19, 231, 20, 38, + 38, 21, 229, 19, 39, 21, 20, 22, 20, 25, + + 25, 23, 220, 20, 24, 20, 23, 23, 202, 22, + 19, 97, 24, 21, 26, 26, 27, 27, 23, 25, + 30, 30, 93, 25, 28, 28, 93, 29, 29, 32, + 32, 96, 48, 48, 26, 44, 27, 43, 26, 41, + 30, 26, 37, 5, 28, 0, 26, 29, 30, 32, + 49, 49, 0, 29, 48, 50, 50, 0, 26, 0, + 27, 0, 28, 31, 31, 0, 32, 52, 52, 0, + 49, 0, 54, 54, 0, 50, 0, 55, 55, 53, + 53, 66, 66, 31, 0, 0, 0, 52, 100, 100, + 0, 31, 54, 31, 52, 56, 56, 55, 31, 53, + + 31, 66, 0, 0, 31, 55, 31, 31, 33, 33, + 100, 53, 54, 57, 57, 56, 58, 58, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 59, + 59, 60, 60, 57, 61, 61, 58, 0, 56, 0, + 0, 57, 62, 62, 63, 63, 0, 64, 64, 59, + 0, 60, 0, 0, 61, 0, 0, 65, 65, 58, + 67, 67, 62, 0, 63, 0, 62, 64, 0, 60, + 59, 0, 59, 68, 68, 61, 60, 65, 69, 69, + 67, 70, 70, 0, 64, 71, 71, 63, 72, 72, + 0, 0, 65, 68, 73, 73, 0, 0, 69, 74, + + 74, 70, 0, 75, 75, 71, 76, 76, 72, 0, + 69, 0, 72, 0, 73, 0, 70, 77, 77, 74, + 78, 78, 0, 75, 71, 0, 76, 79, 79, 0, + 73, 75, 80, 80, 81, 81, 0, 77, 0, 74, + 78, 76, 82, 82, 0, 77, 0, 79, 0, 76, + 0, 0, 80, 0, 81, 78, 0, 80, 0, 0, + 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, + 79, 0, 81, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, + + 85, 85, 85, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 90, 90, 91, 91, 101, 101, 102, + 102, 103, 103, 90, 104, 104, 105, 105, 106, 106, + 107, 107, 0, 90, 0, 91, 0, 101, 0, 102, + 0, 103, 108, 108, 104, 0, 105, 0, 106, 101, + 107, 109, 109, 110, 110, 111, 111, 0, 102, 112, + 112, 0, 108, 0, 113, 113, 114, 114, 115, 115, + + 0, 109, 0, 110, 0, 111, 116, 116, 0, 112, + 117, 117, 0, 108, 113, 0, 114, 112, 115, 118, + 118, 0, 110, 0, 115, 0, 116, 0, 0, 113, + 117, 119, 119, 120, 120, 121, 121, 122, 122, 118, + 123, 123, 124, 124, 125, 125, 0, 116, 0, 0, + 0, 119, 0, 120, 0, 121, 0, 122, 126, 126, + 123, 0, 124, 0, 125, 127, 127, 0, 120, 122, + 0, 0, 123, 0, 124, 0, 125, 0, 126, 128, + 128, 129, 129, 130, 130, 127, 131, 131, 132, 132, + 126, 133, 133, 134, 134, 135, 135, 127, 0, 128, + + 0, 129, 0, 130, 136, 136, 131, 0, 132, 137, + 137, 133, 0, 134, 0, 135, 138, 138, 139, 139, + 140, 140, 130, 0, 136, 141, 141, 142, 142, 137, + 143, 143, 144, 144, 145, 145, 138, 0, 139, 0, + 140, 146, 146, 147, 147, 141, 0, 142, 148, 148, + 143, 0, 144, 0, 145, 149, 149, 150, 150, 151, + 151, 146, 0, 147, 152, 152, 153, 153, 148, 154, + 154, 155, 155, 156, 156, 149, 0, 150, 0, 151, + 157, 157, 158, 158, 152, 0, 153, 159, 159, 154, + 0, 155, 0, 156, 160, 160, 161, 161, 162, 162, + + 157, 0, 158, 163, 163, 164, 164, 159, 165, 165, + 166, 166, 167, 167, 160, 0, 161, 0, 162, 168, + 168, 169, 169, 163, 0, 164, 170, 170, 165, 0, + 166, 0, 167, 171, 171, 172, 172, 173, 173, 168, + 0, 169, 174, 174, 175, 175, 170, 176, 176, 177, + 177, 178, 178, 171, 0, 172, 0, 173, 179, 179, + 180, 180, 174, 0, 175, 181, 181, 176, 0, 177, + 0, 178, 182, 182, 183, 183, 184, 184, 179, 0, + 180, 185, 185, 186, 186, 181, 187, 187, 188, 188, + 189, 189, 182, 0, 183, 0, 184, 190, 190, 191, + + 191, 185, 0, 186, 192, 192, 187, 0, 188, 0, + 189, 193, 193, 194, 194, 195, 195, 190, 0, 191, + 196, 196, 197, 197, 192, 198, 198, 199, 199, 200, + 200, 193, 0, 194, 0, 195, 201, 201, 204, 204, + 196, 0, 197, 205, 205, 198, 0, 199, 0, 200, + 206, 206, 207, 207, 208, 208, 201, 0, 204, 209, + 209, 210, 210, 205, 211, 211, 212, 212, 0, 205, + 206, 0, 207, 0, 208, 0, 206, 0, 208, 209, + 0, 210, 213, 213, 211, 0, 212, 214, 214, 210, + 215, 215, 206, 0, 209, 0, 206, 216, 216, 217, + + 217, 212, 213, 218, 218, 219, 219, 214, 221, 221, + 215, 222, 222, 223, 223, 224, 224, 216, 0, 217, + 225, 225, 0, 218, 0, 219, 226, 226, 221, 227, + 227, 222, 0, 223, 0, 224, 228, 228, 230, 230, + 225, 0, 0, 0, 0, 0, 226, 0, 0, 227, + 0, 0, 0, 0, 225, 0, 228, 0, 230, 234, + 234, 234, 234, 234, 234, 235, 235, 235, 235, 235, + 235, 237, 237, 0, 237, 237, 238, 238, 0, 0, + 238, 238, 239, 239, 0, 239, 239, 239, 240, 240, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "src/lexer.l" +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ +#define YY_NO_INPUT 1 +#line 6 "src/lexer.l" +#define FROM_LEXER +#include <tasm/parser.h> + +static void update_yylloc(struct parser *parser, YYLTYPE *lloc, const char *text) +{ + (void)parser; + + lloc->first_line = lloc->last_line; + lloc->first_column = lloc->last_column; + + for (size_t i = 0; text[i] != 0; ++i) { + if (text[i] == '\n') { + lloc->last_line++; + /* flex uses 1 based indexing */ + lloc->last_column = 1; + } else { + lloc->last_column++; + } + } +} + +#define YY_USER_ACTION update_yylloc(parser, yylloc, yytext); +#line 753 "gen/gen_lexer.inc" + +#line 755 "gen/gen_lexer.inc" + +#define INITIAL 0 +#define SC_COMMENT 1 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (yyscan_t yyscanner); + +#define YY_DECL int yylex (yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { +#line 42 "src/lexer.l" + + +#line 1017 "gen/gen_lexer.inc" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 234 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 991 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +#line 44 "src/lexer.l" +{ + /* strip trailing ':' */ + char *s = yytext + strlen(yytext); + s[-1] = '\0'; + + yylval->str = yytext; + return label; +} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 53 "src/lexer.l" +{ + yylval->tri = parse_imm(yytext); + return imm; +} + YY_BREAK +case 3: +/* rule 3 can match eol */ +YY_RULE_SETUP +#line 58 "src/lexer.l" +{ + /* strip leading and trailing " */ + char *s = yytext + strlen(yytext); + s[-1] = '\0'; + + yylval->str = yytext + 1; + return str; +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 67 "src/lexer.l" +{return set;} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 68 "src/lexer.l" +{return include;} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 70 "src/lexer.l" +{return x0;} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 71 "src/lexer.l" +{return x1;} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 72 "src/lexer.l" +{return x2;} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 73 "src/lexer.l" +{return x3;} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 74 "src/lexer.l" +{return x4;} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 75 "src/lexer.l" +{return x5;} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 76 "src/lexer.l" +{return x6;} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 77 "src/lexer.l" +{return x7;} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 78 "src/lexer.l" +{return x8;} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 79 "src/lexer.l" +{return x9;} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 80 "src/lexer.l" +{return x10;} + YY_BREAK +case 17: +YY_RULE_SETUP +#line 81 "src/lexer.l" +{return x11;} + YY_BREAK +case 18: +YY_RULE_SETUP +#line 82 "src/lexer.l" +{return x12;} + YY_BREAK +case 19: +YY_RULE_SETUP +#line 83 "src/lexer.l" +{return x13;} + YY_BREAK +case 20: +YY_RULE_SETUP +#line 84 "src/lexer.l" +{return x14;} + YY_BREAK +case 21: +YY_RULE_SETUP +#line 85 "src/lexer.l" +{return x15;} + YY_BREAK +case 22: +YY_RULE_SETUP +#line 86 "src/lexer.l" +{return x16;} + YY_BREAK +case 23: +YY_RULE_SETUP +#line 87 "src/lexer.l" +{return x17;} + YY_BREAK +case 24: +YY_RULE_SETUP +#line 88 "src/lexer.l" +{return x18;} + YY_BREAK +case 25: +YY_RULE_SETUP +#line 89 "src/lexer.l" +{return x19;} + YY_BREAK +case 26: +YY_RULE_SETUP +#line 90 "src/lexer.l" +{return x20;} + YY_BREAK +case 27: +YY_RULE_SETUP +#line 91 "src/lexer.l" +{return x21;} + YY_BREAK +case 28: +YY_RULE_SETUP +#line 92 "src/lexer.l" +{return x22;} + YY_BREAK +case 29: +YY_RULE_SETUP +#line 93 "src/lexer.l" +{return x23;} + YY_BREAK +case 30: +YY_RULE_SETUP +#line 94 "src/lexer.l" +{return x24;} + YY_BREAK +case 31: +YY_RULE_SETUP +#line 95 "src/lexer.l" +{return x25;} + YY_BREAK +case 32: +YY_RULE_SETUP +#line 96 "src/lexer.l" +{return x26;} + YY_BREAK +case 33: +YY_RULE_SETUP +#line 97 "src/lexer.l" +{return x27;} + YY_BREAK +case 34: +YY_RULE_SETUP +#line 98 "src/lexer.l" +{return x28;} + YY_BREAK +case 35: +YY_RULE_SETUP +#line 99 "src/lexer.l" +{return x29;} + YY_BREAK +case 36: +YY_RULE_SETUP +#line 100 "src/lexer.l" +{return x30;} + YY_BREAK +case 37: +YY_RULE_SETUP +#line 101 "src/lexer.l" +{return x31;} + YY_BREAK +case 38: +YY_RULE_SETUP +#line 102 "src/lexer.l" +{return x32;} + YY_BREAK +case 39: +YY_RULE_SETUP +#line 103 "src/lexer.l" +{return x33;} + YY_BREAK +case 40: +YY_RULE_SETUP +#line 104 "src/lexer.l" +{return x34;} + YY_BREAK +case 41: +YY_RULE_SETUP +#line 105 "src/lexer.l" +{return x35;} + YY_BREAK +case 42: +YY_RULE_SETUP +#line 106 "src/lexer.l" +{return x36;} + YY_BREAK +case 43: +YY_RULE_SETUP +#line 107 "src/lexer.l" +{return x37;} + YY_BREAK +case 44: +YY_RULE_SETUP +#line 108 "src/lexer.l" +{return x38;} + YY_BREAK +case 45: +YY_RULE_SETUP +#line 109 "src/lexer.l" +{return x39;} + YY_BREAK +case 46: +YY_RULE_SETUP +#line 110 "src/lexer.l" +{return x40;} + YY_BREAK +case 47: +YY_RULE_SETUP +#line 111 "src/lexer.l" +{return x41;} + YY_BREAK +case 48: +YY_RULE_SETUP +#line 112 "src/lexer.l" +{return x42;} + YY_BREAK +case 49: +YY_RULE_SETUP +#line 113 "src/lexer.l" +{return x43;} + YY_BREAK +case 50: +YY_RULE_SETUP +#line 114 "src/lexer.l" +{return x44;} + YY_BREAK +case 51: +YY_RULE_SETUP +#line 115 "src/lexer.l" +{return x45;} + YY_BREAK +case 52: +YY_RULE_SETUP +#line 116 "src/lexer.l" +{return x46;} + YY_BREAK +case 53: +YY_RULE_SETUP +#line 117 "src/lexer.l" +{return x47;} + YY_BREAK +case 54: +YY_RULE_SETUP +#line 118 "src/lexer.l" +{return x48;} + YY_BREAK +case 55: +YY_RULE_SETUP +#line 119 "src/lexer.l" +{return x49;} + YY_BREAK +case 56: +YY_RULE_SETUP +#line 120 "src/lexer.l" +{return x50;} + YY_BREAK +case 57: +YY_RULE_SETUP +#line 121 "src/lexer.l" +{return x51;} + YY_BREAK +case 58: +YY_RULE_SETUP +#line 122 "src/lexer.l" +{return x52;} + YY_BREAK +case 59: +YY_RULE_SETUP +#line 123 "src/lexer.l" +{return x53;} + YY_BREAK +case 60: +YY_RULE_SETUP +#line 124 "src/lexer.l" +{return x54;} + YY_BREAK +case 61: +YY_RULE_SETUP +#line 125 "src/lexer.l" +{return x55;} + YY_BREAK +case 62: +YY_RULE_SETUP +#line 126 "src/lexer.l" +{return x56;} + YY_BREAK +case 63: +YY_RULE_SETUP +#line 127 "src/lexer.l" +{return x57;} + YY_BREAK +case 64: +YY_RULE_SETUP +#line 128 "src/lexer.l" +{return x58;} + YY_BREAK +case 65: +YY_RULE_SETUP +#line 129 "src/lexer.l" +{return x59;} + YY_BREAK +case 66: +YY_RULE_SETUP +#line 130 "src/lexer.l" +{return x60;} + YY_BREAK +case 67: +YY_RULE_SETUP +#line 131 "src/lexer.l" +{return x61;} + YY_BREAK +case 68: +YY_RULE_SETUP +#line 132 "src/lexer.l" +{return x62;} + YY_BREAK +case 69: +YY_RULE_SETUP +#line 133 "src/lexer.l" +{return x63;} + YY_BREAK +case 70: +YY_RULE_SETUP +#line 134 "src/lexer.l" +{return x64;} + YY_BREAK +case 71: +YY_RULE_SETUP +#line 135 "src/lexer.l" +{return x65;} + YY_BREAK +case 72: +YY_RULE_SETUP +#line 136 "src/lexer.l" +{return x66;} + YY_BREAK +case 73: +YY_RULE_SETUP +#line 137 "src/lexer.l" +{return x67;} + YY_BREAK +case 74: +YY_RULE_SETUP +#line 138 "src/lexer.l" +{return x68;} + YY_BREAK +case 75: +YY_RULE_SETUP +#line 139 "src/lexer.l" +{return x69;} + YY_BREAK +case 76: +YY_RULE_SETUP +#line 140 "src/lexer.l" +{return x70;} + YY_BREAK +case 77: +YY_RULE_SETUP +#line 141 "src/lexer.l" +{return x71;} + YY_BREAK +case 78: +YY_RULE_SETUP +#line 142 "src/lexer.l" +{return x72;} + YY_BREAK +case 79: +YY_RULE_SETUP +#line 143 "src/lexer.l" +{return x73;} + YY_BREAK +case 80: +YY_RULE_SETUP +#line 144 "src/lexer.l" +{return x74;} + YY_BREAK +case 81: +YY_RULE_SETUP +#line 145 "src/lexer.l" +{return x75;} + YY_BREAK +case 82: +YY_RULE_SETUP +#line 146 "src/lexer.l" +{return x76;} + YY_BREAK +case 83: +YY_RULE_SETUP +#line 147 "src/lexer.l" +{return x77;} + YY_BREAK +case 84: +YY_RULE_SETUP +#line 148 "src/lexer.l" +{return x78;} + YY_BREAK +case 85: +YY_RULE_SETUP +#line 149 "src/lexer.l" +{return x79;} + YY_BREAK +case 86: +YY_RULE_SETUP +#line 150 "src/lexer.l" +{return x80;} + YY_BREAK +case 87: +YY_RULE_SETUP +#line 152 "src/lexer.l" +{return addi; /* i */} + YY_BREAK +case 88: +YY_RULE_SETUP +#line 153 "src/lexer.l" +{return slti;} + YY_BREAK +case 89: +YY_RULE_SETUP +#line 154 "src/lexer.l" +{return sgei;} + YY_BREAK +case 90: +YY_RULE_SETUP +#line 155 "src/lexer.l" +{return seqi;} + YY_BREAK +case 91: +YY_RULE_SETUP +#line 156 "src/lexer.l" +{return snei;} + YY_BREAK +case 92: +YY_RULE_SETUP +#line 157 "src/lexer.l" +{return unop;} + YY_BREAK +case 93: +YY_RULE_SETUP +#line 158 "src/lexer.l" +{return diop;} + YY_BREAK +case 94: +YY_RULE_SETUP +#line 159 "src/lexer.l" +{return slli;} + YY_BREAK +case 95: +YY_RULE_SETUP +#line 160 "src/lexer.l" +{return srli;} + YY_BREAK +case 96: +YY_RULE_SETUP +#line 161 "src/lexer.l" +{return sll;} + YY_BREAK +case 97: +YY_RULE_SETUP +#line 162 "src/lexer.l" +{return srl;} + YY_BREAK +case 98: +YY_RULE_SETUP +#line 163 "src/lexer.l" +{return add;} + YY_BREAK +case 99: +YY_RULE_SETUP +#line 164 "src/lexer.l" +{return sub;} + YY_BREAK +case 100: +YY_RULE_SETUP +#line 165 "src/lexer.l" +{return slt;} + YY_BREAK +case 101: +YY_RULE_SETUP +#line 166 "src/lexer.l" +{return sge;} + YY_BREAK +case 102: +YY_RULE_SETUP +#line 167 "src/lexer.l" +{return seq;} + YY_BREAK +case 103: +YY_RULE_SETUP +#line 168 "src/lexer.l" +{return sne;} + YY_BREAK +case 104: +YY_RULE_SETUP +#line 169 "src/lexer.l" +{return lui;} + YY_BREAK +case 105: +YY_RULE_SETUP +#line 170 "src/lexer.l" +{return auipc;} + YY_BREAK +case 106: +YY_RULE_SETUP +#line 171 "src/lexer.l" +{return jal;} + YY_BREAK +case 107: +YY_RULE_SETUP +#line 172 "src/lexer.l" +{return jalr;} + YY_BREAK +case 108: +YY_RULE_SETUP +#line 173 "src/lexer.l" +{return beq;} + YY_BREAK +case 109: +YY_RULE_SETUP +#line 174 "src/lexer.l" +{return bne;} + YY_BREAK +case 110: +YY_RULE_SETUP +#line 175 "src/lexer.l" +{return blt;} + YY_BREAK +case 111: +YY_RULE_SETUP +#line 176 "src/lexer.l" +{return bge;} + YY_BREAK +case 112: +YY_RULE_SETUP +#line 177 "src/lexer.l" +{return ld;} + YY_BREAK +case 113: +YY_RULE_SETUP +#line 178 "src/lexer.l" +{return st;} + YY_BREAK +case 114: +YY_RULE_SETUP +#line 179 "src/lexer.l" +{return ecall;} + YY_BREAK +case 115: +YY_RULE_SETUP +#line 180 "src/lexer.l" +{return ebreak;} + YY_BREAK +case 116: +YY_RULE_SETUP +#line 181 "src/lexer.l" +{return pcall;} + YY_BREAK +case 117: +YY_RULE_SETUP +#line 182 "src/lexer.l" +{return fence;} + YY_BREAK +case 118: +YY_RULE_SETUP +#line 183 "src/lexer.l" +{return nop; /* meta */} + YY_BREAK +case 119: +YY_RULE_SETUP +#line 184 "src/lexer.l" +{return li;} + YY_BREAK +case 120: +YY_RULE_SETUP +#line 185 "src/lexer.l" +{return la;} + YY_BREAK +case 121: +YY_RULE_SETUP +#line 187 "src/lexer.l" +{return mul; /* m */} + YY_BREAK +case 122: +YY_RULE_SETUP +#line 188 "src/lexer.l" +{return diV;} + YY_BREAK +case 123: +YY_RULE_SETUP +#line 189 "src/lexer.l" +{return rem;} + YY_BREAK +case 124: +YY_RULE_SETUP +#line 191 "src/lexer.l" +{return stt; /* a */} + YY_BREAK +case 125: +YY_RULE_SETUP +#line 192 "src/lexer.l" +{return cst;} + YY_BREAK +case 126: +YY_RULE_SETUP +#line 193 "src/lexer.l" +{return ent;} + YY_BREAK +case 127: +YY_RULE_SETUP +#line 194 "src/lexer.l" +{return cat;} + YY_BREAK +case 128: +YY_RULE_SETUP +#line 196 "src/lexer.l" +{return csrrw; /* Zcsr */} + YY_BREAK +case 129: +YY_RULE_SETUP +#line 197 "src/lexer.l" +{return csrrs;} + YY_BREAK +case 130: +YY_RULE_SETUP +#line 198 "src/lexer.l" +{return csrrc;} + YY_BREAK +case 131: +YY_RULE_SETUP +#line 200 "src/lexer.l" +{/* skip line comments */} + YY_BREAK +case 132: +YY_RULE_SETUP +#line 202 "src/lexer.l" +{BEGIN(SC_COMMENT);} + YY_BREAK + +case 133: +YY_RULE_SETUP +#line 204 "src/lexer.l" +{++parser->comment_nesting;} + YY_BREAK +case 134: +YY_RULE_SETUP +#line 205 "src/lexer.l" +{ + if (parser->comment_nesting) + --parser->comment_nesting; + else + BEGIN(INITIAL); + } + YY_BREAK +case 135: +YY_RULE_SETUP +#line 212 "src/lexer.l" +{} + YY_BREAK +case 136: +YY_RULE_SETUP +#line 213 "src/lexer.l" +{} + YY_BREAK +case 137: +YY_RULE_SETUP +#line 214 "src/lexer.l" +{} + YY_BREAK +case 138: +/* rule 138 can match eol */ +YY_RULE_SETUP +#line 215 "src/lexer.l" +{} + YY_BREAK + +case 139: +YY_RULE_SETUP +#line 218 "src/lexer.l" +{ + yylval->str = yytext; + return id; +} + YY_BREAK +case 140: +YY_RULE_SETUP +#line 223 "src/lexer.l" +{return LPAREN;} + YY_BREAK +case 141: +YY_RULE_SETUP +#line 224 "src/lexer.l" +{return RPAREN;} + YY_BREAK +case 142: +YY_RULE_SETUP +#line 225 "src/lexer.l" +{return COMMA;} + YY_BREAK +case 143: +/* rule 143 can match eol */ +YY_RULE_SETUP +#line 227 "src/lexer.l" +{/* skip whitespace */} + YY_BREAK +case 144: +YY_RULE_SETUP +#line 229 "src/lexer.l" +{ + struct src_issue issue; + issue.loc = to_src_loc(yylloc); + issue.fctx.fbuf = parser->buf; + issue.fctx.fname = parser->fname; + src_issue(issue, "unexpected token: %s", yytext); + parser->failed = true; +} + YY_BREAK +case 145: +YY_RULE_SETUP +#line 237 "src/lexer.l" +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK +#line 1837 "gen/gen_lexer.inc" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(SC_COMMENT): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 234 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 234 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 233); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 237 "src/lexer.l" + + diff --git a/tasm/gen/gen_parser.c b/tasm/gen/gen_parser.c new file mode 100644 index 0000000..79b33b1 --- /dev/null +++ b/tasm/gen/gen_parser.c @@ -0,0 +1,3229 @@ +/* A Bison parser, made by GNU Bison 3.8.2. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output, and Bison version. */ +#define YYBISON 30802 + +/* Bison version string. */ +#define YYBISON_VERSION "3.8.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 2 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* First part of user prologue. */ +#line 4 "src/parser.y" + + +/* get access to fileno to avoid warnings with flex */ +#define _POSIX_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include <tasm/assembler.h> +#include <tasm/parser.h> +#include <tasm/bits.h> +#include <tasm/regs.h> +#include <tri.h> + + +#line 89 "gen/gen_parser.c" + +# ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast<Type> (Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val) +# else +# define YY_CAST(Type, Val) ((Type) (Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) +# endif +# endif +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + + +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 1 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Token kinds. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + YYEMPTY = -2, + YYEOF = 0, /* "end of file" */ + YYerror = 256, /* error */ + YYUNDEF = 257, /* "invalid token" */ + imm = 258, /* imm */ + label = 259, /* label */ + str = 260, /* str */ + id = 261, /* id */ + COMMA = 262, /* "," */ + LPAREN = 263, /* "(" */ + RPAREN = 264, /* ")" */ + set = 265, /* set */ + include = 266, /* include */ + x0 = 267, /* x0 */ + x1 = 268, /* x1 */ + x2 = 269, /* x2 */ + x3 = 270, /* x3 */ + x4 = 271, /* x4 */ + x5 = 272, /* x5 */ + x6 = 273, /* x6 */ + x7 = 274, /* x7 */ + x8 = 275, /* x8 */ + x9 = 276, /* x9 */ + x10 = 277, /* x10 */ + x11 = 278, /* x11 */ + x12 = 279, /* x12 */ + x13 = 280, /* x13 */ + x14 = 281, /* x14 */ + x15 = 282, /* x15 */ + x16 = 283, /* x16 */ + x17 = 284, /* x17 */ + x18 = 285, /* x18 */ + x19 = 286, /* x19 */ + x20 = 287, /* x20 */ + x21 = 288, /* x21 */ + x22 = 289, /* x22 */ + x23 = 290, /* x23 */ + x24 = 291, /* x24 */ + x25 = 292, /* x25 */ + x26 = 293, /* x26 */ + x27 = 294, /* x27 */ + x28 = 295, /* x28 */ + x29 = 296, /* x29 */ + x30 = 297, /* x30 */ + x31 = 298, /* x31 */ + x32 = 299, /* x32 */ + x33 = 300, /* x33 */ + x34 = 301, /* x34 */ + x35 = 302, /* x35 */ + x36 = 303, /* x36 */ + x37 = 304, /* x37 */ + x38 = 305, /* x38 */ + x39 = 306, /* x39 */ + x40 = 307, /* x40 */ + x41 = 308, /* x41 */ + x42 = 309, /* x42 */ + x43 = 310, /* x43 */ + x44 = 311, /* x44 */ + x45 = 312, /* x45 */ + x46 = 313, /* x46 */ + x47 = 314, /* x47 */ + x48 = 315, /* x48 */ + x49 = 316, /* x49 */ + x50 = 317, /* x50 */ + x51 = 318, /* x51 */ + x52 = 319, /* x52 */ + x53 = 320, /* x53 */ + x54 = 321, /* x54 */ + x55 = 322, /* x55 */ + x56 = 323, /* x56 */ + x57 = 324, /* x57 */ + x58 = 325, /* x58 */ + x59 = 326, /* x59 */ + x60 = 327, /* x60 */ + x61 = 328, /* x61 */ + x62 = 329, /* x62 */ + x63 = 330, /* x63 */ + x64 = 331, /* x64 */ + x65 = 332, /* x65 */ + x66 = 333, /* x66 */ + x67 = 334, /* x67 */ + x68 = 335, /* x68 */ + x69 = 336, /* x69 */ + x70 = 337, /* x70 */ + x71 = 338, /* x71 */ + x72 = 339, /* x72 */ + x73 = 340, /* x73 */ + x74 = 341, /* x74 */ + x75 = 342, /* x75 */ + x76 = 343, /* x76 */ + x77 = 344, /* x77 */ + x78 = 345, /* x78 */ + x79 = 346, /* x79 */ + x80 = 347, /* x80 */ + addi = 348, /* addi */ + slti = 349, /* slti */ + sgei = 350, /* sgei */ + seqi = 351, /* seqi */ + snei = 352, /* snei */ + unop = 353, /* unop */ + diop = 354, /* diop */ + slli = 355, /* slli */ + srli = 356, /* srli */ + sll = 357, /* sll */ + srl = 358, /* srl */ + add = 359, /* add */ + sub = 360, /* sub */ + slt = 361, /* slt */ + sge = 362, /* sge */ + seq = 363, /* seq */ + sne = 364, /* sne */ + lui = 365, /* lui */ + auipc = 366, /* auipc */ + jal = 367, /* jal */ + jalr = 368, /* jalr */ + beq = 369, /* beq */ + bne = 370, /* bne */ + blt = 371, /* blt */ + bge = 372, /* bge */ + ld = 373, /* ld */ + st = 374, /* st */ + ecall = 375, /* ecall */ + ebreak = 376, /* ebreak */ + pcall = 377, /* pcall */ + fence = 378, /* fence */ + li = 379, /* li */ + la = 380, /* la */ + nop = 381, /* nop */ + mul = 382, /* mul */ + diV = 383, /* diV */ + rem = 384, /* rem */ + stt = 385, /* stt */ + cst = 386, /* cst */ + ent = 387, /* ent */ + cat = 388, /* cat */ + csrrw = 389, /* csrrw */ + csrrs = 390, /* csrrs */ + csrrc = 391 /* csrrc */ + }; + typedef enum yytokentype yytoken_kind_t; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +union YYSTYPE +{ +#line 32 "src/parser.y" + + const char *str; + enum gpr_num gpr; + tri_t tri; + +#line 278 "gen/gen_parser.c" + +}; +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + +/* Location type. */ +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE YYLTYPE; +struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +}; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + + + +int yyparse (void *scanner, struct parser *parser, struct asm_ctx *ctx); + + + +/* Symbol kind. */ +enum yysymbol_kind_t +{ + YYSYMBOL_YYEMPTY = -2, + YYSYMBOL_YYEOF = 0, /* "end of file" */ + YYSYMBOL_YYerror = 1, /* error */ + YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ + YYSYMBOL_imm = 3, /* imm */ + YYSYMBOL_label = 4, /* label */ + YYSYMBOL_str = 5, /* str */ + YYSYMBOL_id = 6, /* id */ + YYSYMBOL_COMMA = 7, /* "," */ + YYSYMBOL_LPAREN = 8, /* "(" */ + YYSYMBOL_RPAREN = 9, /* ")" */ + YYSYMBOL_set = 10, /* set */ + YYSYMBOL_include = 11, /* include */ + YYSYMBOL_x0 = 12, /* x0 */ + YYSYMBOL_x1 = 13, /* x1 */ + YYSYMBOL_x2 = 14, /* x2 */ + YYSYMBOL_x3 = 15, /* x3 */ + YYSYMBOL_x4 = 16, /* x4 */ + YYSYMBOL_x5 = 17, /* x5 */ + YYSYMBOL_x6 = 18, /* x6 */ + YYSYMBOL_x7 = 19, /* x7 */ + YYSYMBOL_x8 = 20, /* x8 */ + YYSYMBOL_x9 = 21, /* x9 */ + YYSYMBOL_x10 = 22, /* x10 */ + YYSYMBOL_x11 = 23, /* x11 */ + YYSYMBOL_x12 = 24, /* x12 */ + YYSYMBOL_x13 = 25, /* x13 */ + YYSYMBOL_x14 = 26, /* x14 */ + YYSYMBOL_x15 = 27, /* x15 */ + YYSYMBOL_x16 = 28, /* x16 */ + YYSYMBOL_x17 = 29, /* x17 */ + YYSYMBOL_x18 = 30, /* x18 */ + YYSYMBOL_x19 = 31, /* x19 */ + YYSYMBOL_x20 = 32, /* x20 */ + YYSYMBOL_x21 = 33, /* x21 */ + YYSYMBOL_x22 = 34, /* x22 */ + YYSYMBOL_x23 = 35, /* x23 */ + YYSYMBOL_x24 = 36, /* x24 */ + YYSYMBOL_x25 = 37, /* x25 */ + YYSYMBOL_x26 = 38, /* x26 */ + YYSYMBOL_x27 = 39, /* x27 */ + YYSYMBOL_x28 = 40, /* x28 */ + YYSYMBOL_x29 = 41, /* x29 */ + YYSYMBOL_x30 = 42, /* x30 */ + YYSYMBOL_x31 = 43, /* x31 */ + YYSYMBOL_x32 = 44, /* x32 */ + YYSYMBOL_x33 = 45, /* x33 */ + YYSYMBOL_x34 = 46, /* x34 */ + YYSYMBOL_x35 = 47, /* x35 */ + YYSYMBOL_x36 = 48, /* x36 */ + YYSYMBOL_x37 = 49, /* x37 */ + YYSYMBOL_x38 = 50, /* x38 */ + YYSYMBOL_x39 = 51, /* x39 */ + YYSYMBOL_x40 = 52, /* x40 */ + YYSYMBOL_x41 = 53, /* x41 */ + YYSYMBOL_x42 = 54, /* x42 */ + YYSYMBOL_x43 = 55, /* x43 */ + YYSYMBOL_x44 = 56, /* x44 */ + YYSYMBOL_x45 = 57, /* x45 */ + YYSYMBOL_x46 = 58, /* x46 */ + YYSYMBOL_x47 = 59, /* x47 */ + YYSYMBOL_x48 = 60, /* x48 */ + YYSYMBOL_x49 = 61, /* x49 */ + YYSYMBOL_x50 = 62, /* x50 */ + YYSYMBOL_x51 = 63, /* x51 */ + YYSYMBOL_x52 = 64, /* x52 */ + YYSYMBOL_x53 = 65, /* x53 */ + YYSYMBOL_x54 = 66, /* x54 */ + YYSYMBOL_x55 = 67, /* x55 */ + YYSYMBOL_x56 = 68, /* x56 */ + YYSYMBOL_x57 = 69, /* x57 */ + YYSYMBOL_x58 = 70, /* x58 */ + YYSYMBOL_x59 = 71, /* x59 */ + YYSYMBOL_x60 = 72, /* x60 */ + YYSYMBOL_x61 = 73, /* x61 */ + YYSYMBOL_x62 = 74, /* x62 */ + YYSYMBOL_x63 = 75, /* x63 */ + YYSYMBOL_x64 = 76, /* x64 */ + YYSYMBOL_x65 = 77, /* x65 */ + YYSYMBOL_x66 = 78, /* x66 */ + YYSYMBOL_x67 = 79, /* x67 */ + YYSYMBOL_x68 = 80, /* x68 */ + YYSYMBOL_x69 = 81, /* x69 */ + YYSYMBOL_x70 = 82, /* x70 */ + YYSYMBOL_x71 = 83, /* x71 */ + YYSYMBOL_x72 = 84, /* x72 */ + YYSYMBOL_x73 = 85, /* x73 */ + YYSYMBOL_x74 = 86, /* x74 */ + YYSYMBOL_x75 = 87, /* x75 */ + YYSYMBOL_x76 = 88, /* x76 */ + YYSYMBOL_x77 = 89, /* x77 */ + YYSYMBOL_x78 = 90, /* x78 */ + YYSYMBOL_x79 = 91, /* x79 */ + YYSYMBOL_x80 = 92, /* x80 */ + YYSYMBOL_addi = 93, /* addi */ + YYSYMBOL_slti = 94, /* slti */ + YYSYMBOL_sgei = 95, /* sgei */ + YYSYMBOL_seqi = 96, /* seqi */ + YYSYMBOL_snei = 97, /* snei */ + YYSYMBOL_unop = 98, /* unop */ + YYSYMBOL_diop = 99, /* diop */ + YYSYMBOL_slli = 100, /* slli */ + YYSYMBOL_srli = 101, /* srli */ + YYSYMBOL_sll = 102, /* sll */ + YYSYMBOL_srl = 103, /* srl */ + YYSYMBOL_add = 104, /* add */ + YYSYMBOL_sub = 105, /* sub */ + YYSYMBOL_slt = 106, /* slt */ + YYSYMBOL_sge = 107, /* sge */ + YYSYMBOL_seq = 108, /* seq */ + YYSYMBOL_sne = 109, /* sne */ + YYSYMBOL_lui = 110, /* lui */ + YYSYMBOL_auipc = 111, /* auipc */ + YYSYMBOL_jal = 112, /* jal */ + YYSYMBOL_jalr = 113, /* jalr */ + YYSYMBOL_beq = 114, /* beq */ + YYSYMBOL_bne = 115, /* bne */ + YYSYMBOL_blt = 116, /* blt */ + YYSYMBOL_bge = 117, /* bge */ + YYSYMBOL_ld = 118, /* ld */ + YYSYMBOL_st = 119, /* st */ + YYSYMBOL_ecall = 120, /* ecall */ + YYSYMBOL_ebreak = 121, /* ebreak */ + YYSYMBOL_pcall = 122, /* pcall */ + YYSYMBOL_fence = 123, /* fence */ + YYSYMBOL_li = 124, /* li */ + YYSYMBOL_la = 125, /* la */ + YYSYMBOL_nop = 126, /* nop */ + YYSYMBOL_mul = 127, /* mul */ + YYSYMBOL_diV = 128, /* diV */ + YYSYMBOL_rem = 129, /* rem */ + YYSYMBOL_stt = 130, /* stt */ + YYSYMBOL_cst = 131, /* cst */ + YYSYMBOL_ent = 132, /* ent */ + YYSYMBOL_cat = 133, /* cat */ + YYSYMBOL_csrrw = 134, /* csrrw */ + YYSYMBOL_csrrs = 135, /* csrrs */ + YYSYMBOL_csrrc = 136, /* csrrc */ + YYSYMBOL_YYACCEPT = 137, /* $accept */ + YYSYMBOL_width = 138, /* width */ + YYSYMBOL_addr = 139, /* addr */ + YYSYMBOL_gpr = 140, /* gpr */ + YYSYMBOL_i = 141, /* i */ + YYSYMBOL_m = 142, /* m */ + YYSYMBOL_a = 143, /* a */ + YYSYMBOL_Zcsr = 144, /* Zcsr */ + YYSYMBOL_csr = 145, /* csr */ + YYSYMBOL_statement = 146, /* statement */ + YYSYMBOL_directive = 147, /* directive */ + YYSYMBOL_top = 148, /* top */ + YYSYMBOL_unit = 149, /* unit */ + YYSYMBOL_input = 150 /* input */ +}; +typedef enum yysymbol_kind_t yysymbol_kind_t; + + +/* Second part of user prologue. */ +#line 87 "src/parser.y" + + +struct file_ctx { + const char *fname; + const char *fbuf; +}; + +struct src_loc { + int first_line; + int last_line; + int first_col; + int last_col; +}; + +struct src_issue { + struct src_loc loc; + struct file_ctx fctx; +}; + +/** Modifies the signature of yylex to fit our parser better. */ +#define YY_DECL int yylex(YYSTYPE *yylval, YYLTYPE *yylloc, \ + void *yyscanner, struct parser *parser) + +/** + * Declare yylex. + * + * @param yylval Bison current value. + * @param yylloc Bison location info. + * @param yyscanner Flex scanner. + * @param parser Current parser state. + * @return \c 0 when succesful, \c 1 otherwise. + * More info on yylex() can be found in the flex manual. + */ +YY_DECL; + +/** + * Convert bison location info to our own source location info. + * + * @param yylloc Bison location info. + * @return Internal location info. + */ +static struct src_loc to_src_loc(YYLTYPE *yylloc); + +/** + * Print parsing error. + * Automatically called by bison. + * + * @param yylloc Location of error. + * @param lexer Lexer. + * @param parser Parser state. + * @param msg Message to print. + */ +static void yyerror(YYLTYPE *yylloc, void *lexer, + struct parser *parser, struct asm_ctx *ctx, const char *msg); + + +#line 524 "gen/gen_parser.c" + + +#ifdef short +# undef short +#endif + +/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure + <limits.h> and (if available) <stdint.h> are included + so that the code can choose integer types of a good width. */ + +#ifndef __PTRDIFF_MAX__ +# include <limits.h> /* INFRINGES ON USER NAME SPACE */ +# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include <stdint.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_STDINT_H +# endif +#endif + +/* Narrow types that promote to a signed type and that can represent a + signed or unsigned integer of at least N bits. In tables they can + save space and decrease cache pressure. Promoting to a signed type + helps avoid bugs in integer arithmetic. */ + +#ifdef __INT_LEAST8_MAX__ +typedef __INT_LEAST8_TYPE__ yytype_int8; +#elif defined YY_STDINT_H +typedef int_least8_t yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef __INT_LEAST16_MAX__ +typedef __INT_LEAST16_TYPE__ yytype_int16; +#elif defined YY_STDINT_H +typedef int_least16_t yytype_int16; +#else +typedef short yytype_int16; +#endif + +/* Work around bug in HP-UX 11.23, which defines these macros + incorrectly for preprocessor constants. This workaround can likely + be removed in 2023, as HPE has promised support for HP-UX 11.23 + (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of + <https://h20195.www2.hpe.com/V2/getpdf.aspx/4AA4-7673ENW.pdf>. */ +#ifdef __hpux +# undef UINT_LEAST8_MAX +# undef UINT_LEAST16_MAX +# define UINT_LEAST8_MAX 255 +# define UINT_LEAST16_MAX 65535 +#endif + +#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST8_TYPE__ yytype_uint8; +#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST8_MAX <= INT_MAX) +typedef uint_least8_t yytype_uint8; +#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX +typedef unsigned char yytype_uint8; +#else +typedef short yytype_uint8; +#endif + +#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST16_TYPE__ yytype_uint16; +#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST16_MAX <= INT_MAX) +typedef uint_least16_t yytype_uint16; +#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX +typedef unsigned short yytype_uint16; +#else +typedef int yytype_uint16; +#endif + +#ifndef YYPTRDIFF_T +# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ +# define YYPTRDIFF_T __PTRDIFF_TYPE__ +# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ +# elif defined PTRDIFF_MAX +# ifndef ptrdiff_t +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# endif +# define YYPTRDIFF_T ptrdiff_t +# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX +# else +# define YYPTRDIFF_T long +# define YYPTRDIFF_MAXIMUM LONG_MAX +# endif +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned +# endif +#endif + +#define YYSIZE_MAXIMUM \ + YY_CAST (YYPTRDIFF_T, \ + (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ + ? YYPTRDIFF_MAXIMUM \ + : YY_CAST (YYSIZE_T, -1))) + +#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) + + +/* Stored state numbers (used for stacks). */ +typedef yytype_int16 yy_state_t; + +/* State numbers in computations. */ +typedef int yy_state_fast_t; + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + + +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define YY_ATTRIBUTE_PURE +# endif +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +# else +# define YY_ATTRIBUTE_UNUSED +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YY_USE(E) ((void) (E)) +#else +# define YY_USE(E) /* empty */ +#endif + +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ +# if __GNUC__ * 100 + __GNUC_MINOR__ < 407 +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") +# else +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# endif +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END \ + _Pragma ("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + + +#define YY_ASSERT(E) ((void) (0 && (E))) + +#if 1 + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* 1 */ + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yy_state_t yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \ + + YYSIZEOF (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYPTRDIFF_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / YYSIZEOF (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYPTRDIFF_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 180 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 396 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 137 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 14 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 142 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 328 + +/* YYMAXUTOK -- Last valid token kind. */ +#define YYMAXUTOK 391 + + +/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, with out-of-bounds checking. */ +#define YYTRANSLATE(YYX) \ + (0 <= (YYX) && (YYX) <= YYMAXUTOK \ + ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ + : YYSYMBOL_YYUNDEF) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136 +}; + +#if YYDEBUG +/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_int16 yyrline[] = +{ + 0, 148, 148, 153, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 240, 243, 246, 249, 252, + 255, 258, 261, 264, 267, 270, 273, 276, 279, 282, + 285, 288, 291, 295, 298, 302, 306, 310, 314, 317, + 320, 323, 326, 329, 332, 335, 339, 342, 348, 355, + 358, 361, 365, 368, 371, 374, 378, 381, 384, 388, + 391, 392, 393, 394, 397, 398, 401, 402, 403, 406, + 407, 410, 411 +}; +#endif + +/** Accessing symbol of state STATE. */ +#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) + +#if 1 +/* The user-facing name of the symbol whose (internal) number is + YYSYMBOL. No bounds checking. */ +static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; + +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "\"end of file\"", "error", "\"invalid token\"", "imm", "label", "str", + "id", "\",\"", "\"(\"", "\")\"", "set", "include", "x0", "x1", "x2", + "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", + "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", + "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", "x32", "x33", + "x34", "x35", "x36", "x37", "x38", "x39", "x40", "x41", "x42", "x43", + "x44", "x45", "x46", "x47", "x48", "x49", "x50", "x51", "x52", "x53", + "x54", "x55", "x56", "x57", "x58", "x59", "x60", "x61", "x62", "x63", + "x64", "x65", "x66", "x67", "x68", "x69", "x70", "x71", "x72", "x73", + "x74", "x75", "x76", "x77", "x78", "x79", "x80", "addi", "slti", "sgei", + "seqi", "snei", "unop", "diop", "slli", "srli", "sll", "srl", "add", + "sub", "slt", "sge", "seq", "sne", "lui", "auipc", "jal", "jalr", "beq", + "bne", "blt", "bge", "ld", "st", "ecall", "ebreak", "pcall", "fence", + "li", "la", "nop", "mul", "diV", "rem", "stt", "cst", "ent", "cat", + "csrrw", "csrrs", "csrrc", "$accept", "width", "addr", "gpr", "i", "m", + "a", "Zcsr", "csr", "statement", "directive", "top", "unit", "input", YY_NULLPTR +}; + +static const char * +yysymbol_name (yysymbol_kind_t yysymbol) +{ + return yytname[yysymbol]; +} +#endif + +#define YYPACT_NINF (-187) + +#define yypact_value_is_default(Yyn) \ + ((Yyn) == YYPACT_NINF) + +#define YYTABLE_NINF (-1) + +#define yytable_value_is_error(Yyn) \ + 0 + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 32, -187, 22, 24, 304, 304, 304, 304, 304, 304, + 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, + 304, 304, 304, 304, 304, 304, 304, 304, 304, 26, + 26, -187, -187, -187, -187, 304, 304, -187, 304, 304, + 304, -187, 26, 304, -187, 31, 31, 31, -187, -187, + -187, -187, -187, -187, 32, -187, 40, 38, -187, -187, + -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, + -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, + -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, + -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, + -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, + -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, + -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, + -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, + 37, 39, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, -187, 64, 65, 66, 67, + 68, 69, 70, 71, -187, -187, 72, 73, 74, -187, + -187, -187, 304, 304, 304, 304, 304, 304, 304, 304, + 304, 304, 304, 304, 304, 304, 304, 304, 304, 79, + 80, 78, 304, 304, 304, 304, 304, 304, 304, 82, + 78, 304, 304, 304, 304, 304, 304, 304, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, -187, -187, -187, -187, 101, + 102, 103, 104, 105, 106, 107, -187, -187, 108, 109, + 110, 111, 112, 113, 114, 83, 119, 120, 121, 166, + 165, 304, 168, 169, 304, 304, 304, 304, 304, 304, + 304, 304, 170, 78, 78, 78, 78, 171, 172, 304, + 304, 304, 173, 304, 304, 304, -187, -187, -187, -187, + -187, -187, 187, -187, -187, -187, -187, -187, -187, -187, + -187, -187, -187, -187, -187, -187, -187, -187, 188, 196, + -187, -187, -187, 197, -187, -187, -187, 190, 304, 304, + 304, -187, 36, 204, 205, -187, -187, -187 +}; + +/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 142, 136, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 110, 111, 112, 113, 0, 0, 116, 0, 0, + 0, 122, 0, 0, 125, 0, 0, 0, 130, 132, + 131, 133, 137, 138, 139, 141, 0, 0, 135, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 124, 129, 0, 0, 0, 140, + 1, 134, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 100, 101, 3, 102, 0, + 0, 0, 0, 0, 0, 0, 118, 117, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 85, 86, 87, 88, + 89, 114, 0, 90, 91, 98, 99, 92, 93, 94, + 95, 96, 97, 103, 104, 105, 106, 107, 0, 0, + 119, 120, 121, 0, 126, 127, 128, 0, 0, 0, + 0, 115, 0, 0, 0, 108, 109, 123 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -187, -3, -186, -5, -187, -187, -187, -187, -21, -187, + -187, -187, -7, -187 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_uint8 yydefgoto[] = +{ + 0, 166, 238, 140, 48, 49, 50, 51, 176, 52, + 53, 54, 55, 56 +}; + +/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 247, 177, 178, 167, 57, 58, + 168, 169, 165, 170, 171, 172, 1, 175, 174, 173, + 180, 181, 2, 3, 182, 325, 183, 179, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 235, 236, 237, 246, 286, 304, 305, 306, + 307, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 287, 288, 289, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 290, + 291, 293, 294, 303, 308, 309, 313, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 317, 321, 318, 239, 240, 241, + 242, 243, 244, 245, 319, 320, 248, 249, 250, 251, + 252, 253, 254, 326, 327, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 292, 0, 0, 295, + 296, 297, 298, 299, 300, 301, 302, 0, 0, 0, + 0, 0, 0, 0, 310, 311, 312, 0, 314, 315, + 316, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 322, 323, 324, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139 +}; + +static const yytype_int16 yycheck[] = +{ + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 210, 46, 47, 30, 6, 5, + 35, 36, 6, 38, 39, 40, 4, 6, 43, 42, + 0, 3, 10, 11, 7, 9, 7, 54, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 3, 3, 6, 3, 3, 273, 274, 275, + 276, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 3, 3, 3, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 3, + 5, 3, 3, 3, 3, 3, 3, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 7, 5, 8, 202, 203, 204, + 205, 206, 207, 208, 8, 8, 211, 212, 213, 214, + 215, 216, 217, 9, 9, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 261, -1, -1, 264, + 265, 266, 267, 268, 269, 270, 271, -1, -1, -1, + -1, -1, -1, -1, 279, 280, 281, -1, 283, 284, + 285, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 318, 319, 320, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92 +}; + +/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of + state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 4, 10, 11, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 141, 142, + 143, 144, 146, 147, 148, 149, 150, 6, 5, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 6, 138, 138, 140, 140, + 140, 140, 140, 138, 140, 6, 145, 145, 145, 149, + 0, 3, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 3, 3, 6, 139, 140, + 140, 140, 140, 140, 140, 140, 3, 139, 140, 140, + 140, 140, 140, 140, 140, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, + 3, 5, 140, 3, 3, 140, 140, 140, 140, 140, + 140, 140, 140, 3, 139, 139, 139, 139, 3, 3, + 140, 140, 140, 3, 140, 140, 140, 7, 8, 8, + 8, 5, 140, 140, 140, 9, 9, 9 +}; + +/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ +static const yytype_uint8 yyr1[] = +{ + 0, 137, 138, 139, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 141, 141, 141, 141, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 142, + 142, 142, 143, 143, 143, 143, 144, 144, 144, 145, + 146, 146, 146, 146, 147, 147, 148, 148, 148, 149, + 149, 150, 150 +}; + +/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr2[] = +{ + 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 4, 4, 4, 6, 6, 6, 6, 6, 9, 9, + 1, 1, 1, 1, 6, 8, 1, 4, 4, 6, + 6, 6, 1, 9, 2, 1, 6, 6, 6, 1, + 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, + 2, 1, 0 +}; + + +enum { YYENOMEM = -2 }; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab +#define YYNOMEM goto yyexhaustedlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ + do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, scanner, parser, ctx, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ + while (0) + +/* Backward compatibility with an undocumented macro. + Use YYerror or YYUNDEF. */ +#define YYERRCODE YYUNDEF + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (0) +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + + +/* YYLOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +# ifndef YYLOCATION_PRINT + +# if defined YY_LOCATION_PRINT + + /* Temporary convenience wrapper in case some people defined the + undocumented and private YY_LOCATION_PRINT macros. */ +# define YYLOCATION_PRINT(File, Loc) YY_LOCATION_PRINT(File, *(Loc)) + +# elif defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + +/* Print *YYLOCP on YYO. Private, do not rely on its existence. */ + +YY_ATTRIBUTE_UNUSED +static int +yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) +{ + int res = 0; + int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; + if (0 <= yylocp->first_line) + { + res += YYFPRINTF (yyo, "%d", yylocp->first_line); + if (0 <= yylocp->first_column) + res += YYFPRINTF (yyo, ".%d", yylocp->first_column); + } + if (0 <= yylocp->last_line) + { + if (yylocp->first_line < yylocp->last_line) + { + res += YYFPRINTF (yyo, "-%d", yylocp->last_line); + if (0 <= end_col) + res += YYFPRINTF (yyo, ".%d", end_col); + } + else if (0 <= end_col && yylocp->first_column < end_col) + res += YYFPRINTF (yyo, "-%d", end_col); + } + return res; +} + +# define YYLOCATION_PRINT yy_location_print_ + + /* Temporary convenience wrapper in case some people defined the + undocumented and private YY_LOCATION_PRINT macros. */ +# define YY_LOCATION_PRINT(File, Loc) YYLOCATION_PRINT(File, &(Loc)) + +# else + +# define YYLOCATION_PRINT(File, Loc) ((void) 0) + /* Temporary convenience wrapper in case some people defined the + undocumented and private YY_LOCATION_PRINT macros. */ +# define YY_LOCATION_PRINT YYLOCATION_PRINT + +# endif +# endif /* !defined YYLOCATION_PRINT */ + + +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Kind, Value, Location, scanner, parser, ctx); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*-----------------------------------. +| Print this symbol's value on YYO. | +`-----------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner, struct parser *parser, struct asm_ctx *ctx) +{ + FILE *yyoutput = yyo; + YY_USE (yyoutput); + YY_USE (yylocationp); + YY_USE (scanner); + YY_USE (parser); + YY_USE (ctx); + if (!yyvaluep) + return; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + +/*---------------------------. +| Print this symbol on YYO. | +`---------------------------*/ + +static void +yy_symbol_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner, struct parser *parser, struct asm_ctx *ctx) +{ + YYFPRINTF (yyo, "%s %s (", + yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); + + YYLOCATION_PRINT (yyo, yylocationp); + YYFPRINTF (yyo, ": "); + yy_symbol_value_print (yyo, yykind, yyvaluep, yylocationp, scanner, parser, ctx); + YYFPRINTF (yyo, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, + int yyrule, void *scanner, struct parser *parser, struct asm_ctx *ctx) +{ + int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), + &yyvsp[(yyi + 1) - (yynrhs)], + &(yylsp[(yyi + 1) - (yynrhs)]), scanner, parser, ctx); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, yylsp, Rule, scanner, parser, ctx); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) ((void) 0) +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +/* Context of a parse error. */ +typedef struct +{ + yy_state_t *yyssp; + yysymbol_kind_t yytoken; + YYLTYPE *yylloc; +} yypcontext_t; + +/* Put in YYARG at most YYARGN of the expected tokens given the + current YYCTX, and return the number of tokens stored in YYARG. If + YYARG is null, return the number of expected tokens (guaranteed to + be less than YYNTOKENS). Return YYENOMEM on memory exhaustion. + Return 0 if there are more than YYARGN expected tokens, yet fill + YYARG up to YYARGN. */ +static int +yypcontext_expected_tokens (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + int yyn = yypact[+*yyctx->yyssp]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (!yyarg) + ++yycount; + else if (yycount == yyargn) + return 0; + else + yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx); + } + } + if (yyarg && yycount == 0 && 0 < yyargn) + yyarg[0] = YYSYMBOL_YYEMPTY; + return yycount; +} + + + + +#ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) +# else +/* Return the length of YYSTR. */ +static YYPTRDIFF_T +yystrlen (const char *yystr) +{ + YYPTRDIFF_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +#endif + +#ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +#endif + +#ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYPTRDIFF_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYPTRDIFF_T yyn = 0; + char const *yyp = yystr; + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + else + goto append; + + append: + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (yyres) + return yystpcpy (yyres, yystr) - yyres; + else + return yystrlen (yystr); +} +#endif + + +static int +yy_syntax_error_arguments (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yyctx->yytoken != YYSYMBOL_YYEMPTY) + { + int yyn; + if (yyarg) + yyarg[yycount] = yyctx->yytoken; + ++yycount; + yyn = yypcontext_expected_tokens (yyctx, + yyarg ? yyarg + 1 : yyarg, yyargn - 1); + if (yyn == YYENOMEM) + return YYENOMEM; + else + yycount += yyn; + } + return yycount; +} + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, + const yypcontext_t *yyctx) +{ + enum { YYARGS_MAX = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat: reported tokens (one for the "unexpected", + one per "expected"). */ + yysymbol_kind_t yyarg[YYARGS_MAX]; + /* Cumulated lengths of YYARG. */ + YYPTRDIFF_T yysize = 0; + + /* Actual size of YYARG. */ + int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX); + if (yycount == YYENOMEM) + return YYENOMEM; + + switch (yycount) + { +#define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: /* Avoid compiler warnings. */ + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +#undef YYCASE_ + } + + /* Compute error message size. Don't count the "%s"s, but reserve + room for the terminator. */ + yysize = yystrlen (yyformat) - 2 * yycount + 1; + { + int yyi; + for (yyi = 0; yyi < yycount; ++yyi) + { + YYPTRDIFF_T yysize1 + = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]); + if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) + yysize = yysize1; + else + return YYENOMEM; + } + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return -1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]); + yyformat += 2; + } + else + { + ++yyp; + ++yyformat; + } + } + return 0; +} + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, + yysymbol_kind_t yykind, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, void *scanner, struct parser *parser, struct asm_ctx *ctx) +{ + YY_USE (yyvaluep); + YY_USE (yylocationp); + YY_USE (scanner); + YY_USE (parser); + YY_USE (ctx); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (void *scanner, struct parser *parser, struct asm_ctx *ctx) +{ +/* Lookahead token kind. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + +/* Location data for the lookahead symbol. */ +static YYLTYPE yyloc_default +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + = { 1, 1, 1, 1 } +# endif +; +YYLTYPE yylloc = yyloc_default; + + /* Number of syntax errors so far. */ + int yynerrs = 0; + + yy_state_fast_t yystate = 0; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus = 0; + + /* Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* Their size. */ + YYPTRDIFF_T yystacksize = YYINITDEPTH; + + /* The state stack: array, bottom, top. */ + yy_state_t yyssa[YYINITDEPTH]; + yy_state_t *yyss = yyssa; + yy_state_t *yyssp = yyss; + + /* The semantic value stack: array, bottom, top. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp = yyvs; + + /* The location stack: array, bottom, top. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp = yyls; + + int yyn; + /* The return value of yyparse. */ + int yyresult; + /* Lookahead symbol kind. */ + yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[3]; + + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yychar = YYEMPTY; /* Cause a token to be read. */ + + yylsp[0] = yylloc; + goto yysetstate; + + +/*------------------------------------------------------------. +| yynewstate -- push a new state, which is found in yystate. | +`------------------------------------------------------------*/ +yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + +/*--------------------------------------------------------------------. +| yysetstate -- set current state (the top of the stack) to yystate. | +`--------------------------------------------------------------------*/ +yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); + YY_IGNORE_USELESS_CAST_BEGIN + *yyssp = YY_CAST (yy_state_t, yystate); + YY_IGNORE_USELESS_CAST_END + YY_STACK_PRINT (yyss, yyssp); + + if (yyss + yystacksize - 1 <= yyssp) +#if !defined yyoverflow && !defined YYSTACK_RELOCATE + YYNOMEM; +#else + { + /* Get the current used size of the three stacks, in elements. */ + YYPTRDIFF_T yysize = yyssp - yyss + 1; + +# if defined yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + yy_state_t *yyss1 = yyss; + YYSTYPE *yyvs1 = yyvs; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * YYSIZEOF (*yyssp), + &yyvs1, yysize * YYSIZEOF (*yyvsp), + &yyls1, yysize * YYSIZEOF (*yylsp), + &yystacksize); + yyss = yyss1; + yyvs = yyvs1; + yyls = yyls1; + } +# else /* defined YYSTACK_RELOCATE */ + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + YYNOMEM; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yy_state_t *yyss1 = yyss; + union yyalloc *yyptr = + YY_CAST (union yyalloc *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); + if (! yyptr) + YYNOMEM; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YY_IGNORE_USELESS_CAST_BEGIN + YYDPRINTF ((stderr, "Stack size increased to %ld\n", + YY_CAST (long, yystacksize))); + YY_IGNORE_USELESS_CAST_END + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } +#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ + + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token\n")); + yychar = yylex (&yylval, &yylloc, scanner, parser); + } + + if (yychar <= YYEOF) + { + yychar = YYEOF; + yytoken = YYSYMBOL_YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else if (yychar == YYerror) + { + /* The scanner already issued an error message, process directly + to error recovery. But do not keep the error token as + lookahead, it is too special and may lead us to an endless + loop in error recovery. */ + yychar = YYUNDEF; + yytoken = YYSYMBOL_YYerror; + yyerror_range[1] = yylloc; + goto yyerrlab1; + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + *++yylsp = yylloc; + + /* Discard the shifted token. */ + yychar = YYEMPTY; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + yyerror_range[1] = yyloc; + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 4: /* gpr: x0 */ +#line 157 "src/parser.y" + {(yyval.gpr) = X0_NUM;} +#line 2112 "gen/gen_parser.c" + break; + + case 5: /* gpr: x1 */ +#line 158 "src/parser.y" + {(yyval.gpr) = X1_NUM;} +#line 2118 "gen/gen_parser.c" + break; + + case 6: /* gpr: x2 */ +#line 159 "src/parser.y" + {(yyval.gpr) = X2_NUM;} +#line 2124 "gen/gen_parser.c" + break; + + case 7: /* gpr: x3 */ +#line 160 "src/parser.y" + {(yyval.gpr) = X3_NUM;} +#line 2130 "gen/gen_parser.c" + break; + + case 8: /* gpr: x4 */ +#line 161 "src/parser.y" + {(yyval.gpr) = X4_NUM;} +#line 2136 "gen/gen_parser.c" + break; + + case 9: /* gpr: x5 */ +#line 162 "src/parser.y" + {(yyval.gpr) = X5_NUM;} +#line 2142 "gen/gen_parser.c" + break; + + case 10: /* gpr: x6 */ +#line 163 "src/parser.y" + {(yyval.gpr) = X6_NUM;} +#line 2148 "gen/gen_parser.c" + break; + + case 11: /* gpr: x7 */ +#line 164 "src/parser.y" + {(yyval.gpr) = X7_NUM;} +#line 2154 "gen/gen_parser.c" + break; + + case 12: /* gpr: x8 */ +#line 165 "src/parser.y" + {(yyval.gpr) = X8_NUM;} +#line 2160 "gen/gen_parser.c" + break; + + case 13: /* gpr: x9 */ +#line 166 "src/parser.y" + {(yyval.gpr) = X9_NUM;} +#line 2166 "gen/gen_parser.c" + break; + + case 14: /* gpr: x10 */ +#line 167 "src/parser.y" + {(yyval.gpr) = X10_NUM;} +#line 2172 "gen/gen_parser.c" + break; + + case 15: /* gpr: x11 */ +#line 168 "src/parser.y" + {(yyval.gpr) = X11_NUM;} +#line 2178 "gen/gen_parser.c" + break; + + case 16: /* gpr: x12 */ +#line 169 "src/parser.y" + {(yyval.gpr) = X12_NUM;} +#line 2184 "gen/gen_parser.c" + break; + + case 17: /* gpr: x13 */ +#line 170 "src/parser.y" + {(yyval.gpr) = X13_NUM;} +#line 2190 "gen/gen_parser.c" + break; + + case 18: /* gpr: x14 */ +#line 171 "src/parser.y" + {(yyval.gpr) = X14_NUM;} +#line 2196 "gen/gen_parser.c" + break; + + case 19: /* gpr: x15 */ +#line 172 "src/parser.y" + {(yyval.gpr) = X15_NUM;} +#line 2202 "gen/gen_parser.c" + break; + + case 20: /* gpr: x16 */ +#line 173 "src/parser.y" + {(yyval.gpr) = X16_NUM;} +#line 2208 "gen/gen_parser.c" + break; + + case 21: /* gpr: x17 */ +#line 174 "src/parser.y" + {(yyval.gpr) = X17_NUM;} +#line 2214 "gen/gen_parser.c" + break; + + case 22: /* gpr: x18 */ +#line 175 "src/parser.y" + {(yyval.gpr) = X18_NUM;} +#line 2220 "gen/gen_parser.c" + break; + + case 23: /* gpr: x19 */ +#line 176 "src/parser.y" + {(yyval.gpr) = X19_NUM;} +#line 2226 "gen/gen_parser.c" + break; + + case 24: /* gpr: x20 */ +#line 177 "src/parser.y" + {(yyval.gpr) = X20_NUM;} +#line 2232 "gen/gen_parser.c" + break; + + case 25: /* gpr: x21 */ +#line 178 "src/parser.y" + {(yyval.gpr) = X21_NUM;} +#line 2238 "gen/gen_parser.c" + break; + + case 26: /* gpr: x22 */ +#line 179 "src/parser.y" + {(yyval.gpr) = X22_NUM;} +#line 2244 "gen/gen_parser.c" + break; + + case 27: /* gpr: x23 */ +#line 180 "src/parser.y" + {(yyval.gpr) = X23_NUM;} +#line 2250 "gen/gen_parser.c" + break; + + case 28: /* gpr: x24 */ +#line 181 "src/parser.y" + {(yyval.gpr) = X24_NUM;} +#line 2256 "gen/gen_parser.c" + break; + + case 29: /* gpr: x25 */ +#line 182 "src/parser.y" + {(yyval.gpr) = X25_NUM;} +#line 2262 "gen/gen_parser.c" + break; + + case 30: /* gpr: x26 */ +#line 183 "src/parser.y" + {(yyval.gpr) = X26_NUM;} +#line 2268 "gen/gen_parser.c" + break; + + case 31: /* gpr: x27 */ +#line 184 "src/parser.y" + {(yyval.gpr) = X27_NUM;} +#line 2274 "gen/gen_parser.c" + break; + + case 32: /* gpr: x28 */ +#line 185 "src/parser.y" + {(yyval.gpr) = X28_NUM;} +#line 2280 "gen/gen_parser.c" + break; + + case 33: /* gpr: x29 */ +#line 186 "src/parser.y" + {(yyval.gpr) = X29_NUM;} +#line 2286 "gen/gen_parser.c" + break; + + case 34: /* gpr: x30 */ +#line 187 "src/parser.y" + {(yyval.gpr) = X30_NUM;} +#line 2292 "gen/gen_parser.c" + break; + + case 35: /* gpr: x31 */ +#line 188 "src/parser.y" + {(yyval.gpr) = X31_NUM;} +#line 2298 "gen/gen_parser.c" + break; + + case 36: /* gpr: x32 */ +#line 189 "src/parser.y" + {(yyval.gpr) = X32_NUM;} +#line 2304 "gen/gen_parser.c" + break; + + case 37: /* gpr: x33 */ +#line 190 "src/parser.y" + {(yyval.gpr) = X33_NUM;} +#line 2310 "gen/gen_parser.c" + break; + + case 38: /* gpr: x34 */ +#line 191 "src/parser.y" + {(yyval.gpr) = X34_NUM;} +#line 2316 "gen/gen_parser.c" + break; + + case 39: /* gpr: x35 */ +#line 192 "src/parser.y" + {(yyval.gpr) = X35_NUM;} +#line 2322 "gen/gen_parser.c" + break; + + case 40: /* gpr: x36 */ +#line 193 "src/parser.y" + {(yyval.gpr) = X36_NUM;} +#line 2328 "gen/gen_parser.c" + break; + + case 41: /* gpr: x37 */ +#line 194 "src/parser.y" + {(yyval.gpr) = X37_NUM;} +#line 2334 "gen/gen_parser.c" + break; + + case 42: /* gpr: x38 */ +#line 195 "src/parser.y" + {(yyval.gpr) = X38_NUM;} +#line 2340 "gen/gen_parser.c" + break; + + case 43: /* gpr: x39 */ +#line 196 "src/parser.y" + {(yyval.gpr) = X39_NUM;} +#line 2346 "gen/gen_parser.c" + break; + + case 44: /* gpr: x40 */ +#line 197 "src/parser.y" + {(yyval.gpr) = X40_NUM;} +#line 2352 "gen/gen_parser.c" + break; + + case 45: /* gpr: x41 */ +#line 198 "src/parser.y" + {(yyval.gpr) = X41_NUM;} +#line 2358 "gen/gen_parser.c" + break; + + case 46: /* gpr: x42 */ +#line 199 "src/parser.y" + {(yyval.gpr) = X42_NUM;} +#line 2364 "gen/gen_parser.c" + break; + + case 47: /* gpr: x43 */ +#line 200 "src/parser.y" + {(yyval.gpr) = X43_NUM;} +#line 2370 "gen/gen_parser.c" + break; + + case 48: /* gpr: x44 */ +#line 201 "src/parser.y" + {(yyval.gpr) = X44_NUM;} +#line 2376 "gen/gen_parser.c" + break; + + case 49: /* gpr: x45 */ +#line 202 "src/parser.y" + {(yyval.gpr) = X45_NUM;} +#line 2382 "gen/gen_parser.c" + break; + + case 50: /* gpr: x46 */ +#line 203 "src/parser.y" + {(yyval.gpr) = X46_NUM;} +#line 2388 "gen/gen_parser.c" + break; + + case 51: /* gpr: x47 */ +#line 204 "src/parser.y" + {(yyval.gpr) = X47_NUM;} +#line 2394 "gen/gen_parser.c" + break; + + case 52: /* gpr: x48 */ +#line 205 "src/parser.y" + {(yyval.gpr) = X48_NUM;} +#line 2400 "gen/gen_parser.c" + break; + + case 53: /* gpr: x49 */ +#line 206 "src/parser.y" + {(yyval.gpr) = X49_NUM;} +#line 2406 "gen/gen_parser.c" + break; + + case 54: /* gpr: x50 */ +#line 207 "src/parser.y" + {(yyval.gpr) = X50_NUM;} +#line 2412 "gen/gen_parser.c" + break; + + case 55: /* gpr: x51 */ +#line 208 "src/parser.y" + {(yyval.gpr) = X51_NUM;} +#line 2418 "gen/gen_parser.c" + break; + + case 56: /* gpr: x52 */ +#line 209 "src/parser.y" + {(yyval.gpr) = X52_NUM;} +#line 2424 "gen/gen_parser.c" + break; + + case 57: /* gpr: x53 */ +#line 210 "src/parser.y" + {(yyval.gpr) = X53_NUM;} +#line 2430 "gen/gen_parser.c" + break; + + case 58: /* gpr: x54 */ +#line 211 "src/parser.y" + {(yyval.gpr) = X54_NUM;} +#line 2436 "gen/gen_parser.c" + break; + + case 59: /* gpr: x55 */ +#line 212 "src/parser.y" + {(yyval.gpr) = X55_NUM;} +#line 2442 "gen/gen_parser.c" + break; + + case 60: /* gpr: x56 */ +#line 213 "src/parser.y" + {(yyval.gpr) = X56_NUM;} +#line 2448 "gen/gen_parser.c" + break; + + case 61: /* gpr: x57 */ +#line 214 "src/parser.y" + {(yyval.gpr) = X57_NUM;} +#line 2454 "gen/gen_parser.c" + break; + + case 62: /* gpr: x58 */ +#line 215 "src/parser.y" + {(yyval.gpr) = X58_NUM;} +#line 2460 "gen/gen_parser.c" + break; + + case 63: /* gpr: x59 */ +#line 216 "src/parser.y" + {(yyval.gpr) = X59_NUM;} +#line 2466 "gen/gen_parser.c" + break; + + case 64: /* gpr: x60 */ +#line 217 "src/parser.y" + {(yyval.gpr) = X60_NUM;} +#line 2472 "gen/gen_parser.c" + break; + + case 65: /* gpr: x61 */ +#line 218 "src/parser.y" + {(yyval.gpr) = X61_NUM;} +#line 2478 "gen/gen_parser.c" + break; + + case 66: /* gpr: x62 */ +#line 219 "src/parser.y" + {(yyval.gpr) = X62_NUM;} +#line 2484 "gen/gen_parser.c" + break; + + case 67: /* gpr: x63 */ +#line 220 "src/parser.y" + {(yyval.gpr) = X63_NUM;} +#line 2490 "gen/gen_parser.c" + break; + + case 68: /* gpr: x64 */ +#line 221 "src/parser.y" + {(yyval.gpr) = X64_NUM;} +#line 2496 "gen/gen_parser.c" + break; + + case 69: /* gpr: x65 */ +#line 222 "src/parser.y" + {(yyval.gpr) = X65_NUM;} +#line 2502 "gen/gen_parser.c" + break; + + case 70: /* gpr: x66 */ +#line 223 "src/parser.y" + {(yyval.gpr) = X66_NUM;} +#line 2508 "gen/gen_parser.c" + break; + + case 71: /* gpr: x67 */ +#line 224 "src/parser.y" + {(yyval.gpr) = X67_NUM;} +#line 2514 "gen/gen_parser.c" + break; + + case 72: /* gpr: x68 */ +#line 225 "src/parser.y" + {(yyval.gpr) = X68_NUM;} +#line 2520 "gen/gen_parser.c" + break; + + case 73: /* gpr: x69 */ +#line 226 "src/parser.y" + {(yyval.gpr) = X69_NUM;} +#line 2526 "gen/gen_parser.c" + break; + + case 74: /* gpr: x70 */ +#line 227 "src/parser.y" + {(yyval.gpr) = X70_NUM;} +#line 2532 "gen/gen_parser.c" + break; + + case 75: /* gpr: x71 */ +#line 228 "src/parser.y" + {(yyval.gpr) = X71_NUM;} +#line 2538 "gen/gen_parser.c" + break; + + case 76: /* gpr: x72 */ +#line 229 "src/parser.y" + {(yyval.gpr) = X72_NUM;} +#line 2544 "gen/gen_parser.c" + break; + + case 77: /* gpr: x73 */ +#line 230 "src/parser.y" + {(yyval.gpr) = X73_NUM;} +#line 2550 "gen/gen_parser.c" + break; + + case 78: /* gpr: x74 */ +#line 231 "src/parser.y" + {(yyval.gpr) = X74_NUM;} +#line 2556 "gen/gen_parser.c" + break; + + case 79: /* gpr: x75 */ +#line 232 "src/parser.y" + {(yyval.gpr) = X75_NUM;} +#line 2562 "gen/gen_parser.c" + break; + + case 80: /* gpr: x76 */ +#line 233 "src/parser.y" + {(yyval.gpr) = X76_NUM;} +#line 2568 "gen/gen_parser.c" + break; + + case 81: /* gpr: x77 */ +#line 234 "src/parser.y" + {(yyval.gpr) = X77_NUM;} +#line 2574 "gen/gen_parser.c" + break; + + case 82: /* gpr: x78 */ +#line 235 "src/parser.y" + {(yyval.gpr) = X78_NUM;} +#line 2580 "gen/gen_parser.c" + break; + + case 83: /* gpr: x79 */ +#line 236 "src/parser.y" + {(yyval.gpr) = X79_NUM;} +#line 2586 "gen/gen_parser.c" + break; + + case 84: /* gpr: x80 */ +#line 237 "src/parser.y" + {(yyval.gpr) = X80_NUM;} +#line 2592 "gen/gen_parser.c" + break; + + case 85: /* i: addi gpr "," gpr "," imm */ +#line 241 "src/parser.y" + {emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-4].gpr), OP_IMM_ADDI, (yyvsp[-2].gpr), (yyvsp[0].tri));} +#line 2598 "gen/gen_parser.c" + break; + + case 86: /* i: slti gpr "," gpr "," imm */ +#line 244 "src/parser.y" + {emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-4].gpr), OP_IMM_SLTI, (yyvsp[-2].gpr), (yyvsp[0].tri));} +#line 2604 "gen/gen_parser.c" + break; + + case 87: /* i: sgei gpr "," gpr "," imm */ +#line 247 "src/parser.y" + {emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-4].gpr), OP_IMM_SGEI, (yyvsp[-2].gpr), (yyvsp[0].tri));} +#line 2610 "gen/gen_parser.c" + break; + + case 88: /* i: seqi gpr "," gpr "," imm */ +#line 250 "src/parser.y" + {emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-4].gpr), OP_IMM_SEQI, (yyvsp[-2].gpr), (yyvsp[0].tri));} +#line 2616 "gen/gen_parser.c" + break; + + case 89: /* i: snei gpr "," gpr "," imm */ +#line 253 "src/parser.y" + {emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-4].gpr), OP_IMM_SNEI, (yyvsp[-2].gpr), (yyvsp[0].tri));} +#line 2622 "gen/gen_parser.c" + break; + + case 90: /* i: slli gpr "," gpr "," imm */ +#line 256 "src/parser.y" + {check_shift((yyvsp[0].tri)); emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-4].gpr), OP_IMM_SLLI, (yyvsp[-2].gpr), (yyvsp[0].tri));} +#line 2628 "gen/gen_parser.c" + break; + + case 91: /* i: srli gpr "," gpr "," imm */ +#line 259 "src/parser.y" + {check_shift((yyvsp[0].tri)); emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-4].gpr), OP_IMM_SRLI, (yyvsp[-2].gpr), (yyvsp[0].tri));} +#line 2634 "gen/gen_parser.c" + break; + + case 92: /* i: add gpr "," gpr "," gpr */ +#line 262 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_ADD, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2640 "gen/gen_parser.c" + break; + + case 93: /* i: sub gpr "," gpr "," gpr */ +#line 265 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_SUB, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2646 "gen/gen_parser.c" + break; + + case 94: /* i: slt gpr "," gpr "," gpr */ +#line 268 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_SLT, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2652 "gen/gen_parser.c" + break; + + case 95: /* i: sge gpr "," gpr "," gpr */ +#line 271 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_SGE, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2658 "gen/gen_parser.c" + break; + + case 96: /* i: seq gpr "," gpr "," gpr */ +#line 274 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_SEQ, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2664 "gen/gen_parser.c" + break; + + case 97: /* i: sne gpr "," gpr "," gpr */ +#line 277 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_SNE, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2670 "gen/gen_parser.c" + break; + + case 98: /* i: sll gpr "," gpr "," gpr */ +#line 280 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_SLL, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2676 "gen/gen_parser.c" + break; + + case 99: /* i: srl gpr "," gpr "," gpr */ +#line 283 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_SRL, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2682 "gen/gen_parser.c" + break; + + case 100: /* i: lui gpr "," imm */ +#line 286 "src/parser.y" + {emit_u(ctx, OPCODE_LUI, (yyvsp[-2].gpr), (yyvsp[0].tri));} +#line 2688 "gen/gen_parser.c" + break; + + case 101: /* i: auipc gpr "," imm */ +#line 289 "src/parser.y" + {emit_u(ctx, OPCODE_AUIPC, (yyvsp[-2].gpr), (yyvsp[0].tri));} +#line 2694 "gen/gen_parser.c" + break; + + case 102: /* i: jal gpr "," addr */ +#line 292 "src/parser.y" + {emit_u(ctx, OPCODE_JAL, (yyvsp[-2].gpr), 0); + emit_reloc(ctx, RELOC_J, (yyvsp[0].str));} +#line 2701 "gen/gen_parser.c" + break; + + case 103: /* i: jalr gpr "," gpr "," imm */ +#line 296 "src/parser.y" + {emit_i(ctx, OPCODE_JALR, (yyvsp[-4].gpr), 0, (yyvsp[-2].gpr), (yyvsp[0].tri));} +#line 2707 "gen/gen_parser.c" + break; + + case 104: /* i: beq gpr "," gpr "," addr */ +#line 299 "src/parser.y" + {emit_s(ctx, OPCODE_BRANCH, BRANCH_BEQ, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0); + emit_reloc(ctx, RELOC_B, (yyvsp[0].str));} +#line 2714 "gen/gen_parser.c" + break; + + case 105: /* i: bne gpr "," gpr "," addr */ +#line 303 "src/parser.y" + {emit_s(ctx, OPCODE_BRANCH, BRANCH_BNE, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0); + emit_reloc(ctx, RELOC_B, (yyvsp[0].str));} +#line 2721 "gen/gen_parser.c" + break; + + case 106: /* i: blt gpr "," gpr "," addr */ +#line 307 "src/parser.y" + {emit_s(ctx, OPCODE_BRANCH, BRANCH_BLT, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0); + emit_reloc(ctx, RELOC_B, (yyvsp[0].str));} +#line 2728 "gen/gen_parser.c" + break; + + case 107: /* i: bge gpr "," gpr "," addr */ +#line 311 "src/parser.y" + {emit_s(ctx, OPCODE_BRANCH, BRANCH_BGE, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0); + emit_reloc(ctx, RELOC_B, (yyvsp[0].str));} +#line 2735 "gen/gen_parser.c" + break; + + case 108: /* i: ld width "," gpr "," imm "(" gpr ")" */ +#line 315 "src/parser.y" + {emit_i(ctx, OPCODE_LOAD, check_width((yyvsp[-7].str)), (yyvsp[-5].gpr), (yyvsp[-1].gpr), (yyvsp[-3].tri));} +#line 2741 "gen/gen_parser.c" + break; + + case 109: /* i: st width "," gpr "," imm "(" gpr ")" */ +#line 318 "src/parser.y" + {emit_s(ctx, OPCODE_STORE, check_width((yyvsp[-7].str)), (yyvsp[-5].gpr), (yyvsp[-1].gpr), (yyvsp[-3].tri));} +#line 2747 "gen/gen_parser.c" + break; + + case 110: /* i: ecall */ +#line 321 "src/parser.y" + {emit_i(ctx, OPCODE_SYSTEM, X0_NUM, SYSTEM_ECALL, X0_NUM, 0);} +#line 2753 "gen/gen_parser.c" + break; + + case 111: /* i: ebreak */ +#line 324 "src/parser.y" + {emit_i(ctx, OPCODE_SYSTEM, X0_NUM, SYSTEM_EBREAK, X0_NUM, 0);} +#line 2759 "gen/gen_parser.c" + break; + + case 112: /* i: pcall */ +#line 327 "src/parser.y" + {emit_i(ctx, OPCODE_SYSTEM, X0_NUM, SYSTEM_PCALL, X0_NUM, 0);} +#line 2765 "gen/gen_parser.c" + break; + + case 113: /* i: fence */ +#line 330 "src/parser.y" + {emit_i(ctx, OPCODE_MEM, X0_NUM, MEM_FENCE, X0_NUM, 0); /* still todo */} +#line 2771 "gen/gen_parser.c" + break; + + case 114: /* i: unop gpr "," gpr "," str */ +#line 333 "src/parser.y" + {emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-4].gpr), OP_IMM_UNOP, (yyvsp[-2].gpr), check_nop((yyvsp[0].str)));} +#line 2777 "gen/gen_parser.c" + break; + + case 115: /* i: diop gpr "," gpr "," gpr "," str */ +#line 336 "src/parser.y" + {emit_d(ctx, OPCODE_DIOP, (yyvsp[-6].gpr), (yyvsp[-4].gpr), (yyvsp[-2].gpr), check_nop3((yyvsp[0].str)));} +#line 2783 "gen/gen_parser.c" + break; + + case 116: /* i: nop */ +#line 340 "src/parser.y" + {emit_i(ctx, OPCODE_OP_IMM, X0_NUM, OP_IMM_ADDI, X0_NUM, 0);} +#line 2789 "gen/gen_parser.c" + break; + + case 117: /* i: la gpr "," addr */ +#line 343 "src/parser.y" + {emit_u(ctx, OPCODE_LUI, (yyvsp[-2].gpr), 0); + /* important that the reloc is in the middle here */ + emit_reloc(ctx, RELOC_LA, (yyvsp[0].str)); + emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-2].gpr), OP_IMM_ADDI, (yyvsp[-2].gpr), 0);} +#line 2798 "gen/gen_parser.c" + break; + + case 118: /* i: li gpr "," imm */ +#line 349 "src/parser.y" + {emit_u(ctx, OPCODE_LUI, (yyvsp[-2].gpr), 0); + emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-2].gpr), OP_IMM_ADDI, (yyvsp[-2].gpr), 0);} +#line 2805 "gen/gen_parser.c" + break; + + case 119: /* m: mul gpr "," gpr "," gpr */ +#line 356 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_MUL, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2811 "gen/gen_parser.c" + break; + + case 120: /* m: diV gpr "," gpr "," gpr */ +#line 359 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_DIV, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2817 "gen/gen_parser.c" + break; + + case 121: /* m: rem gpr "," gpr "," gpr */ +#line 362 "src/parser.y" + {emit_r(ctx, OPCODE_OP, (yyvsp[-4].gpr), OP_DIV, (yyvsp[-2].gpr), (yyvsp[0].gpr), 0);} +#line 2823 "gen/gen_parser.c" + break; + + case 122: /* a: stt */ +#line 366 "src/parser.y" + {emit_i(ctx, OPCODE_MEM, X0_NUM, MEM_STT, X0_NUM, 0);} +#line 2829 "gen/gen_parser.c" + break; + + case 123: /* a: cst width "," gpr "," imm "(" gpr ")" */ +#line 369 "src/parser.y" + {emit_s(ctx, OPCODE_STORE, STORE_CST | check_width((yyvsp[-7].str)), (yyvsp[-5].gpr), (yyvsp[-1].gpr), (yyvsp[-3].tri));} +#line 2835 "gen/gen_parser.c" + break; + + case 124: /* a: ent gpr */ +#line 372 "src/parser.y" + {emit_i(ctx, OPCODE_MEM, (yyvsp[0].gpr), MEM_ENT, X0_NUM, 0);} +#line 2841 "gen/gen_parser.c" + break; + + case 125: /* a: cat */ +#line 375 "src/parser.y" + {emit_i(ctx, OPCODE_MEM, X0_NUM, MEM_CAT, X0_NUM, 0);} +#line 2847 "gen/gen_parser.c" + break; + + case 126: /* Zcsr: csrrw csr "," gpr "," gpr */ +#line 379 "src/parser.y" + {emit_i(ctx, OPCODE_SYSTEM, (yyvsp[-2].gpr), SYSTEM_CSRRW, (yyvsp[0].gpr), check_csr((yyvsp[-4].str)));} +#line 2853 "gen/gen_parser.c" + break; + + case 127: /* Zcsr: csrrs csr "," gpr "," gpr */ +#line 382 "src/parser.y" + {emit_i(ctx, OPCODE_SYSTEM, (yyvsp[-2].gpr), SYSTEM_CSRRS, (yyvsp[0].gpr), check_csr((yyvsp[-4].str)));} +#line 2859 "gen/gen_parser.c" + break; + + case 128: /* Zcsr: csrrc csr "," gpr "," gpr */ +#line 385 "src/parser.y" + {emit_i(ctx, OPCODE_SYSTEM, (yyvsp[-2].gpr), SYSTEM_CSRRC, (yyvsp[0].gpr), check_csr((yyvsp[-4].str)));} +#line 2865 "gen/gen_parser.c" + break; + + case 135: /* directive: include str */ +#line 398 "src/parser.y" + {process_file(ctx, (yyvsp[0].str));} +#line 2871 "gen/gen_parser.c" + break; + + case 136: /* top: label */ +#line 401 "src/parser.y" + {emit_label(ctx, (yyvsp[0].str));} +#line 2877 "gen/gen_parser.c" + break; + + +#line 2881 "gen/gen_parser.c" + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + { + const int yylhs = yyr1[yyn] - YYNTOKENS; + const int yyi = yypgoto[yylhs] + *yyssp; + yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp + ? yytable[yyi] + : yydefgoto[yylhs]); + } + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + { + yypcontext_t yyctx + = {yyssp, yytoken, &yylloc}; + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == -1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = YY_CAST (char *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); + if (yymsg) + { + yysyntax_error_status + = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + yymsgp = yymsg; + } + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = YYENOMEM; + } + } + yyerror (&yylloc, scanner, parser, ctx, yymsgp); + if (yysyntax_error_status == YYENOMEM) + YYNOMEM; + } + } + + yyerror_range[1] = yylloc; + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, scanner, parser, ctx); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and the + label yyerrorlab therefore never appears in user code. */ + if (0) + YYERROR; + ++yynerrs; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + /* Pop stack until we find a state that shifts the error token. */ + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYSYMBOL_YYerror; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[1] = *yylsp; + yydestruct ("Error: popping", + YY_ACCESSING_SYMBOL (yystate), yyvsp, yylsp, scanner, parser, ctx); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + yyerror_range[2] = yylloc; + ++yylsp; + YYLLOC_DEFAULT (*yylsp, yyerror_range, 2); + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturnlab; + + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturnlab; + + +/*-----------------------------------------------------------. +| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | +`-----------------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, scanner, parser, ctx, YY_("memory exhausted")); + yyresult = 2; + goto yyreturnlab; + + +/*----------------------------------------------------------. +| yyreturnlab -- parsing is finished, clean up and return. | +`----------------------------------------------------------*/ +yyreturnlab: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, scanner, parser, ctx); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yylsp, scanner, parser, ctx); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + return yyresult; +} + +#line 413 "src/parser.y" + + +static const char *find_lineno(const char *buf, size_t no) +{ + if (no == 0 || no == 1) + return buf; + + char c; + while ((c = *buf)) { + buf++; + + if (c == '\n') + no--; + + if (no == 1) + break; + } + + return buf; +} + +static void _issue(struct src_issue issue, const char *fmt, va_list args) +{ + /* get start and end of current line in buffer */ + const char *line_start = find_lineno(issue.fctx.fbuf, + issue.loc.first_line); + const char *line_end = strchr(line_start, '\n'); + if (!line_end) + line_end = strchr(line_start, 0); + + const int line_len = line_end - line_start; + + fprintf(stderr, "%s:%i:%i: ", + issue.fctx.fname, + issue.loc.first_line, + issue.loc.first_col); + + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + + int lineno_len = snprintf(NULL, 0, "%i", issue.loc.first_line); + fputc(' ', stderr); + fprintf(stderr, "%i | ", issue.loc.first_line); + + fprintf(stderr, "%.*s\n", line_len, line_start); + + for (int i = 0; i < lineno_len + 2; ++i) + fputc(' ', stderr); + + fprintf(stderr, "| "); + + for (int i = 0; i < issue.loc.first_col - 1; ++i) + fputc(line_start[i] == '\t' ? '\t' : ' ', stderr); + + for (int i = issue.loc.first_col; i < issue.loc.last_col; ++i) { + if (i == issue.loc.first_col) + fputc('^', stderr); + else + fputc('~', stderr); + } + + fputc('\n', stderr); +} + +void src_issue(struct src_issue issue, const char *err_msg, ...) +{ + va_list args; + va_start(args, err_msg); + _issue(issue, err_msg, args); + va_end(args); +} +#include "gen_lexer.inc" + +static struct src_loc to_src_loc(YYLTYPE *yylloc) +{ + struct src_loc loc; + loc.first_line = yylloc->first_line; + loc.last_line = yylloc->last_line; + loc.first_col = yylloc->first_column; + loc.last_col = yylloc->last_column; + return loc; +} + +static void yyerror(YYLTYPE *yylloc, void *lexer, + struct parser *parser, struct asm_ctx *ctx, const char *msg) +{ + (void)lexer; + (void)ctx; + + struct src_issue issue; + issue.loc = to_src_loc(yylloc); + issue.fctx.fbuf = parser->buf; + issue.fctx.fname = parser->fname; + src_issue(issue, msg); +} + +struct parser *create_parser() +{ + return calloc(1, sizeof(struct parser)); +} + +void destroy_parser(struct parser *p) +{ + yylex_destroy(p->lexer); + free(p); +} + +void parse(struct parser *p, struct asm_ctx *ctx, const char *fname, const char *buf) +{ + p->fname = fname; + p->buf = buf; + + p->comment_nesting = 0; + + p->failed = false; + + yylex_init(&p->lexer); + yy_scan_string(buf, p->lexer); + yyparse(p->lexer, p, ctx); +} diff --git a/tasm/include/tasm/assembler.h b/tasm/include/tasm/assembler.h new file mode 100644 index 0000000..d687dbb --- /dev/null +++ b/tasm/include/tasm/assembler.h @@ -0,0 +1,51 @@ +#ifndef TASM_ASSEMBLER_H +#define TASM_ASSEMBLER_H + +#include <tasm/regs.h> +#include <tri.h> + +struct asm_ctx; + +enum asm_reloc { + /* absolute LUI + ADDI */ + RELOC_LA, + /* relative AUIPC + ADDI (currently unimplemented) */ + RELOC_LR, + RELOC_B, + RELOC_J, +}; + +tri_t parse_imm(const char *imm); + +void emit_r(struct asm_ctx *ctx, tri_t opcode, + enum gpr_num rd, tri_t fn0, enum gpr_num rs1, + enum gpr_num rs2, tri_t fn5); + +void emit_i(struct asm_ctx *ctx, tri_t opcode, + enum gpr_num rd, tri_t fn0, enum gpr_num rs1, tri_t imm9); + +void emit_s(struct asm_ctx *ctx, tri_t opcode, + tri_t fn0, enum gpr_num rs1, enum gpr_num rs2, tri_t imm9); + +void emit_u(struct asm_ctx *ctx, tri_t opcode, + enum gpr_num rd, tri_t imm18); + +void emit_d(struct asm_ctx *ctx, tri_t opcode, + enum gpr_num rd, enum gpr_num rs1, enum gpr_num rs2, tri_t imm10); + +/* emits a relocation for the previous instruction, very important to keep in + * mind! */ +void emit_reloc(struct asm_ctx *ctx, enum asm_reloc reloc, const char *name); +void emit_label(struct asm_ctx *ctx, const char *name); + +tri_t check_nop(const char *nop); +tri_t check_nop3(const char *nop3); +void check_shift(tri_t shmt); + +tri_t check_csr(const char *csr); +tri_t check_width(const char *width); + +int process_file(struct asm_ctx *ctx, const char *file); +int assemble(const char *outfile, const char *infile); + +#endif diff --git a/tasm/include/tasm/bits.h b/tasm/include/tasm/bits.h new file mode 100644 index 0000000..2070425 --- /dev/null +++ b/tasm/include/tasm/bits.h @@ -0,0 +1,81 @@ +#ifndef TASM_BITS_H +#define TASM_BITS_H + +#include <tasm/regs.h> +#include <tri.h> + +#define OPCODE_OP_IMM 0b0000000000 +#define OP_IMM_ADDI 0b0000000000 +#define OP_IMM_SUBI 0b0000000001 +#define OP_IMM_SLTI 0b0000000010 +#define OP_IMM_SGEI 0b0000000100 +#define OP_IMM_SEQI 0b0000000101 +#define OP_IMM_SNEI 0b0000000110 +#define OP_IMM_SLLI 0b0000001000 +#define OP_IMM_SRLI 0b0000001001 +#define OP_IMM_UNOP 0b0000001010 + +#define OPCODE_OP 0b0000000001 +#define OP_ADD 0b0000000000 +#define OP_SUB 0b0000000001 +#define OP_SLT 0b0000000010 +#define OP_SGE 0b0000000100 +#define OP_SEQ 0b0000000101 +#define OP_SNE 0b0000000110 +#define OP_SLL 0b0000001000 +#define OP_SRL 0b0000001001 +#define OP_MUL 0b0000001010 +#define OP_DIV 0b0000010000 +#define OP_REM 0b0000010001 + +#define OPCODE_LUI 0b0000000010 +#define OPCODE_AUIPC 0b0000000100 +#define OPCODE_JAL 0b0000000101 +#define OPCODE_JALR 0b0000000110 + +#define OPCODE_BRANCH 0b0000001000 +#define BRANCH_BEQ 0b0000000000 +#define BRANCH_BNE 0b0000000001 +#define BRANCH_BLT 0b0000000010 +#define BRANCH_BGE 0b0000000100 + +#define OPCODE_LOAD 0b0000001001 +#define OPCODE_STORE 0b0000001010 +#define STORE_CST 0b0000000001 + +#define OPCODE_SYSTEM 0b0000010000 +#define SYSTEM_ECALL 0b0000000000 +#define SYSTEM_EBREAK 0b0000000001 +#define SYSTEM_PCALL 0b0000000010 +#define SYSTEM_CSRRW 0b0000000100 +#define SYSTEM_CSRRS 0b0000000101 +#define SYSTEM_CSRRC 0b0000000110 + +#define OPCODE_MEM 0b0000010001 +#define MEM_FENCE 0b0000000000 +#define MEM_STT 0b0000000001 +#define MEM_ENT 0b0000000010 +#define MEM_CAT 0b0000000100 + +#define OPCODE_DIOP 0b0000010010 + +#define WIDTH_W 0b0100000000 +#define WIDTH_T 0b0000000000 + +#define nonnull __attribute__((nonnull)) + +tri_t parse_opcode(tri_t i); + +tri_t build_r(tri_t opcode, tri_t rd, tri_t fn0, tri_t rs1, tri_t rs2, tri_t fn5); +void nonnull parse_r(tri_t i, tri_t *rd, tri_t *rs1, tri_t *rs2, tri_t *fn0, tri_t *fn5); + +tri_t build_i(tri_t opcode, tri_t rd, tri_t fn0, tri_t rs1, tri_t imm9); +void nonnull parse_i(tri_t i, tri_t *rd, tri_t *fn0, tri_t *rs1, tri_t *imm9); + +tri_t build_s(tri_t opcode, tri_t imm4, tri_t fn0, tri_t rs1, tri_t rs2, tri_t imm5); +void nonnull parse_s(tri_t i, tri_t *imm4, tri_t *fn0, tri_t *rs1, tri_t *rs2, tri_t *imm5); + +tri_t build_u(tri_t opcode, tri_t rd, tri_t imm18); +void nonnull parse_u(tri_t i, tri_t *rd, tri_t *imm18); + +#endif diff --git a/tasm/include/tasm/parser.h b/tasm/include/tasm/parser.h new file mode 100644 index 0000000..20da00c --- /dev/null +++ b/tasm/include/tasm/parser.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef PARSER_H +#define PARSER_H + +/** + * @file parser.h + * + * Glue file to get lexer and parser to play nice. + */ + +#include <stddef.h> +#include <stdbool.h> + +/** Stuff the parser needs to do its job. */ +struct parser { + /** Whether parsing failed or succeeded. */ + bool failed; + /** Lexer. Parser owns the lexer and is responsible for initializing + * and destroyint the lexer. + */ + void *lexer; + + /** File content in memory. */ + const char *buf; + /** Filename. */ + const char *fname; + /** How deeply we've nested comments. */ + size_t comment_nesting; +}; + +/** + * Create new parser. + * + * @return Created parser. + */ +struct parser *create_parser(); + +/** + * Destroy parser. + * + * @param p Parser to destroy. + */ +void destroy_parser(struct parser *p); + +/** + * Run parser on buffer \p buf with name \p fname. + * + * @param p Parser to run. + * @param fname Name of file \p buf was read from. + * @param buf Contents of \p fname. + */ +void parse(struct parser *p, struct asm_ctx *ctx, const char *fname, const char *buf); + +#endif /* PARSER_H */ diff --git a/tasm/include/tasm/regs.h b/tasm/include/tasm/regs.h new file mode 100644 index 0000000..3018ea4 --- /dev/null +++ b/tasm/include/tasm/regs.h @@ -0,0 +1,357 @@ +#ifndef TASM_REGS_H +#define TASM_REGS_H + +#include <stdlib.h> +#include <stdio.h> + +enum gpr_num { + X0_NUM, + X1_NUM, + X2_NUM, + X3_NUM, + X4_NUM, + X5_NUM, + X6_NUM, + X7_NUM, + X8_NUM, + X9_NUM, + X10_NUM, + X11_NUM, + X12_NUM, + X13_NUM, + X14_NUM, + X15_NUM, + X16_NUM, + X17_NUM, + X18_NUM, + X19_NUM, + X20_NUM, + X21_NUM, + X22_NUM, + X23_NUM, + X24_NUM, + X25_NUM, + X26_NUM, + X27_NUM, + X28_NUM, + X29_NUM, + X30_NUM, + X31_NUM, + X32_NUM, + X33_NUM, + X34_NUM, + X35_NUM, + X36_NUM, + X37_NUM, + X38_NUM, + X39_NUM, + X40_NUM, + X41_NUM, + X42_NUM, + X43_NUM, + X44_NUM, + X45_NUM, + X46_NUM, + X47_NUM, + X48_NUM, + X49_NUM, + X50_NUM, + X51_NUM, + X52_NUM, + X53_NUM, + X54_NUM, + X55_NUM, + X56_NUM, + X57_NUM, + X58_NUM, + X59_NUM, + X60_NUM, + X61_NUM, + X62_NUM, + X63_NUM, + X64_NUM, + X65_NUM, + X66_NUM, + X67_NUM, + X68_NUM, + X69_NUM, + X70_NUM, + X71_NUM, + X72_NUM, + X73_NUM, + X74_NUM, + X75_NUM, + X76_NUM, + X77_NUM, + X78_NUM, + X79_NUM, + X80_NUM, +}; + +/* generated with a script */ +enum gpr_tri { + X41 = 170, + X42 = 168, + X43 = 169, + X44 = 162, + X45 = 160, + X46 = 161, + X47 = 166, + X48 = 164, + X49 = 165, + X50 = 138, + X51 = 136, + X52 = 137, + X53 = 130, + X54 = 128, + X55 = 129, + X56 = 134, + X57 = 132, + X58 = 133, + X59 = 154, + X60 = 152, + X61 = 153, + X62 = 146, + X63 = 144, + X64 = 145, + X65 = 150, + X66 = 148, + X67 = 149, + X68 = 42, + X69 = 40, + X70 = 41, + X71 = 34, + X72 = 32, + X73 = 33, + X74 = 38, + X75 = 36, + X76 = 37, + X77 = 10, + X78 = 8, + X79 = 9, + X80 = 2, + X0 = 0, + X1 = 1, + X2 = 6, + X3 = 4, + X4 = 5, + X5 = 26, + X6 = 24, + X7 = 25, + X8 = 18, + X9 = 16, + X10 = 17, + X11 = 22, + X12 = 20, + X13 = 21, + X14 = 106, + X15 = 104, + X16 = 105, + X17 = 98, + X18 = 96, + X19 = 97, + X20 = 102, + X21 = 100, + X22 = 101, + X23 = 74, + X24 = 72, + X25 = 73, + X26 = 66, + X27 = 64, + X28 = 65, + X29 = 70, + X30 = 68, + X31 = 69, + X32 = 90, + X33 = 88, + X34 = 89, + X35 = 82, + X36 = 80, + X37 = 81, + X38 = 86, + X39 = 84, + X40 = 85, +}; + +static inline enum gpr_tri gpr_tri(enum gpr_num g) +{ + switch (g) { + case X0_NUM: return X0; + case X1_NUM: return X1; + case X2_NUM: return X2; + case X3_NUM: return X3; + case X4_NUM: return X4; + case X5_NUM: return X5; + case X6_NUM: return X6; + case X7_NUM: return X7; + case X8_NUM: return X8; + case X9_NUM: return X9; + case X10_NUM: return X10; + case X11_NUM: return X11; + case X12_NUM: return X12; + case X13_NUM: return X13; + case X14_NUM: return X14; + case X15_NUM: return X15; + case X16_NUM: return X16; + case X17_NUM: return X17; + case X18_NUM: return X18; + case X19_NUM: return X19; + case X20_NUM: return X20; + case X21_NUM: return X21; + case X22_NUM: return X22; + case X23_NUM: return X23; + case X24_NUM: return X24; + case X25_NUM: return X25; + case X26_NUM: return X26; + case X27_NUM: return X27; + case X28_NUM: return X28; + case X29_NUM: return X29; + case X30_NUM: return X30; + case X31_NUM: return X31; + case X32_NUM: return X32; + case X33_NUM: return X33; + case X34_NUM: return X34; + case X35_NUM: return X35; + case X36_NUM: return X36; + case X37_NUM: return X37; + case X38_NUM: return X38; + case X39_NUM: return X39; + case X40_NUM: return X40; + case X41_NUM: return X41; + case X42_NUM: return X42; + case X43_NUM: return X43; + case X44_NUM: return X44; + case X45_NUM: return X45; + case X46_NUM: return X46; + case X47_NUM: return X47; + case X48_NUM: return X48; + case X49_NUM: return X49; + case X50_NUM: return X50; + case X51_NUM: return X51; + case X52_NUM: return X52; + case X53_NUM: return X53; + case X54_NUM: return X54; + case X55_NUM: return X55; + case X56_NUM: return X56; + case X57_NUM: return X57; + case X58_NUM: return X58; + case X59_NUM: return X59; + case X60_NUM: return X60; + case X61_NUM: return X61; + case X62_NUM: return X62; + case X63_NUM: return X63; + case X64_NUM: return X64; + case X65_NUM: return X65; + case X66_NUM: return X66; + case X67_NUM: return X67; + case X68_NUM: return X68; + case X69_NUM: return X69; + case X70_NUM: return X70; + case X71_NUM: return X71; + case X72_NUM: return X72; + case X73_NUM: return X73; + case X74_NUM: return X74; + case X75_NUM: return X75; + case X76_NUM: return X76; + case X77_NUM: return X77; + case X78_NUM: return X78; + case X79_NUM: return X79; + case X80_NUM: return X80; + } + + fprintf(stderr, "illegal gpr num: %d\n", g); + abort(); + return -1; +} + +static inline enum gpr_num gpr_num(enum gpr_tri t) +{ + switch (t) { + case X0: return X0_NUM; + case X1: return X1_NUM; + case X2: return X2_NUM; + case X3: return X3_NUM; + case X4: return X4_NUM; + case X5: return X5_NUM; + case X6: return X6_NUM; + case X7: return X7_NUM; + case X8: return X8_NUM; + case X9: return X9_NUM; + case X10: return X10_NUM; + case X11: return X11_NUM; + case X12: return X12_NUM; + case X13: return X13_NUM; + case X14: return X14_NUM; + case X15: return X15_NUM; + case X16: return X16_NUM; + case X17: return X17_NUM; + case X18: return X18_NUM; + case X19: return X19_NUM; + case X20: return X20_NUM; + case X21: return X21_NUM; + case X22: return X22_NUM; + case X23: return X23_NUM; + case X24: return X24_NUM; + case X25: return X25_NUM; + case X26: return X26_NUM; + case X27: return X27_NUM; + case X28: return X28_NUM; + case X29: return X29_NUM; + case X30: return X30_NUM; + case X31: return X31_NUM; + case X32: return X32_NUM; + case X33: return X33_NUM; + case X34: return X34_NUM; + case X35: return X35_NUM; + case X36: return X36_NUM; + case X37: return X37_NUM; + case X38: return X38_NUM; + case X39: return X39_NUM; + case X40: return X40_NUM; + case X41: return X41_NUM; + case X42: return X42_NUM; + case X43: return X43_NUM; + case X44: return X44_NUM; + case X45: return X45_NUM; + case X46: return X46_NUM; + case X47: return X47_NUM; + case X48: return X48_NUM; + case X49: return X49_NUM; + case X50: return X50_NUM; + case X51: return X51_NUM; + case X52: return X52_NUM; + case X53: return X53_NUM; + case X54: return X54_NUM; + case X55: return X55_NUM; + case X56: return X56_NUM; + case X57: return X57_NUM; + case X58: return X58_NUM; + case X59: return X59_NUM; + case X60: return X60_NUM; + case X61: return X61_NUM; + case X62: return X62_NUM; + case X63: return X63_NUM; + case X64: return X64_NUM; + case X65: return X65_NUM; + case X66: return X66_NUM; + case X67: return X67_NUM; + case X68: return X68_NUM; + case X69: return X69_NUM; + case X70: return X70_NUM; + case X71: return X71_NUM; + case X72: return X72_NUM; + case X73: return X73_NUM; + case X74: return X74_NUM; + case X75: return X75_NUM; + case X76: return X76_NUM; + case X77: return X77_NUM; + case X78: return X78_NUM; + case X79: return X79_NUM; + case X80: return X80_NUM; + } + + fprintf(stderr, "illegal gpr: %d\n", t); + abort(); + return -1; +} +#endif diff --git a/tasm/scripts/gen-deps b/tasm/scripts/gen-deps new file mode 100755 index 0000000..f45707c --- /dev/null +++ b/tasm/scripts/gen-deps @@ -0,0 +1,37 @@ +#!/bin/sh + +PREFIX= +COMPILE=COMPILE +LINT=LINT +BUILD=build/ + +while getopts "p:c:b:l:" opt; do + case "$opt" in + p) PREFIX="$OPTARG"_;; + c) COMPILE="$OPTARG";; + l) LINT="$OPTARG";; + b) BUILD=build/"$OPTARG";; + *) echo "unrecognised option -$OPTARG" >&2; exit 1;; + esac +done + +shift $((OPTIND - 1)) + +# create all subdirectories +mkdir -p $(echo "${@}" | tr ' ' '\n' | sed "s|[^/]*$||;s|^|${BUILD}/|" | uniq) + +for s in ${@} +do + obj="${BUILD}/${s%.*}.o" + lint="${obj}.l" + dep="${obj}.d" + + echo "${PREFIX}OBJS += ${obj}" >> deps.mk + echo "${PREFIX}LINTS += ${lint}" >> deps.mk + echo "${dep}:" >> deps.mk + echo "-include ${dep}" >> deps.mk + echo "${obj}: ${s}" >> deps.mk + echo " \$(${COMPILE}) -c ${s} -o ${obj}" >> deps.mk + echo "${lint}: ${s}" >> deps.mk + echo " \$(${LINT}) -c ${s} -o /dev/null" >> deps.mk +done diff --git a/tasm/scripts/license b/tasm/scripts/license new file mode 100755 index 0000000..53bd5da --- /dev/null +++ b/tasm/scripts/license @@ -0,0 +1,16 @@ +#!/bin/sh + +SPDX="/* SPDX-License-Identifier: copyleft-next-0.3.1 */" + +for f in "$@" +do + if [ "$(head -1 "$f")" != "${SPDX}" ] + then + sed -i "1i${SPDX}\n" "$f" + fi + + if ! grep 'Copyright' "$f" > /dev/null + then + echo "Missing copyright info in $f" + fi +done diff --git a/tasm/scripts/makefile b/tasm/scripts/makefile new file mode 100644 index 0000000..5c87c98 --- /dev/null +++ b/tasm/scripts/makefile @@ -0,0 +1,72 @@ +# this could be done better +RELEASE ?= 0 +OPTFLAGS != [ "$(RELEASE)" != "0" ] \ + && echo "-O3 -flto" \ + || echo "-O0" + +DEBUG ?= 1 +DEBUGFLAGS != [ "$(DEBUG)" != "0" ] \ + && echo "-DDEBUG=1" \ + || echo "-DNDEBUG=1" + +ASSERT ?= 1 +ASSERTFLAGS != [ "$(ASSERT)" != "0" ] \ + && echo "-DASSERT=1" \ + || echo + +DEPFLAGS = -MT $@ -MMD -MP -MF $@.d +LINTFLAGS = -fsyntax-only +PREPROCESS = -E + +LLVM ?= 0 +BUILD = build + +all: tasm + +# default values, overwrite if/when needed +CROSS_COMPILE = + +OBJCOPY != [ "$(LLVM)" != "0" ] \ + && echo llvm-objcopy \ + || echo $(CROSS_COMPILE)objcopy + +COMPILER != [ "$(LLVM)" != "0" ] \ + && echo clang --target="$(CROSS_COMPILE)" \ + || echo $(CROSS_COMPILE)gcc + + +OBFLAGS = -std=gnu17 -g +WARNFLAGS = -Wall -Wextra + +COMPILE_FLAGS = $(CFLAGS) $(WARNFLAGS) $(OPTFLAGS) $(OBFLAGS) $(ASSERTFLAGS) \ + $(DEBUGFLAGS) + +INCLUDE_FLAGS = -I include -I ../core + +# This makes sure .bss is loaded into the binary +OBJCOPY_FLAGS ?= -Obinary -R .garbage \ + --set-section-flags .bss=alloc,load,contents + +COMPILE = $(COMPILER) \ + $(COMPILE_FLAGS) $(DEPFLAGS) $(INCLUDE_FLAGS) + +LINT = $(COMPILER) \ + $(COMPILE_FLAGS) $(LINTFLAGS) $(INCLUDE_FLAGS) + +UBSAN ?= 0 +TASM_FLAGS != [ "$(UBSAN)" != "0" ] \ + && echo -fsanitize=undefined \ + || echo + +COMPILE_TASM = $(COMPILE) $(TASM_FLAGS) + +-include deps.mk +-include src/source.mk + +tasm: $(TASM_OBJS) + $(COMPILE_TASM) $(TASM_OBJS) -o $@ + + +# might lint some common things twice +.PHONY: +lint: $(TASM_LINTS) diff --git a/tasm/scripts/warn-undocumented b/tasm/scripts/warn-undocumented new file mode 100755 index 0000000..aa7d0f7 --- /dev/null +++ b/tasm/scripts/warn-undocumented @@ -0,0 +1,7 @@ +#!/bin/sh +# look through all files for either @file or \file +for file in $@ +do + grep -c '[@\]file' "$file" |\ + awk -F':' "\$1 == 0 {print \"Undocumented file: $file\"}" +done diff --git a/tasm/src/assembler.c b/tasm/src/assembler.c new file mode 100644 index 0000000..c0c05be --- /dev/null +++ b/tasm/src/assembler.c @@ -0,0 +1,393 @@ +#include <tasm/assembler.h> +#include <tasm/parser.h> +#include <tasm/bits.h> + +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <limits.h> +#include <stdio.h> +#include <errno.h> + +struct asm_ctx { + size_t size; + size_t idx; + tri_t *buf; +}; + +static void emit(struct asm_ctx *ctx, tri_t i) +{ + if (ctx->size == ctx->idx) { + ctx->size *= 2; + ctx->buf = realloc(ctx->buf, ctx->size * sizeof(tri_t)); + } + + ctx->buf[ctx->idx++] = i; +} + +static bool check_imm(tri_t imm, size_t n) +{ + /* check that we can fit imm into n trits */ + return tri_mask(imm, n) == imm; +} + +tri_t parse_imm(const char *imm) +{ + size_t len = strlen(imm); + if (len < 2) { + /* must be base 10 */ + char *end = NULL; + int64_t val = strtoll(imm, &end, 10); + assert(imm + len == end); + return tri_from(val); + } + + if (strncmp(imm, "0t", 2) == 0) { + /* must be raw trinary */ + return tri_parse_default(imm, len); + } + + if (strncmp(imm, "0h", 2) == 0) { + /* must be heptavintimal */ + fprintf(stderr, "heptavintimal not yet implemented\n"); + abort(); + return 0; + } + + /* try to let strtoll figure out */ + char *end = NULL; + int64_t val = strtoll(imm, &end, 0); + if (imm + len == end) + return tri_from(val); + + + fprintf(stderr, "unrecognised immediate: %s\n", imm); + abort(); + return 0; +} + +void emit_r(struct asm_ctx *ctx, tri_t opcode, + enum gpr_num rd, tri_t fn0, enum gpr_num rs1, + enum gpr_num rs2, tri_t fn5) +{ + tri_t xrd = gpr_tri(rd ); + tri_t xrs1 = gpr_tri(rs1); + tri_t xrs2 = gpr_tri(rs2); + tri_t i = build_r(opcode, xrd, fn0, xrs1, xrs2, fn5); + emit(ctx, i); +} + +void emit_i(struct asm_ctx *ctx, tri_t opcode, + enum gpr_num rd, tri_t fn0, enum gpr_num rs1, tri_t imm9) +{ + tri_t xrd = gpr_tri(rd ); + tri_t xrs1 = gpr_tri(rs1); + if (!check_imm(imm9, 9)) { + fprintf(stderr, "immediate %lx doesn't fit into 9 trits\n", imm9); + abort(); + return; + } + tri_t i = build_i(opcode, xrd, fn0, xrs1, imm9); + emit(ctx, i); +} + +void emit_s(struct asm_ctx *ctx, tri_t opcode, + tri_t fn0, enum gpr_num rs1, enum gpr_num rs2, tri_t imm9) +{ + tri_t xrs1 = gpr_tri(rs1); + tri_t xrs2 = gpr_tri(rs2); + if (!check_imm(imm9, 9)) { + fprintf(stderr, "immediate %lx doesn't fit into 9 trits\n", imm9); + abort(); + return; + } + tri_t imm4 = tri_mask(imm9, 4); + tri_t imm5 = tri_mask(tri_sr(imm9, 4), 5); + + tri_t i = build_s(opcode, imm4, fn0, xrs1, xrs2, imm5); + emit(ctx, i); +} + +void emit_u(struct asm_ctx *ctx, tri_t opcode, + enum gpr_num rd, tri_t imm18) +{ + tri_t xrd = gpr_tri(rd); + if (!check_imm(imm18, 18)) { + fprintf(stderr, "immediate %lx does not fit into 18 trits\n", imm18); + abort(); + return; + } + + tri_t i = build_u(opcode, xrd, imm18); + emit(ctx, i); +} + +void emit_d(struct asm_ctx *ctx, tri_t opcode, + enum gpr_num rd, enum gpr_num rs1, enum gpr_num rs2, tri_t imm10) +{ + tri_t xrd = gpr_tri(rd ); + tri_t xrs1 = gpr_tri(rs1); + tri_t xrs2 = gpr_tri(rs2); + + if (!check_imm(imm10, 10)) { + fprintf(stderr, "immediate %lx does not fit into 10 trits\n", imm10); + abort(); + return; + } + + tri_t imm0 = tri_mask(imm10, 5); + tri_t imm1 = tri_mask(tri_sr(imm10, 5), 5); + + tri_t i = build_r(opcode, xrd, imm0, xrs1, xrs2, imm1); + emit(ctx, i); +} + +static char *tasm_basename(const char *file) +{ + size_t l = strlen(file); + size_t n = l - 1; + while (--n) { + if (file[n] == '/') + break; + } + + if (n == 0) + return strdup(file); + + return strndup(file + n + 1, l - n); +} + +static char *tasm_dirname(const char *file) +{ + size_t l = strlen(file); + size_t n = l - 1; + while (--n) { + if (file[n] == '/') + break; + } + + return strndup(file, n); +} + +static char *tasm_cwdname() +{ + size_t size; + long path_max = pathconf(".", _PC_PATH_MAX); + if (path_max == -1) + size = 1024; + else + size = (size_t)path_max; + + char *buf = malloc(size); + if (!buf) + return NULL; + + if (!getcwd(buf, size)) { + fprintf(stderr, "%s\n", strerror(errno)); + free(buf); + return NULL; + } + + return buf; +} + +static char *read_file(const char *file, FILE *f) +{ + fseek(f, 0, SEEK_END); + /** @todo check how well standardized this actually is */ + long s = ftell(f); + if (s == LONG_MAX) { + fprintf(stderr, "%s might be a directory", file); + return NULL; + } + + fseek(f, 0, SEEK_SET); + + char *buf = malloc(s + 1); + if (!buf) + return NULL; + + fread(buf, s + 1, 1, f); + /* remember terminating null */ + buf[s] = 0; + return buf; +} + +static int process(struct asm_ctx *ctx, const char *file) +{ + FILE *f = fopen(file, "rb"); + if (!f) { + fprintf(stderr, "failed opening %s: %s\n", file, strerror(errno)); + return -1; + } + + const char *buf = read_file(file, f); + fclose(f); + + if (!buf) + return -1; + + struct parser *p = create_parser(); + parse(p, ctx, file, buf); + bool failed = p->failed; + destroy_parser(p); + + free((void *)buf); + + if (failed) + return -1; + + return 0; +} + +/** @todo eventually take context */ +int process_file(struct asm_ctx *ctx, const char *file) +{ + const char *base = tasm_basename(file); + const char *dir = tasm_dirname(file); + + const char *cwd = tasm_cwdname(); + + chdir(dir); + int res = process(ctx, base); + chdir(cwd); + + free((void *)base); + free((void *)dir); + free((void *)cwd); + + return res; +} + +int assemble(const char *outfile, const char *infile) +{ + /** @todo cleanup */ + struct asm_ctx ctx = {.size = 1, .buf = malloc(sizeof(tri_t)), .idx = 0}; + int ret = process_file(&ctx, infile); + if (ret) + return ret; + + FILE *f = fopen(outfile, "wb"); + if (!f) + return -1; + + for (size_t i = 0; i < ctx.idx; ++i) { + tri_t t = ctx.buf[i]; + /* output trytewise LE */ + uint32_t t0 = tri_mask(t, 9); + uint32_t t1 = tri_mask(tri_sr(t, 9), 9); + uint32_t t2 = tri_mask(tri_sr(t, 18), 9); + + size_t c0 = fwrite(&t0, sizeof(t0), 1, f); + size_t c1 = fwrite(&t1, sizeof(t1), 1, f); + size_t c2 = fwrite(&t2, sizeof(t2), 1, f); + + /* better error handling would be nice */ + assert(c0); + assert(c1); + assert(c2); + } + + fclose(f); + free(ctx.buf); +} + +void check_shift(tri_t shmt) +{ + int64_t v = tri_from(shmt); + assert(v < 27); +} + +tri_t check_nop(const char *nop) +{ + tri_t r = 0; + size_t count = 0; + size_t len = strlen(nop); + for (size_t i = 0; i < len; ++i) { + switch (nop[i]) { + case 'o': + case 'O': + case '0': tri_set_trit(r, i, 0); break; + + case 'n': + case 'N': + case 'i': tri_set_trit(r, i, -1); break; + + case 'p': + case 'P': + case '1': tri_set_trit(r, i, 1); break; + + case ' ': continue; + default: + fprintf(stderr, "invalid character in unop format: %c\n", nop[i]); + abort(); + } + + count++; + } + + assert(count == 3); + return r; +} + +tri_t check_nop3(const char *nop) +{ + tri_t r = 0; + size_t count = 0; + size_t len = strlen(nop); + for (size_t i = 0; i < len; ++i) { + switch (nop[i]) { + case 'o': + case 'O': + case '0': tri_set_trit(r, i, 0); break; + + case 'n': + case 'N': + case 'i': tri_set_trit(r, i, -1); break; + + case 'p': + case 'P': + case '1': tri_set_trit(r, i, 1); break; + + case ' ': continue; + default: + fprintf(stderr, "invalid character in unop format: %c\n", nop[i]); + abort(); + } + + count++; + } + + assert(count == 9); + return r; +} + +tri_t check_csr(const char *csr) +{ + /** @todo only mpower supported for now, will have to work on this */ + assert(strcmp(csr, "mpower")); + return 0; +} + +tri_t check_width(const char *width) +{ + if (strncmp(width, "w", 1) == 0) + return WIDTH_W; + + if (strncmp(width, "t", 1) == 0) + return WIDTH_T; + + fprintf(stderr, "illegal width specifier: %s\n", width); + abort(); + return 0; +} + +void emit_reloc(struct asm_ctx *ctx, enum asm_reloc reloc, const char *name) +{ + /** @todo implement */ +} + +void emit_label(struct asm_ctx *ctx, const char *name) +{ + /** @todo implement */ +} diff --git a/tasm/src/bits.c b/tasm/src/bits.c new file mode 100644 index 0000000..6397e2f --- /dev/null +++ b/tasm/src/bits.c @@ -0,0 +1,75 @@ +#include <tasm/bits.h> + +tri_t parse_opcode(tri_t i) +{ + /* opcode is lowest five trits */ + return tri_mask(i, 5); +} + +tri_t build_r(tri_t opcode, tri_t rd, tri_t fn0, tri_t rs1, tri_t rs2, tri_t fn5) +{ + return opcode + | tri_sl(rd , 5) + | tri_sl(fn0, 9) + | tri_sl(rs1, 14) + | tri_sl(rs2, 18) + | tri_sl(fn5, 22); +} + +void parse_r(tri_t i, tri_t *rd, tri_t *fn0, tri_t *rs1, tri_t *rs2, tri_t *fn5) +{ + *rd = tri_mask(tri_sr(i, 5), 4); + *fn0 = tri_mask(tri_sr(i, 9), 5); + *rs1 = tri_mask(tri_sr(i, 14), 4); + *rs2 = tri_mask(tri_sr(i, 18), 4); + *fn5 = tri_mask(tri_sr(i, 22), 5); +} + +tri_t build_i(tri_t opcode, tri_t rd, tri_t fn0, tri_t rs1, tri_t imm9) +{ + return opcode + | tri_sl(rd , 5) + | tri_sl(fn0 , 9) + | tri_sl(rs1 , 14) + | tri_sl(imm9, 18); +} + +void parse_i(tri_t i, tri_t *rd, tri_t *fn0, tri_t *rs1, tri_t *imm9) +{ + *rd = tri_mask(tri_sl(i, 5), 4); + *fn0 = tri_mask(tri_sl(i, 9), 5); + *rs1 = tri_mask(tri_sl(i, 14), 4); + *imm9 = tri_mask(tri_sl(i, 18), 9); +} + +tri_t build_s(tri_t opcode, tri_t imm4, tri_t fn0, tri_t rs1, tri_t rs2, tri_t imm5) +{ + return opcode + | tri_sl(imm4, 5) + | tri_sl(fn0 , 9) + | tri_sl(rs1 , 14) + | tri_sl(rs2 , 18) + | tri_sl(imm5, 22); +} + +void parse_s(tri_t i, tri_t *imm4, tri_t *fn0, tri_t *rs1, tri_t *rs2, tri_t *imm5) +{ + *imm4 = tri_mask(tri_sl(i, 5), 4); + *fn0 = tri_mask(tri_sl(i, 9), 5); + *rs1 = tri_mask(tri_sl(i, 14), 4); + *rs2 = tri_mask(tri_sl(i, 18), 4); + *imm5 = tri_mask(tri_sl(i, 22), 5); +} + +tri_t build_u(tri_t opcode, tri_t rd, tri_t imm18) +{ + return opcode + | tri_sl(rd , 5) + | tri_sl(imm18, 9); +} + +void parse_u(tri_t i, tri_t *rd, tri_t *imm18) +{ + *rd = tri_mask(tri_sl(i, 5), 4); + *imm18 = tri_mask(tri_sl(i, 9), 18); +} diff --git a/tasm/src/lexer.l b/tasm/src/lexer.l new file mode 100644 index 0000000..01a4bee --- /dev/null +++ b/tasm/src/lexer.l @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +%option reentrant noyywrap nounput noinput nodefault +%{ +#define FROM_LEXER +#include <tasm/parser.h> + +static void update_yylloc(struct parser *parser, YYLTYPE *lloc, const char *text) +{ + (void)parser; + + lloc->first_line = lloc->last_line; + lloc->first_column = lloc->last_column; + + for (size_t i = 0; text[i] != 0; ++i) { + if (text[i] == '\n') { + lloc->last_line++; + /* flex uses 1 based indexing */ + lloc->last_column = 1; + } else { + lloc->last_column++; + } + } +} + +#define YY_USER_ACTION update_yylloc(parser, yylloc, yytext); +%} + +%x SC_COMMENT + +id [_a-zA-Z][_a-zA-Z0-9]* +label {id}[[:space:]]*: + +dec -?[0-9]+ +tri 0t[01i]+ +hept 0h[0-9A-HKMNPRTVXZa-hkmnprtvxz]+ +imm {tri}|{hept}|{dec} + +str \"(\\.|[^"\\])*\" + +%% + +{label} { + /* strip trailing ':' */ + char *s = yytext + strlen(yytext); + s[-1] = '\0'; + + yylval->str = yytext; + return label; +} + +{imm} { + yylval->tri = parse_imm(yytext); + return imm; +} + +{str} { + /* strip leading and trailing " */ + char *s = yytext + strlen(yytext); + s[-1] = '\0'; + + yylval->str = yytext + 1; + return str; +} + +".set" {return set;} +".include" {return include;} + +"x0" {return x0;} +"x1" {return x1;} +"x2" {return x2;} +"x3" {return x3;} +"x4" {return x4;} +"x5" {return x5;} +"x6" {return x6;} +"x7" {return x7;} +"x8" {return x8;} +"x9" {return x9;} +"x10" {return x10;} +"x11" {return x11;} +"x12" {return x12;} +"x13" {return x13;} +"x14" {return x14;} +"x15" {return x15;} +"x16" {return x16;} +"x17" {return x17;} +"x18" {return x18;} +"x19" {return x19;} +"x20" {return x20;} +"x21" {return x21;} +"x22" {return x22;} +"x23" {return x23;} +"x24" {return x24;} +"x25" {return x25;} +"x26" {return x26;} +"x27" {return x27;} +"x28" {return x28;} +"x29" {return x29;} +"x30" {return x30;} +"x31" {return x31;} +"x32" {return x32;} +"x33" {return x33;} +"x34" {return x34;} +"x35" {return x35;} +"x36" {return x36;} +"x37" {return x37;} +"x38" {return x38;} +"x39" {return x39;} +"x40" {return x40;} +"x41" {return x41;} +"x42" {return x42;} +"x43" {return x43;} +"x44" {return x44;} +"x45" {return x45;} +"x46" {return x46;} +"x47" {return x47;} +"x48" {return x48;} +"x49" {return x49;} +"x50" {return x50;} +"x51" {return x51;} +"x52" {return x52;} +"x53" {return x53;} +"x54" {return x54;} +"x55" {return x55;} +"x56" {return x56;} +"x57" {return x57;} +"x58" {return x58;} +"x59" {return x59;} +"x60" {return x60;} +"x61" {return x61;} +"x62" {return x62;} +"x63" {return x63;} +"x64" {return x64;} +"x65" {return x65;} +"x66" {return x66;} +"x67" {return x67;} +"x68" {return x68;} +"x69" {return x69;} +"x70" {return x70;} +"x71" {return x71;} +"x72" {return x72;} +"x73" {return x73;} +"x74" {return x74;} +"x75" {return x75;} +"x76" {return x76;} +"x77" {return x77;} +"x78" {return x78;} +"x79" {return x79;} +"x80" {return x80;} + +"addi" {return addi; /* i */} +"slti" {return slti;} +"sgei" {return sgei;} +"seqi" {return seqi;} +"snei" {return snei;} +"unop" {return unop;} +"diop" {return diop;} +"slli" {return slli;} +"srli" {return srli;} +"sll" {return sll;} +"srl" {return srl;} +"add" {return add;} +"sub" {return sub;} +"slt" {return slt;} +"sge" {return sge;} +"seq" {return seq;} +"sne" {return sne;} +"lui" {return lui;} +"auipc" {return auipc;} +"jal" {return jal;} +"jalr" {return jalr;} +"beq" {return beq;} +"bne" {return bne;} +"blt" {return blt;} +"bge" {return bge;} +"ld" {return ld;} +"st" {return st;} +"ecall" {return ecall;} +"ebreak" {return ebreak;} +"pcall" {return pcall;} +"fence" {return fence;} +"nop" {return nop; /* meta */} +"li" {return li;} +"la" {return la;} + +"mul" {return mul; /* m */} +"div" {return diV;} +"rem" {return rem;} + +"stt" {return stt; /* a */} +"cst" {return cst;} +"ent" {return ent;} +"cat" {return cat;} + +"csrrw" {return csrrw; /* Zcsr */} +"csrrs" {return csrrs;} +"csrrc" {return csrrc;} + +"//".* {/* skip line comments */} + +"/*" {BEGIN(SC_COMMENT);} +<SC_COMMENT>{ + "/*" {++parser->comment_nesting;} + "*"+"/" { + if (parser->comment_nesting) + --parser->comment_nesting; + else + BEGIN(INITIAL); + } + + "*"+ {} + [^/*\n]+ {} + [/] {} + \n {} +} + +{id} { + yylval->str = yytext; + return id; +} + +"(" {return LPAREN;} +")" {return RPAREN;} +"," {return COMMA;} + +[[:space:]]+ {/* skip whitespace */} + +. { + struct src_issue issue; + issue.loc = to_src_loc(yylloc); + issue.fctx.fbuf = parser->buf; + issue.fctx.fname = parser->fname; + src_issue(issue, "unexpected token: %s", yytext); + parser->failed = true; +} +%% diff --git a/tasm/src/main.c b/tasm/src/main.c new file mode 100644 index 0000000..bb6a1ac --- /dev/null +++ b/tasm/src/main.c @@ -0,0 +1,68 @@ +#include <tasm/assembler.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> + +static const char *cmdline_usage = +"tasm trinary assembler usage:\n" +" tasm [-I <dir>...] -o outfile infile\n" +" -h Show usage (this)\n" +" -I <dir> Add directory to include path\n" +" -o <outfile> File to output to\n" +" infile Top file to assemble\n" +; + +static void usage() +{ + fprintf(stderr, cmdline_usage); +} + +int main(int argc, char *argv[]) +{ + const char *outfile = NULL; + int opt; + while ((opt = getopt(argc, argv, "hI:o:")) != -1) { + switch (opt) { + case 'I': + fprintf(stderr, "include paths not yet implemented\n"); + break; + + case 'o': + outfile = optarg; + break; + + case 'h': + usage(); + exit(EXIT_SUCCESS); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + } + } + + if (!outfile) { + fprintf(stderr, "no output file\n"); + usage(); + exit(EXIT_FAILURE); + } + + if (optind >= argc) { + fprintf(stderr, "no input files\n"); + usage(); + exit(EXIT_FAILURE); + } + + if (optind != argc - 1) { + fprintf(stderr, "too many input files\n"); + usage(); + exit(EXIT_FAILURE); + } + + if (assemble(outfile, argv[optind])) + exit(EXIT_FAILURE); + + return EXIT_SUCCESS; +} diff --git a/tasm/src/parser.y b/tasm/src/parser.y new file mode 100644 index 0000000..ef8d3df --- /dev/null +++ b/tasm/src/parser.y @@ -0,0 +1,532 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +%{ + +/* get access to fileno to avoid warnings with flex */ +#define _POSIX_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include <tasm/assembler.h> +#include <tasm/parser.h> +#include <tasm/bits.h> +#include <tasm/regs.h> +#include <tri.h> + +%} + +%locations + +%define parse.trace +%define parse.error verbose +%define api.pure full +%define lr.type ielr + +%lex-param {void *scanner} {struct parser *parser} +%parse-param {void *scanner} {struct parser *parser} {struct asm_ctx *ctx} + +%union { + const char *str; + enum gpr_num gpr; + tri_t tri; +}; + +%token <tri> imm +%token <str> label +%token <str> str +%token <str> id + +%token COMMA "," +%token LPAREN "(" +%token RPAREN ")" + +%token set +%token include +%nterm <gpr> gpr; +%nterm <str> width addr csr + +/* regs */ +%token x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 +%token x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 +%token x20 x21 x22 x23 x24 x25 x26 x27 x28 x29 +%token x30 x31 x32 x33 x34 x35 x36 x37 x38 x39 +%token x40 x41 x42 x43 x44 x45 x46 x47 x48 x49 +%token x50 x51 x52 x53 x54 x55 x56 x57 x58 x59 +%token x60 x61 x62 x63 x64 x65 x66 x67 x68 x69 +%token x70 x71 x72 x73 x74 x75 x76 x77 x78 x79 +%token x80 + +/* i */ +%token addi slti sgei seqi snei +%token unop diop +%token slli srli sll srl +%token add sub +%token slt sge seq sne +%token lui auipc +%token jal jalr +%token beq bne blt bge +%token ld st +%token ecall ebreak pcall +%token fence +/* meta */ +%token li la nop + +/* m (avoid name clash with stdlib div) */ +%token mul diV rem + +/* a */ +%token stt cst ent cat + +/* Zcsr */ +%token csrrw csrrs csrrc + +%{ + +struct file_ctx { + const char *fname; + const char *fbuf; +}; + +struct src_loc { + int first_line; + int last_line; + int first_col; + int last_col; +}; + +struct src_issue { + struct src_loc loc; + struct file_ctx fctx; +}; + +/** Modifies the signature of yylex to fit our parser better. */ +#define YY_DECL int yylex(YYSTYPE *yylval, YYLTYPE *yylloc, \ + void *yyscanner, struct parser *parser) + +/** + * Declare yylex. + * + * @param yylval Bison current value. + * @param yylloc Bison location info. + * @param yyscanner Flex scanner. + * @param parser Current parser state. + * @return \c 0 when succesful, \c 1 otherwise. + * More info on yylex() can be found in the flex manual. + */ +YY_DECL; + +/** + * Convert bison location info to our own source location info. + * + * @param yylloc Bison location info. + * @return Internal location info. + */ +static struct src_loc to_src_loc(YYLTYPE *yylloc); + +/** + * Print parsing error. + * Automatically called by bison. + * + * @param yylloc Location of error. + * @param lexer Lexer. + * @param parser Parser state. + * @param msg Message to print. + */ +static void yyerror(YYLTYPE *yylloc, void *lexer, + struct parser *parser, struct asm_ctx *ctx, const char *msg); + +%} + +%start input; +%% + +width + : id + +/* eventually we might allow jumping to immediate addresses, but for now require + * that a label always be used */ +addr + : id + +/* lexer makes sure the abi names are correct */ +gpr + : x0 {$$ = X0_NUM;} + | x1 {$$ = X1_NUM;} + | x2 {$$ = X2_NUM;} + | x3 {$$ = X3_NUM;} + | x4 {$$ = X4_NUM;} + | x5 {$$ = X5_NUM;} + | x6 {$$ = X6_NUM;} + | x7 {$$ = X7_NUM;} + | x8 {$$ = X8_NUM;} + | x9 {$$ = X9_NUM;} + | x10 {$$ = X10_NUM;} + | x11 {$$ = X11_NUM;} + | x12 {$$ = X12_NUM;} + | x13 {$$ = X13_NUM;} + | x14 {$$ = X14_NUM;} + | x15 {$$ = X15_NUM;} + | x16 {$$ = X16_NUM;} + | x17 {$$ = X17_NUM;} + | x18 {$$ = X18_NUM;} + | x19 {$$ = X19_NUM;} + | x20 {$$ = X20_NUM;} + | x21 {$$ = X21_NUM;} + | x22 {$$ = X22_NUM;} + | x23 {$$ = X23_NUM;} + | x24 {$$ = X24_NUM;} + | x25 {$$ = X25_NUM;} + | x26 {$$ = X26_NUM;} + | x27 {$$ = X27_NUM;} + | x28 {$$ = X28_NUM;} + | x29 {$$ = X29_NUM;} + | x30 {$$ = X30_NUM;} + | x31 {$$ = X31_NUM;} + | x32 {$$ = X32_NUM;} + | x33 {$$ = X33_NUM;} + | x34 {$$ = X34_NUM;} + | x35 {$$ = X35_NUM;} + | x36 {$$ = X36_NUM;} + | x37 {$$ = X37_NUM;} + | x38 {$$ = X38_NUM;} + | x39 {$$ = X39_NUM;} + | x40 {$$ = X40_NUM;} + | x41 {$$ = X41_NUM;} + | x42 {$$ = X42_NUM;} + | x43 {$$ = X43_NUM;} + | x44 {$$ = X44_NUM;} + | x45 {$$ = X45_NUM;} + | x46 {$$ = X46_NUM;} + | x47 {$$ = X47_NUM;} + | x48 {$$ = X48_NUM;} + | x49 {$$ = X49_NUM;} + | x50 {$$ = X50_NUM;} + | x51 {$$ = X51_NUM;} + | x52 {$$ = X52_NUM;} + | x53 {$$ = X53_NUM;} + | x54 {$$ = X54_NUM;} + | x55 {$$ = X55_NUM;} + | x56 {$$ = X56_NUM;} + | x57 {$$ = X57_NUM;} + | x58 {$$ = X58_NUM;} + | x59 {$$ = X59_NUM;} + | x60 {$$ = X60_NUM;} + | x61 {$$ = X61_NUM;} + | x62 {$$ = X62_NUM;} + | x63 {$$ = X63_NUM;} + | x64 {$$ = X64_NUM;} + | x65 {$$ = X65_NUM;} + | x66 {$$ = X66_NUM;} + | x67 {$$ = X67_NUM;} + | x68 {$$ = X68_NUM;} + | x69 {$$ = X69_NUM;} + | x70 {$$ = X70_NUM;} + | x71 {$$ = X71_NUM;} + | x72 {$$ = X72_NUM;} + | x73 {$$ = X73_NUM;} + | x74 {$$ = X74_NUM;} + | x75 {$$ = X75_NUM;} + | x76 {$$ = X76_NUM;} + | x77 {$$ = X77_NUM;} + | x78 {$$ = X78_NUM;} + | x79 {$$ = X79_NUM;} + | x80 {$$ = X80_NUM;} + +i + : addi gpr "," gpr "," imm + {emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_ADDI, $4, $6);} + + | slti gpr "," gpr "," imm + {emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_SLTI, $4, $6);} + + | sgei gpr "," gpr "," imm + {emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_SGEI, $4, $6);} + + | seqi gpr "," gpr "," imm + {emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_SEQI, $4, $6);} + + | snei gpr "," gpr "," imm + {emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_SNEI, $4, $6);} + + | slli gpr "," gpr "," imm + {check_shift($6); emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_SLLI, $4, $6);} + + | srli gpr "," gpr "," imm + {check_shift($6); emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_SRLI, $4, $6);} + + | add gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_ADD, $4, $6, 0);} + + | sub gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_SUB, $4, $6, 0);} + + | slt gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_SLT, $4, $6, 0);} + + | sge gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_SGE, $4, $6, 0);} + + | seq gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_SEQ, $4, $6, 0);} + + | sne gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_SNE, $4, $6, 0);} + + | sll gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_SLL, $4, $6, 0);} + + | srl gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_SRL, $4, $6, 0);} + + | lui gpr "," imm + {emit_u(ctx, OPCODE_LUI, $2, $4);} + + | auipc gpr "," imm + {emit_u(ctx, OPCODE_AUIPC, $2, $4);} + + | jal gpr "," addr + {emit_u(ctx, OPCODE_JAL, $2, 0); + emit_reloc(ctx, RELOC_J, $4);} + + | jalr gpr "," gpr "," imm + {emit_i(ctx, OPCODE_JALR, $2, 0, $4, $6);} + + | beq gpr "," gpr "," addr + {emit_s(ctx, OPCODE_BRANCH, BRANCH_BEQ, $2, $4, 0); + emit_reloc(ctx, RELOC_B, $6);} + + | bne gpr "," gpr "," addr + {emit_s(ctx, OPCODE_BRANCH, BRANCH_BNE, $2, $4, 0); + emit_reloc(ctx, RELOC_B, $6);} + + | blt gpr "," gpr "," addr + {emit_s(ctx, OPCODE_BRANCH, BRANCH_BLT, $2, $4, 0); + emit_reloc(ctx, RELOC_B, $6);} + + | bge gpr "," gpr "," addr + {emit_s(ctx, OPCODE_BRANCH, BRANCH_BGE, $2, $4, 0); + emit_reloc(ctx, RELOC_B, $6);} + + | ld width "," gpr "," imm "(" gpr ")" + {emit_i(ctx, OPCODE_LOAD, check_width($2), $4, $8, $6);} + + | st width "," gpr "," imm "(" gpr ")" + {emit_s(ctx, OPCODE_STORE, check_width($2), $4, $8, $6);} + + | ecall + {emit_i(ctx, OPCODE_SYSTEM, X0_NUM, SYSTEM_ECALL, X0_NUM, 0);} + + | ebreak + {emit_i(ctx, OPCODE_SYSTEM, X0_NUM, SYSTEM_EBREAK, X0_NUM, 0);} + + | pcall + {emit_i(ctx, OPCODE_SYSTEM, X0_NUM, SYSTEM_PCALL, X0_NUM, 0);} + + | fence + {emit_i(ctx, OPCODE_MEM, X0_NUM, MEM_FENCE, X0_NUM, 0); /* still todo */} + + | unop gpr "," gpr "," str + {emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_UNOP, $4, check_nop($6));} + + | diop gpr "," gpr "," gpr "," str + {emit_d(ctx, OPCODE_DIOP, $2, $4, $6, check_nop3($8));} + + /* meta */ + | nop + {emit_i(ctx, OPCODE_OP_IMM, X0_NUM, OP_IMM_ADDI, X0_NUM, 0);} + + | la gpr "," addr + {emit_u(ctx, OPCODE_LUI, $2, 0); + /* important that the reloc is in the middle here */ + emit_reloc(ctx, RELOC_LA, $4); + emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_ADDI, $2, 0);} + + | li gpr "," imm + {emit_u(ctx, OPCODE_LUI, $2, 0); + emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_ADDI, $2, 0);} + /* stuff like call and ret TBD once I've come up with a proper register + * calling convention so we know which register to use as ra */ + +m + : mul gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_MUL, $4, $6, 0);} + + | diV gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_DIV, $4, $6, 0);} + + | rem gpr "," gpr "," gpr + {emit_r(ctx, OPCODE_OP, $2, OP_DIV, $4, $6, 0);} + +a + : stt + {emit_i(ctx, OPCODE_MEM, X0_NUM, MEM_STT, X0_NUM, 0);} + + | cst width "," gpr "," imm "(" gpr ")" + {emit_s(ctx, OPCODE_STORE, STORE_CST | check_width($2), $4, $8, $6);} + + | ent gpr + {emit_i(ctx, OPCODE_MEM, $2, MEM_ENT, X0_NUM, 0);} + + | cat + {emit_i(ctx, OPCODE_MEM, X0_NUM, MEM_CAT, X0_NUM, 0);} + +Zcsr + : csrrw csr "," gpr "," gpr + {emit_i(ctx, OPCODE_SYSTEM, $4, SYSTEM_CSRRW, $6, check_csr($2));} + + | csrrs csr "," gpr "," gpr + {emit_i(ctx, OPCODE_SYSTEM, $4, SYSTEM_CSRRS, $6, check_csr($2));} + + | csrrc csr "," gpr "," gpr + {emit_i(ctx, OPCODE_SYSTEM, $4, SYSTEM_CSRRC, $6, check_csr($2));} + +csr + : id + +statement + : i + | a + | m + | Zcsr + +directive + : set id imm + | include str {process_file(ctx, $2);} + +top + : label {emit_label(ctx, $1);} + | statement + | directive + +unit + : top + | top unit + +input + : unit + | /* empty */ + +%% + +static const char *find_lineno(const char *buf, size_t no) +{ + if (no == 0 || no == 1) + return buf; + + char c; + while ((c = *buf)) { + buf++; + + if (c == '\n') + no--; + + if (no == 1) + break; + } + + return buf; +} + +static void _issue(struct src_issue issue, const char *fmt, va_list args) +{ + /* get start and end of current line in buffer */ + const char *line_start = find_lineno(issue.fctx.fbuf, + issue.loc.first_line); + const char *line_end = strchr(line_start, '\n'); + if (!line_end) + line_end = strchr(line_start, 0); + + const int line_len = line_end - line_start; + + fprintf(stderr, "%s:%i:%i: ", + issue.fctx.fname, + issue.loc.first_line, + issue.loc.first_col); + + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + + int lineno_len = snprintf(NULL, 0, "%i", issue.loc.first_line); + fputc(' ', stderr); + fprintf(stderr, "%i | ", issue.loc.first_line); + + fprintf(stderr, "%.*s\n", line_len, line_start); + + for (int i = 0; i < lineno_len + 2; ++i) + fputc(' ', stderr); + + fprintf(stderr, "| "); + + for (int i = 0; i < issue.loc.first_col - 1; ++i) + fputc(line_start[i] == '\t' ? '\t' : ' ', stderr); + + for (int i = issue.loc.first_col; i < issue.loc.last_col; ++i) { + if (i == issue.loc.first_col) + fputc('^', stderr); + else + fputc('~', stderr); + } + + fputc('\n', stderr); +} + +void src_issue(struct src_issue issue, const char *err_msg, ...) +{ + va_list args; + va_start(args, err_msg); + _issue(issue, err_msg, args); + va_end(args); +} +#include "gen_lexer.inc" + +static struct src_loc to_src_loc(YYLTYPE *yylloc) +{ + struct src_loc loc; + loc.first_line = yylloc->first_line; + loc.last_line = yylloc->last_line; + loc.first_col = yylloc->first_column; + loc.last_col = yylloc->last_column; + return loc; +} + +static void yyerror(YYLTYPE *yylloc, void *lexer, + struct parser *parser, struct asm_ctx *ctx, const char *msg) +{ + (void)lexer; + (void)ctx; + + struct src_issue issue; + issue.loc = to_src_loc(yylloc); + issue.fctx.fbuf = parser->buf; + issue.fctx.fname = parser->fname; + src_issue(issue, msg); +} + +struct parser *create_parser() +{ + return calloc(1, sizeof(struct parser)); +} + +void destroy_parser(struct parser *p) +{ + yylex_destroy(p->lexer); + free(p); +} + +void parse(struct parser *p, struct asm_ctx *ctx, const char *fname, const char *buf) +{ + p->fname = fname; + p->buf = buf; + + p->comment_nesting = 0; + + p->failed = false; + + yylex_init(&p->lexer); + yy_scan_string(buf, p->lexer); + yyparse(p->lexer, p, ctx); +} diff --git a/tasm/src/source.mk b/tasm/src/source.mk new file mode 100644 index 0000000..5052ba3 --- /dev/null +++ b/tasm/src/source.mk @@ -0,0 +1,8 @@ +SOURCES != echo src/*.c +TASM_SOURCES += $(SOURCES) gen/gen_parser.c + +gen/gen_parser.c: src/parser.y gen/gen_lexer.inc + bison -Wcounterexamples -o gen/gen_parser.c src/parser.y + +gen/gen_lexer.inc: src/lexer.l + flex -o gen/gen_lexer.inc src/lexer.l diff --git a/tasm/tests/a.t b/tasm/tests/a.t new file mode 100644 index 0000000..f23f9c0 --- /dev/null +++ b/tasm/tests/a.t @@ -0,0 +1,6 @@ +start: + li x1, 48 + li x2, 19683 + st w, x1, 0(x2) + li x1, 3 + csrrw mpower, x0, x1 diff --git a/tasm/tests/include.t b/tasm/tests/include.t new file mode 100644 index 0000000..50dfe97 --- /dev/null +++ b/tasm/tests/include.t @@ -0,0 +1 @@ +.include "a.t" diff --git a/triscv/Makefile b/triscv/Makefile new file mode 100644 index 0000000..adceb03 --- /dev/null +++ b/triscv/Makefile @@ -0,0 +1,56 @@ +.PHONY: all +all: setup + $(MAKE) -f scripts/makefile + +# this kicks all unrecognised targets to the client script. +# note that trying to compile individual files, e.g. +# +# make kernel.elf +# +# will not work, you would need +# +# make -f scripts/makefile kernel.elf +# +# instead +.DEFAULT: setup + $(MAKE) -f scripts/makefile $< + +.PHONY: +setup: + @echo -n > deps.mk + @./scripts/gen-deps -p TRISCV -c COMPILE_TRISCV -b triscv "${TRISCV_SOURCES}" + +CLEANUP := build deps.mk triscv +CLEANUP_CMD := +TRISCV_SOURCES := deps/utf9/utf9.c + +include src/source.mk + +.PHONY: format +format: + find arch lib common include -iname '*.[ch]' |\ + xargs uncrustify -c uncrustify.conf --no-backup -F - + +.PHONY: license +license: + find arch lib common include -iname '*.[ch]' |\ + xargs ./scripts/license + +.PHONY: docs +docs: + find arch lib common include -iname '*.[ch]' -not -path */gen/* |\ + xargs ./scripts/warn-undocumented + doxygen docs/doxygen.conf + +RM = rm + +.PHONY: clean +clean: + $(RM) -rf $(CLEANUP) + +.PHONY: clean_docs +clean_docs: + $(RM) -rf docs/output + +.PHONY: clean_all +clean_all: clean clean_docs diff --git a/triscv/README.md b/triscv/README.md new file mode 100644 index 0000000..3b8beeb --- /dev/null +++ b/triscv/README.md @@ -0,0 +1,272 @@ +# `triscv`, a trinary riscv-like ISA simulator + +An attempt at creating a trinary computer simulator capable of running simple +operating systems, with virtual memory and user/system separation. + +Natural bases of three used as trit groupings, i.e. +3^0 = trit +3^1 = nit (likely not actually used?) +3^2 = tryte (base size of characters etc, similar to byte) +3^3 = tri (base word size) + +Ideally I would like to extend support up to 3^4 (tril?) that would be +equivalent to 64 bit groupings on conventional hardware, but the my trinary +arithmetic library underlying the simulator doesn't support 81 trits due to +efficiency/portability concerns. 128 bit integers could be usable on at least +x86, but not really portable. Something like `gmp` could also be used, but would +be very slow. Alternatively, consider 45 trit as an equivalence to 64 bit +computers, as they are approximately the same in value and divisible by three. + +Heavy inspiration taken from riscv. + +M-mode/S-mode/U-mode fits pretty nicely into trinary, heh. + +# Operation set + +27 trit ops, registers 3^4? + + 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 + 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +|-----------------------------------------------------| +| fn5 | rs2 | rs1 | fn0 | rd | opcode | R-type +|-----------------------------------------------------| +| imm9 | rs1 | fn0 | rd | opcode | I-type +|-----------------------------------------------------| +| imm5 | rs2 | rs1 | fn0 | imm4 | opcode | S-type +|-----------------------------------------------------| +| imm18 | rd | opcode | U-type +|-----------------------------------------------------| +| imm5 | rs2 | rs1 | immd | rd | opcode | D-type +|-----------------------------------------------------| +(D is a variant of R, where immd is actually fn0, but used as an immediate) + +Compressed instructions probably possible to implement in future but left alone +for now. + +Exact instructions still TBD, but R type probably reserves one fn trit value for +diops. It's unclear to me how readily diops can be implemented in hardware, so +consider this more exploratory than anythin else. + +Similarly, I-type reserved on fn trit value to unops. + +Turns out it's literally just a mapping, i.e. unops use a three-way mux with +the input value as the selection trit and the three control bits inputs to the +mux. Similarly, diops are just a nine-way mux. + +# Registers + +81, of which x0 is constant 0. ABI TBD but probably similar to riscv. + +# Virtual memory + +Physical memory consists of PPN[2], PPN[1], PPN[0] and page offset. 27 trits is enough +for about 7 teratrytes of memory, which probably doesn't need range extensions +like 32bit computers tend to use. + +Page table entries: + + 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 + 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +|-----------------------------------------------------| +| PPN[2] | PPN[1] | PPN[0] |RSW|G|U|X|A|R|V| +|------------------------------------------------D-W--| +| TAG | +|-----------------------------------------------------| +| Reserved | +|-----------------------------------------------------| + +TAG is a tag that allows us to separate one address space into multiple regions, +similar to CODOMS system but scaled down a lot. If left 0, code executing in the +region is allowed to access other regions but outside regions are not allowed to +access the zero region, except executing a migration jump. + +The reserved region might come +in handy for 'extensions' in the future, but can probably be set to zero for +now. + +R/W and A/D work by the following table: + +N => both (R and W, A and D) +O => none +P => top (R, A) + +RSW is reserved for S-mode usage. + +The idea here is a page marked write must also be marked read, and a dirty page +must also have been accessed. Whether an interrupt is raised when A/D is updated +is set by a status CSR, to be determined later. Three-level page tables. + +Each base page is 3^8 = 6561, and since each PTE +takes up 9 trytes, each base page can fit 3^6 PTEs. Therefore, to cover the full +27 bit address space, we need three `satp` CSRs, `satpn`, `satpo`, `satpp`, +corresponding to the first trit in the address. This can give reasonably +efficient separation of user/kernelspace, for example -1 for kernel and 1 for +user. Still about 2.5 tera per space. + +This can be extended to 81 bits, although with no nice whole number that maps to +81. Not a huge deal, by any means, although kind of annoying that the number of +elements per PTE shrinks to 243. Maybe not a huge issue, but might limit +useability somewhat as the number of page levels has to be increased much more +rapidly to get larger virtual address spaces. + +Requiring physical addresses to be the same width as virtual addresses +simplifies hypervisor stuff somewhat, could be useful? Not that allocating some +pages in series is too big of an issue, but still feels like an unnecessary +complication in the RISC-V specs. Apparently the explanation given is that is +can be useful to emulate larger physical address spaces than virtual spaces, +though I'd like to see some examples. I guess easier masking of some addresses? +Dunno. + +I might want to add in a bus error to separate it from pmp errors, there's been +some discussion about it in riscv mailing lists. + +# CSRs + +TDB + +# Extensions + +## I + +addi, slti +|-----------------------------------------------------| +| imm0 | rs1 | fn0 | rd | OP-IMM | I-type +|-----------------------------------------------------| + +unop (some macro instructions might be available in assembler) +|-----------------------------------------------------| +| 0 |N|O|P| rs1 | fn0 | rd | OP-IMM | I-type +|-----------------------------------------------------| + +slli, srli (shifts work differently in balanced forms, have to be careful) + (shmt is 'unsigned', i.e. the actual shift amount is shmt + 13) +|-----------------------------------------------------| +| imm0 |shmt | rs1 | fn0 | rd | OP-IMM | I-type +|-----------------------------------------------------| + +lui +|-----------------------------------------------------| +| imm9 | rd | LUI | U-type +|-----------------------------------------------------| + +auipc +|-----------------------------------------------------| +| imm9 | rd | AUIPC | U-type +|-----------------------------------------------------| + +add, slt, sge, seq, sne, sll, srl, sub +|-----------------------------------------------------| +| 0 | rs2 | rs1 | fn0 | rd | OP | R-type +|-----------------------------------------------------| + +diop +|-----------------------------------------------------| +|N|O|P|N|O| rs2 | rs1 |P|N|O|P|0| rd | DIOP | D-type +|-----------------------------------------------------| + +nop +|-----------------------------------------------------| +| 0 | x0 | 0 | x0 | OP-IMM | I-type +|-----------------------------------------------------| + +jal +|-----------------------------------------------------| +| imm9 | rd | JAL | U-type +|-----------------------------------------------------| + +jalr +|-----------------------------------------------------| +| imm0 | rs1 | 0 | rd | JALR | I-type +|-----------------------------------------------------| + +beq, bne, blt, bge +|-----------------------------------------------------| +| imm0 | rs2 | rs1 | fn0 | imm4 | BRANCH | S-type +|-----------------------------------------------------| + +load (w = width, i = 1 tryte, 0 = 3 trytes, 1 = 9 trytes) +|-----------------------------------------------------| +| imm0 | rs1 |w| 0 | rd | LOAD | I-type +|-----------------------------------------------------| + +store +|-----------------------------------------------------| +| imm5 | rs2 | rs1 |w| 0 | imm4 | STORE | S-type +|-----------------------------------------------------| + +fence (todo) +|-----------------------------------------------------| +| imm0 | rs1 | fn0 | rd | MEM | I-type +|-----------------------------------------------------| + +ecall, ebreak, pcall +|-----------------------------------------------------| +| imm0 | x0 | fn0 | x0 | SYSTEM | I-type +|-----------------------------------------------------| + +hints, any OP-IMM or OP with rd = x0. Additionally, +a number of maybe-instructions in SYSTEM for future use, if unimplemented +just write 0 to rd. + +## M + +mul +|-----------------------------------------------------| +| fn5 | rs2 | rs1 | fn0 | rd | OP | R-type +|-----------------------------------------------------| + +div +|-----------------------------------------------------| +| fn5 | rs2 | rs1 | fn0 | rd | OP | R-type +|-----------------------------------------------------| + +rem +|-----------------------------------------------------| +| fn5 | rs2 | rs1 | fn0 | rd | OP | R-type +|-----------------------------------------------------| + +## A + +stt (start transaction) +cst (checked store) +ent (end transaction) +cat (cancel transaction) + +Each system has a buffer with at least three slots for checked transactions. +Each checked transaction is written to the buffer when an stc is encountered. +stc clears out this buffer and ent checks if all stores are valid and flushes +the buffer to real memory, or cache or wherever. A system is allowed to give +each core a buffer or use a global buffer, but the size should be given in a CSR +somewhere. Platforms may require at least n slots. Maybe? Reads inside +transaction read from memory. Slow commits, at least somewhat, but probably +somewhat simpler. Spinlock (and by extension, mutex) would then be + +spinlock: + // spin until a zero appears + lw x1, (x2) + bnez x1, spinlock + + // start transaction, try to write 1 + stt + li x1, 1 + stc x1, (x2) + ent x1 + // someone else tried at the same time, wait for next zero + // preferably also do a spin for a random but increasing time to try to + // avoid livelock, or rely on whatever system we're dealing with to + // provide it for us + beqz x1, spinlock + +could probably also provide simple atomics, like add or something, but eh + +## Zicsr + +csrrw, csrrs, csrrc +|-----------------------------------------------------| +| imm0 | rs | fn0 | rd | SYSTEM | I-type +|-----------------------------------------------------| + +The CSR numbers are specified in the future. + +Also, possibly floating point stuff in the future, though I haven't chosen a +floating point format yet. diff --git a/triscv/deps/utf9 b/triscv/deps/utf9 new file mode 120000 index 0000000..d8b349e --- /dev/null +++ b/triscv/deps/utf9 @@ -0,0 +1 @@ +../../utf9
\ No newline at end of file diff --git a/triscv/docs/doxygen-kmi.css b/triscv/docs/doxygen-kmi.css new file mode 100644 index 0000000..39d144e --- /dev/null +++ b/triscv/docs/doxygen-kmi.css @@ -0,0 +1,2137 @@ +/** + +Doxygen Awesome +https://github.com/jothepro/doxygen-awesome-css + +MIT License + +Copyright (c) 2021 - 2022 jothepro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + */ + +html { + /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ + --primary-color: #1779c4; + --primary-dark-color: #335c80; + --primary-light-color: #70b1e9; + + /* page base colors */ + --page-background-color: white; + --page-foreground-color: #2f4153; + --page-secondary-foreground-color: #637485; + + /* color for all separators on the website: hr, borders, ... */ + --separator-color: #dedede; + + /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */ + --border-radius-large: 8px; + --border-radius-small: 4px; + --border-radius-medium: 6px; + + /* default spacings. Most compontest reference these values for spacing, to provide uniform spacing on the page. */ + --spacing-small: 5px; + --spacing-medium: 10px; + --spacing-large: 16px; + + /* default box shadow used for raising an element above the normal content. Used in dropdowns, Searchresult, ... */ + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); + + --odd-color: rgba(0,0,0,.028); + + /* font-families. will affect all text on the website + * font-family: the normal font for text, headlines, menus + * font-family-monospace: used for preformatted text in memtitle, code, fragments + */ +--font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; +--font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + +/* font sizes */ +--page-font-size: 15.6px; +--navigation-font-size: 14.4px; +--code-font-size: 14px; /* affects code, fragment */ +--title-font-size: 22px; + +/* content text properties. These only affect the page content, not the navigation or any other ui elements */ +--content-line-height: 27px; +/* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ +--content-maxwidth: 1000px; + +/* colors for various content boxes: @warning, @note, @deprecated @bug */ +--warning-color: #f8d1cc; +--warning-color-dark: #b61825; +--warning-color-darker: #75070f; +--note-color: #faf3d8; +--note-color-dark: #f3a600; +--note-color-darker: #5f4204; +--todo-color: #e4f3ff; +--todo-color-dark: #1879C4; +--todo-color-darker: #274a5c; +--deprecated-color: #ecf0f3; +--deprecated-color-dark: #5b6269; +--deprecated-color-darker: #43454a; +--bug-color: #e4dafd; +--bug-color-dark: #5b2bdd; +--bug-color-darker: #2a0d72; +--invariant-color: #d8f1e3; +--invariant-color-dark: #44b86f; +--invariant-color-darker: #265532; + +/* blockquote colors */ +--blockquote-background: #f8f9fa; +--blockquote-foreground: #636568; + +/* table colors */ +--tablehead-background: #f1f1f1; +--tablehead-foreground: var(--page-foreground-color); + +/* menu-display: block | none + * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible. + * `GENERATE_TREEVIEW` MUST be enabled! + */ +--menu-display: block; + +--menu-focus-foreground: var(--page-background-color); +--menu-focus-background: var(--primary-color); +--menu-selected-background: rgba(0,0,0,.05); + + +--header-background: var(--page-background-color); +--header-foreground: var(--page-foreground-color); + +/* searchbar colors */ +--searchbar-background: var(--side-nav-background); +--searchbar-foreground: var(--page-foreground-color); + +/* searchbar size + * (`searchbar-width` is only applied on screens >= 768px. + * on smaller screens the searchbar will always fill the entire screen width) */ +--searchbar-height: 33px; +--searchbar-width: 210px; +--searchbar-border-radius: var(--searchbar-height); + +/* code block colors */ +--code-background: #f5f5f5; +--code-foreground: var(--page-foreground-color); + +/* fragment colors */ +--fragment-background: #F8F9FA; +--fragment-foreground: #37474F; +--fragment-keyword: #bb6bb2; +--fragment-keywordtype: #8258b3; +--fragment-keywordflow: #d67c3b; +--fragment-token: #438a59; +--fragment-comment: #969696; +--fragment-link: #5383d6; +--fragment-preprocessor: #46aaa5; +--fragment-linenumber-color: #797979; +--fragment-linenumber-background: #f4f4f5; +--fragment-linenumber-border: #e3e5e7; +--fragment-lineheight: 20px; + +/* sidebar navigation (treeview) colors */ +--side-nav-background: #fbfbfb; +--side-nav-foreground: var(--page-foreground-color); +--side-nav-arrow-opacity: 0; +--side-nav-arrow-hover-opacity: 0.9; + +--toc-background: var(--side-nav-background); +--toc-foreground: var(--side-nav-foreground); + +/* height of an item in any tree / collapsable table */ +--tree-item-height: 30px; + +--memname-font-size: var(--code-font-size); +--memtitle-font-size: 18px; + +--webkit-scrollbar-size: 7px; +--webkit-scrollbar-padding: 4px; +--webkit-scrollbar-color: var(--separator-color); +} + +@media screen and (max-width: 767px) { + html { + --page-font-size: 16px; + --navigation-font-size: 16px; + --code-font-size: 15px; /* affects code, fragment */ + --title-font-size: 22px; + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #2e1917; + --warning-color-dark: #ad2617; + --warning-color-darker: #f5b1aa; + --note-color: #3b2e04; + --note-color-dark: #f1b602; + --note-color-darker: #ceb670; + --todo-color: #163750; + --todo-color-dark: #1982D2; + --todo-color-darker: #dcf0fa; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2a2536; + --bug-color-dark: #7661b3; + --bug-color-darker: #ae9ed6; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; + } +} + +/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */ +html.dark-mode { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #2e1917; + --warning-color-dark: #ad2617; + --warning-color-darker: #f5b1aa; + --note-color: #3b2e04; + --note-color-dark: #f1b602; + --note-color-darker: #ceb670; + --todo-color: #163750; + --todo-color-dark: #1982D2; + --todo-color-darker: #dcf0fa; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2a2536; + --bug-color-dark: #7661b3; + --bug-color-darker: #ae9ed6; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; +} + +body { + color: var(--page-foreground-color); + background-color: var(--page-background-color); + font-size: var(--page-font-size); +} + +body, table, div, p, dl, #nav-tree .label, .title, .sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, .SelectItem, #MSearchField, .navpath li.navelem a, .navpath li.navelem a:hover { + font-family: var(--font-family); +} + +h1, h2, h3, h4, h5 { + margin-top: .9em; + font-weight: 600; + line-height: initial; +} + +p, div, table, dl { + font-size: var(--page-font-size); +} + +a:link, a:visited, a:hover, a:focus, a:active { + color: var(--primary-color) !important; + font-weight: 500; +} + +a.anchor { + scroll-margin-top: var(--spacing-large); +} + +/* +Title and top navigation + */ + +#top { + background: var(--header-background); + border-bottom: 1px solid var(--separator-color); +} + +@media screen and (min-width: 768px) { + #top { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + } +} + +#main-nav { + flex-grow: 5; + padding: var(--spacing-small) var(--spacing-medium); +} + +#titlearea { + width: auto; + padding: var(--spacing-medium) var(--spacing-large); + background: none; + color: var(--header-foreground); + border-bottom: none; +} + +@media screen and (max-width: 767px) { + #titlearea { + padding-bottom: var(--spacing-small); + } +} + +#titlearea table tbody tr { + height: auto !important; +} + +#projectname { + font-size: var(--title-font-size); + font-weight: 600; +} + +#projectnumber { + font-family: inherit; + font-size: 60%; +} + +#projectbrief { + font-family: inherit; + font-size: 80%; +} + +#projectlogo { + vertical-align: middle; +} + +#projectlogo img { + max-height: calc(var(--title-font-size) * 2); + margin-right: var(--spacing-small); +} + +.sm-dox, .tabs, .tabs2, .tabs3 { + background: none; + padding: 0; +} + +.tabs, .tabs2, .tabs3 { + border-bottom: 1px solid var(--separator-color); + margin-bottom: -1px; +} + +@media screen and (max-width: 767px) { + .sm-dox a span.sub-arrow { + background: var(--code-background); + } + + #main-menu a.has-submenu span.sub-arrow { + color: var(--page-secondary-foreground-color); + border-radius: var(--border-radius-medium); + } + + #main-menu a.has-submenu:hover span.sub-arrow { + color: var(--page-foreground-color); + } +} + +@media screen and (min-width: 768px) { + .sm-dox li, .tablist li { + display: var(--menu-display); + } + + .sm-dox a span.sub-arrow { + border-color: var(--header-foreground) transparent transparent transparent; + } + + .sm-dox a:hover span.sub-arrow { + border-color: var(--menu-focus-foreground) transparent transparent transparent; + } + + .sm-dox ul a span.sub-arrow { + border-color: transparent transparent transparent var(--page-foreground-color); + } + + .sm-dox ul a:hover span.sub-arrow { + border-color: transparent transparent transparent var(--menu-focus-foreground); + } +} + +.sm-dox ul { + background: var(--page-background-color); + box-shadow: var(--box-shadow); + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium) !important; + padding: var(--spacing-small); + animation: ease-out 150ms slideInMenu; +} + +@keyframes slideInMenu { + from { + opacity: 0; + transform: translate(0px, -2px); + } + + to { + opacity: 1; + transform: translate(0px, 0px); + } +} + +.sm-dox ul a { + color: var(--page-foreground-color) !important; + background: var(--page-background-color); + font-size: var(--navigation-font-size); +} + +.sm-dox>li>ul:after { + border-bottom-color: var(--page-background-color) !important; +} + +.sm-dox>li>ul:before { + border-bottom-color: var(--separator-color) !important; +} + +.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus { + font-size: var(--navigation-font-size) !important; + color: var(--menu-focus-foreground) !important; + text-shadow: none; + background-color: var(--menu-focus-background); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a { + text-shadow: none; + background: transparent; + background-image: none !important; + color: var(--header-foreground) !important; + font-weight: normal; + font-size: var(--navigation-font-size); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a:focus { + outline: auto; +} + +.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover { + text-shadow: none; + font-weight: normal; + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; + border-radius: var(--border-radius-small) !important; + font-size: var(--navigation-font-size); +} + +.tablist li.current { + border-radius: var(--border-radius-small); + background: var(--menu-selected-background); +} + +.tablist li { + margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small); +} + +.tablist a { + padding: 0 var(--spacing-large); +} + + +/* +Search box + */ + +#MSearchBox { + height: var(--searchbar-height); + background: var(--searchbar-background); + border-radius: var(--searchbar-border-radius); + border: 1px solid var(--separator-color); + overflow: hidden; + width: var(--searchbar-width); + position: relative; + box-shadow: none; + display: block; + margin-top: 0; +} + +.left #MSearchSelect { + left: 0; + user-select: none; + padding-left: 8px; +} + +.left #MSearchSelect[src$=".png"] { + padding-left: 0 +} + +.SelectionMark { + user-select: none; +} + +.tabs .left #MSearchSelect { + padding-left: 0; +} + +.tabs #MSearchBox { + position: absolute; + right: var(--spacing-medium); +} + +@media screen and (max-width: 767px) { + .tabs #MSearchBox { + position: relative; + right: 0; + margin-left: var(--spacing-medium); + margin-top: 0; + } +} + +#MSearchSelectWindow, #MSearchResultsWindow { + z-index: 9999; +} + +#MSearchBox.MSearchBoxActive { + border-color: var(--primary-color); + box-shadow: inset 0 0 0 1px var(--primary-color); +} + +#main-menu > li:last-child { + margin-right: 0; +} + +@media screen and (max-width: 767px) { + #main-menu > li:last-child { + height: 50px; + } +} + +#MSearchField { + font-size: var(--navigation-font-size); + height: calc(var(--searchbar-height) - 2px); + background: transparent; + width: calc(var(--searchbar-width) - 64px); +} + +.MSearchBoxActive #MSearchField { + color: var(--searchbar-foreground); +} + +#MSearchSelect { + top: calc(calc(var(--searchbar-height) / 2) - 11px); +} + +#MSearchBox span.left, #MSearchBox span.right { + background: none; + background-image: none; +} + +#MSearchBox span.right { + padding-top: calc(calc(var(--searchbar-height) / 2) - 12px); + position: absolute; + right: var(--spacing-small); +} + +.tabs #MSearchBox span.right { + top: calc(calc(var(--searchbar-height) / 2) - 12px); +} + +@keyframes slideInSearchResults { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } +} + +#MSearchResultsWindow { + left: auto !important; + right: var(--spacing-medium); + border-radius: var(--border-radius-large); + border: 1px solid var(--separator-color); + transform: translate(0, 20px); + box-shadow: var(--box-shadow); + animation: ease-out 280ms slideInSearchResults; + background: var(--page-background-color); +} + +iframe#MSearchResults { + margin: 4px; +} + +iframe { + color-scheme: normal; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) iframe#MSearchResults { + filter: invert() hue-rotate(180deg); + } +} + +html.dark-mode iframe#MSearchResults { + filter: invert() hue-rotate(180deg); +} + +#MSearchSelectWindow { + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + box-shadow: var(--box-shadow); + background: var(--page-background-color); + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); +} + +#MSearchSelectWindow a.SelectItem { + font-size: var(--navigation-font-size); + line-height: var(--content-line-height); + margin: 0 var(--spacing-small); + border-radius: var(--border-radius-small); + color: var(--page-foreground-color) !important; + font-weight: normal; +} + +#MSearchSelectWindow a.SelectItem:hover { + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; +} + +@media screen and (max-width: 767px) { + #MSearchBox { + margin-top: var(--spacing-medium); + margin-bottom: var(--spacing-medium); + width: calc(100vw - 30px); + } + + #main-menu > li:last-child { + float: none !important; + } + + #MSearchField { + width: calc(100vw - 110px); + } + + @keyframes slideInSearchResultsMobile { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } + } + + #MSearchResultsWindow { + left: var(--spacing-medium) !important; + right: var(--spacing-medium); + overflow: auto; + transform: translate(0, 20px); + animation: ease-out 280ms slideInSearchResultsMobile; + } + + /* + * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2 + */ +label.main-menu-btn ~ #searchBoxPos1 { + top: 3px !important; + right: 6px !important; + left: 45px; + display: flex; +} + +label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox { + margin-top: 0; + margin-bottom: 0; + flex-grow: 2; + float: left; +} +} + +/* +Tree view + */ + +#side-nav { + padding: 0 !important; + background: var(--side-nav-background); +} + +@media screen and (max-width: 767px) { + #side-nav { + display: none; + } + + #doc-content { + margin-left: 0 !important; + } +} + +#nav-tree { + background: transparent; +} + +#nav-tree .label { + font-size: var(--navigation-font-size); +} + +#nav-tree .item { + height: var(--tree-item-height); + line-height: var(--tree-item-height); +} + +#nav-sync { + bottom: 12px; + right: 12px; + top: auto !important; + user-select: none; +} + +#nav-tree .selected { + text-shadow: none; + background-image: none; + background-color: transparent; + position: relative; +} + +#nav-tree .selected::after { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + width: 4px; + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + background: var(--primary-color); +} + + +#nav-tree a { + color: var(--side-nav-foreground) !important; + font-weight: normal; +} + +#nav-tree a:focus { + outline-style: auto; +} + +#nav-tree .arrow { + opacity: var(--side-nav-arrow-opacity); +} + +.arrow { + color: inherit; + cursor: pointer; + font-size: 45%; + vertical-align: middle; + margin-right: 2px; + font-family: serif; + height: auto; + text-align: right; +} + +#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow { + opacity: var(--side-nav-arrow-hover-opacity); +} + +#nav-tree .selected a { + color: var(--primary-color) !important; + font-weight: bolder; + font-weight: 600; +} + +.ui-resizable-e { + background: var(--separator-color); + width: 1px; +} + +/* +Contents + */ + +div.header { + border-bottom: 1px solid var(--separator-color); + background-color: var(--page-background-color); + background-image: none; +} + +div.contents, div.header .title, div.header .summary { + max-width: var(--content-maxwidth); +} + +div.contents, div.header .title { + line-height: initial; + margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto; +} + +div.header .summary { + margin: var(--spacing-medium) auto 0 auto; +} + +div.headertitle { + padding: 0; +} + +div.header .title { + font-weight: 600; + font-size: 210%; + padding: var(--spacing-medium) var(--spacing-large); + word-break: break-word; +} + +div.header .summary { + width: auto; + display: block; + float: none; + padding: 0 var(--spacing-large); +} + +td.memSeparator { + border-color: var(--separator-color); +} + +span.mlabel { + background: var(--primary-color); + border: none; + padding: 4px 9px; + border-radius: 12px; + margin-right: var(--spacing-medium); +} + +span.mlabel:last-of-type { + margin-right: 2px; +} + +div.contents { + padding: 0 var(--spacing-large); +} + +div.contents p, div.contents li { + line-height: var(--content-line-height); +} + +div.contents div.dyncontent { + margin: var(--spacing-medium) 0; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) div.contents div.dyncontent img, + html:not(.light-mode) div.contents center img, + html:not(.light-mode) div.contents table img, + html:not(.light-mode) div.contents div.dyncontent iframe, + html:not(.light-mode) div.contents center iframe, + html:not(.light-mode) div.contents table iframe { + filter: hue-rotate(180deg) invert(); + } +} + +html.dark-mode div.contents div.dyncontent img, +html.dark-mode div.contents center img, +html.dark-mode div.contents table img, +html.dark-mode div.contents div.dyncontent iframe, +html.dark-mode div.contents center iframe, +html.dark-mode div.contents table iframe { + filter: hue-rotate(180deg) invert(); +} + +h2.groupheader { + border-bottom: 0px; + color: var(--page-foreground-color); + box-shadow: + 100px 0 var(--page-background-color), + -100px 0 var(--page-background-color), + 100px 0.75px var(--separator-color), + -100px 0.75px var(--separator-color), + 500px 0 var(--page-background-color), + -500px 0 var(--page-background-color), + 500px 0.75px var(--separator-color), + -500px 0.75px var(--separator-color), + 1500px 0 var(--page-background-color), + -1500px 0 var(--page-background-color), + 1500px 0.75px var(--separator-color), + -1500px 0.75px var(--separator-color), + 2000px 0 var(--page-background-color), + -2000px 0 var(--page-background-color), + 2000px 0.75px var(--separator-color), + -2000px 0.75px var(--separator-color); +} + +blockquote { + margin: 0 var(--spacing-medium) 0 var(--spacing-medium); + padding: var(--spacing-small) var(--spacing-large); + background: var(--blockquote-background); + color: var(--blockquote-foreground); + border-left: 0; + overflow: visible; + border-radius: var(--border-radius-medium); + overflow: visible; + position: relative; +} + +blockquote::before, blockquote::after { + font-weight: bold; + font-family: serif; + font-size: 360%; + opacity: .15; + position: absolute; +} + +blockquote::before { + content: "“"; + left: -10px; + top: 4px; +} + +blockquote::after { + content: "”"; + right: -8px; + bottom: -25px; +} + +blockquote p { + margin: var(--spacing-small) 0 var(--spacing-medium) 0; +} +.paramname { + font-weight: 600; + color: var(--primary-dark-color); +} + +.paramname > code { + border: 0; +} + +table.params .paramname { + font-weight: 600; + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + padding-right: var(--spacing-small); +} + +.glow { + text-shadow: 0 0 15px var(--primary-light-color) !important; +} + +.alphachar a { + color: var(--page-foreground-color); +} + +/* +Table of Contents + */ + +div.toc { + z-index: 10; + position: relative; + background-color: var(--toc-background); + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + box-shadow: var(--box-shadow); + padding: 0 var(--spacing-large); + margin: 0 0 var(--spacing-medium) var(--spacing-medium); +} + +div.toc h3 { + color: var(--toc-foreground); + font-size: var(--navigation-font-size); + margin: var(--spacing-large) 0; +} + +div.toc li { + font-size: var(--navigation-font-size); + padding: 0; + background: none; +} + +div.toc li:before { + content: '↓'; + font-weight: 800; + font-family: var(--font-family); + margin-right: var(--spacing-small); + color: var(--toc-foreground); + opacity: .4; +} + +div.toc ul li.level1 { + margin: 0; +} + +div.toc ul li.level2, div.toc ul li.level3 { + margin-top: 0; +} + + +@media screen and (max-width: 767px) { + div.toc { + float: none; + width: auto; + margin: 0 0 var(--spacing-medium) 0; + } +} + +/* +Code & Fragments + */ + +code, div.fragment, pre.fragment { + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + overflow: hidden; +} + +code { + display: inline; + background: var(--code-background); + color: var(--code-foreground); + padding: 2px 6px; + word-break: break-word; +} + +div.fragment, pre.fragment { + margin: var(--spacing-medium) 0; + padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); + background: var(--fragment-background); + color: var(--fragment-foreground); + overflow-x: auto; +} + +@media screen and (max-width: 767px) { + div.fragment, pre.fragment { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: 0; + } + + .contents > div.fragment, + .textblock > div.fragment, + .textblock > pre.fragment, + .contents > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + border-radius: 0; + border-left: 0; + } + + .textblock li > .fragment, + .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + } + + .memdoc li > .fragment, + .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + } + + .textblock ul, .memdoc ul { + overflow: initial; + } + + .memdoc > div.fragment, + .memdoc > pre.fragment, + dl dd > div.fragment, + dl dd pre.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, + dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, + dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + border-radius: 0; + border-left: 0; + } +} + +code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size) !important; +} + +div.line:after { + margin-right: var(--spacing-medium); +} + +div.fragment .line, pre.fragment { + white-space: pre; + word-wrap: initial; + line-height: var(--fragment-lineheight); +} + +div.fragment span.keyword { + color: var(--fragment-keyword); +} + +div.fragment span.keywordtype { + color: var(--fragment-keywordtype); +} + +div.fragment span.keywordflow { + color: var(--fragment-keywordflow); +} + +div.fragment span.stringliteral { + color: var(--fragment-token) +} + +div.fragment span.comment { + color: var(--fragment-comment); +} + +div.fragment a.code { + color: var(--fragment-link) !important; +} + +div.fragment span.preprocessor { + color: var(--fragment-preprocessor); +} + +div.fragment span.lineno { + display: inline-block; + width: 27px; + border-right: none; + background: var(--fragment-linenumber-background); + color: var(--fragment-linenumber-color); +} + +div.fragment span.lineno a { + background: none; + color: var(--fragment-link) !important; +} + +div.fragment .line:first-child .lineno { + box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); +} + +/* +dl warning, attention, note, deprecated, bug, ... + */ + +dl.bug dt a, dl.deprecated dt a, dl.todo dt a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.todo, dl.remark { + padding: var(--spacing-medium); + margin: var(--spacing-medium) 0; + color: var(--page-background-color); + overflow: hidden; + margin-left: 0; + border-radius: var(--border-radius-small); +} + +dl.section dd { + margin-bottom: 2px; +} + +dl.warning, dl.attention { + background: var(--warning-color); + border-left: 8px solid var(--warning-color-dark); + color: var(--warning-color-darker); +} + +dl.warning dt, dl.attention dt { + color: var(--warning-color-dark); +} + +dl.note, dl.remark { + background: var(--note-color); + border-left: 8px solid var(--note-color-dark); + color: var(--note-color-darker); +} + +dl.note dt, dl.remark dt { + color: var(--note-color-dark); +} + +dl.todo { + background: var(--todo-color); + border-left: 8px solid var(--todo-color-dark); + color: var(--todo-color-darker); +} + +dl.todo dt { + color: var(--todo-color-dark); +} + +dl.bug dt a { + color: var(--todo-color-dark) !important; +} + +dl.bug { + background: var(--bug-color); + border-left: 8px solid var(--bug-color-dark); + color: var(--bug-color-darker); +} + +dl.bug dt a { + color: var(--bug-color-dark) !important; +} + +dl.deprecated { + background: var(--deprecated-color); + border-left: 8px solid var(--deprecated-color-dark); + color: var(--deprecated-color-darker); +} + +dl.deprecated dt a { + color: var(--deprecated-color-dark) !important; +} + +dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { + margin-inline-start: 0px; +} + +dl.invariant, dl.pre { + background: var(--invariant-color); + border-left: 8px solid var(--invariant-color-dark); + color: var(--invariant-color-darker); +} + +dl.invariant dt, dl.pre dt { + color: var(--invariant-color-dark); +} + +/* +memitem + */ + +div.memdoc, div.memproto, h2.memtitle { + box-shadow: none; + background-image: none; + border: none; +} + +div.memdoc { + padding: 0 var(--spacing-medium); + background: var(--page-background-color); +} + +h2.memtitle, div.memitem { + border: 1px solid var(--separator-color); + box-shadow: var(--box-shadow); +} + +h2.memtitle { + box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); +} + +div.memitem { + transition: none; +} + +div.memproto, h2.memtitle { + background: var(--fragment-background); + text-shadow: none; +} + +h2.memtitle { + font-weight: 500; + font-size: var(--memtitle-font-size); + font-family: var(--font-family-monospace); + border-bottom: none; + border-top-left-radius: var(--border-radius-medium); + border-top-right-radius: var(--border-radius-medium); + word-break: break-all; + position: relative; +} + +h2.memtitle:after { + content: ""; + display: block; + background: var(--fragment-background); + height: var(--spacing-medium); + bottom: calc(0px - var(--spacing-medium)); + left: 0; + right: -14px; + position: absolute; + border-top-right-radius: var(--border-radius-medium); +} + +h2.memtitle > span.permalink { + font-size: inherit; +} + +h2.memtitle > span.permalink > a { + text-decoration: none; + padding-left: 3px; + margin-right: -4px; + user-select: none; + display: inline-block; + margin-top: -6px; +} + +h2.memtitle > span.permalink > a:hover { + color: var(--primary-dark-color) !important; +} + +a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { + border-color: var(--primary-light-color); +} + +div.memitem { + border-top-right-radius: var(--border-radius-medium); + border-bottom-right-radius: var(--border-radius-medium); + border-bottom-left-radius: var(--border-radius-medium); + overflow: hidden; + display: block !important; +} + +div.memdoc { + border-radius: 0; +} + +div.memproto { + border-radius: 0 var(--border-radius-small) 0 0; + overflow: auto; + border-bottom: 1px solid var(--separator-color); + padding: var(--spacing-medium); + margin-bottom: -1px; +} + +div.memtitle { + border-top-right-radius: var(--border-radius-medium); + border-top-left-radius: var(--border-radius-medium); +} + +div.memproto table.memname { + font-family: var(--font-family-monospace); + color: var(--page-foreground-color); + font-size: var(--memname-font-size); +} + +div.memproto div.memtemplate { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--memname-font-size); + margin-left: 2px; +} + +table.mlabels, table.mlabels > tbody { + display: block; +} + +td.mlabels-left { + width: auto; +} + +td.mlabels-right { + margin-top: 3px; + position: sticky; + left: 0; +} + +table.mlabels > tbody > tr:first-child { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} + +.memname, .memitem span.mlabels { + margin: 0 +} + +/* +reflist + */ + +dl.reflist { + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-medium); + border: 1px solid var(--separator-color); + overflow: hidden; + padding: 0; +} + + +dl.reflist dt, dl.reflist dd { + box-shadow: none; + text-shadow: none; + background-image: none; + border: none; + padding: 12px; +} + + +dl.reflist dt { + font-weight: 500; + border-radius: 0; + background: var(--code-background); + border-bottom: 1px solid var(--separator-color); + color: var(--page-foreground-color) +} + + +dl.reflist dd { + background: none; +} + +/* +Table + */ + +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) { + display: inline-block; + max-width: 100%; +} + +.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); +} + +table.markdownTable, table.fieldtable { + border: none; + margin: var(--spacing-medium) 0; + box-shadow: 0 0 0 1px var(--separator-color); + border-radius: var(--border-radius-small); +} + +table.fieldtable { + width: 100%; +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background: var(--tablehead-background); + color: var(--tablehead-foreground); + font-weight: 600; + font-size: var(--page-font-size); +} + +th.markdownTableHeadLeft:first-child, th.markdownTableHeadRight:first-child, th.markdownTableHeadCenter:first-child, th.markdownTableHeadNone:first-child { + border-top-left-radius: var(--border-radius-small); +} + +th.markdownTableHeadLeft:last-child, th.markdownTableHeadRight:last-child, th.markdownTableHeadCenter:last-child, th.markdownTableHeadNone:last-child { + border-top-right-radius: var(--border-radius-small); +} + +table.markdownTable td, table.markdownTable th, table.fieldtable dt { + border: none; + border-right: 1px solid var(--separator-color); + padding: var(--spacing-small) var(--spacing-medium); +} + +table.markdownTable td:last-child, table.markdownTable th:last-child, table.fieldtable dt:last-child { + border: none; +} + +table.markdownTable tr, table.markdownTable tr { + border-bottom: 1px solid var(--separator-color); +} + +table.markdownTable tr:last-child, table.markdownTable tr:last-child { + border-bottom: none; +} + +table.fieldtable th { + font-size: var(--page-font-size); + font-weight: 600; + background-image: none; + background-color: var(--tablehead-background); + color: var(--tablehead-foreground); + border-bottom: 1px solid var(--separator-color); +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + border-bottom: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid var(--separator-color); +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: var(--primary-light-color); + box-shadow: 0 0 15px var(--primary-light-color); +} + +table.memberdecls { + display: block; +} + +table.memberdecls tr[class^='memitem'] { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); +} + +table.memberdecls tr[class^='memitem'] .memTemplParams { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + color: var(--primary-dark-color); +} + +table.memberdecls .memItemLeft, +table.memberdecls .memItemRight, +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight, +table.memberdecls .memTemplParams { + transition: none; + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + background-color: var(--fragment-background); +} + +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight { + padding-top: 2px; +} + +table.memberdecls .memTemplParams { + border-bottom: 0; + border-left: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + padding-bottom: 0; +} + +table.memberdecls .memTemplItemLeft { + border-radius: 0 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + border-top: 0; +} + +table.memberdecls .memTemplItemRight { + border-radius: 0 0 var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + border-top: 0; +} + +table.memberdecls .memItemLeft { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + padding-left: var(--spacing-medium); + padding-right: 0; +} + +table.memberdecls .memItemRight { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-right: var(--spacing-medium); + padding-left: 0; + +} + +table.memberdecls .mdescLeft, table.memberdecls .mdescRight { + background: none; + color: var(--page-foreground-color); + padding: var(--spacing-small) 0; +} + +table.memberdecls .memSeparator { + background: var(--page-background-color); + height: var(--spacing-large); + border: 0; + transition: none; +} + +table.memberdecls .groupheader { + margin-bottom: var(--spacing-large); +} + +table.memberdecls .inherit_header td { + padding: 0 0 var(--spacing-medium) 0; + text-indent: -12px; + line-height: 1.5em; + color: var(--page-secondary-foreground-color); +} + +@media screen and (max-width: 767px) { + + table.memberdecls .memItemLeft, + table.memberdecls .memItemRight, + table.memberdecls .mdescLeft, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemLeft, + table.memberdecls .memTemplItemRight, + table.memberdecls .memTemplParams { + display: block; + text-align: left; + padding-left: var(--spacing-large); + margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); + border-right: none; + border-left: none; + border-radius: 0; + } + + table.memberdecls .memItemLeft, + table.memberdecls .mdescLeft, + table.memberdecls .memTemplItemLeft { + border-bottom: 0; + padding-bottom: 0; + } + + table.memberdecls .memTemplItemLeft { + padding-top: 0; + } + + table.memberdecls .mdescLeft { + margin-top: calc(0px - var(--page-font-size)); + } + + table.memberdecls .memItemRight, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemRight { + border-top: 0; + padding-top: 0; + padding-right: var(--spacing-large); + overflow-x: auto; + } + + table.memberdecls tr[class^='memitem']:not(.inherit) { + display: block; + width: calc(100vw - 2 * var(--spacing-large)); + } + + table.memberdecls .mdescRight { + color: var(--page-foreground-color); + } + + table.memberdecls tr.inherit { + visibility: hidden; + } + + table.memberdecls tr[style="display: table-row;"] { + display: block !important; + visibility: visible; + width: calc(100vw - 2 * var(--spacing-large)); + animation: fade .5s; + } + + @keyframes fade { + 0% { + opacity: 0; + max-height: 0; + } + + 100% { + opacity: 1; + max-height: 200px; + } + } +} + + +/* +Horizontal Rule + */ + +hr { + margin-top: var(--spacing-large); + margin-bottom: var(--spacing-large); + height: 1px; + background-color: var(--separator-color); + border: 0; +} + +.contents hr { + box-shadow: 100px 0 0 var(--separator-color), + -100px 0 0 var(--separator-color), + 500px 0 0 var(--separator-color), + -500px 0 0 var(--separator-color), + 1500px 0 0 var(--separator-color), + -1500px 0 0 var(--separator-color), + 2000px 0 0 var(--separator-color), + -2000px 0 0 var(--separator-color); +} + +.contents img, .contents .center, .contents center, .contents div.image object { + max-width: 100%; + overflow: auto; +} + +@media screen and (max-width: 767px) { + .contents .dyncontent > .center, .contents > center { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); + } +} + +/* +Directories + */ +div.directory { + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + width: auto; +} + +table.directory { + font-family: var(--font-family); + font-size: var(--page-font-size); + font-weight: normal; + width: 100%; +} + +table.directory td.entry { + padding: var(--spacing-small); +} + +table.directory td.desc { + min-width: 250px; +} + +table.directory tr.even { + background-color: var(--odd-color); +} + +.icona { + width: auto; + height: auto; + margin: 0 var(--spacing-small); +} + +.icon { + background: var(--primary-color); + width: 18px; + height: 18px; + line-height: 18px; +} + +.iconfopen, .icondoc, .iconfclosed { + background-position: center; + margin-bottom: 0; +} + +.icondoc { + filter: saturate(0.2); +} + +@media screen and (max-width: 767px) { + div.directory { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed { + filter: hue-rotate(180deg) invert(); + } +} + +html.dark-mode .iconfopen, html.dark-mode .iconfclosed { + filter: hue-rotate(180deg) invert(); +} + +/* +Class list + */ + +.classindex dl.odd { + background: var(--odd-color); + border-radius: var(--border-radius-small); +} + +/* +Class Index Doxygen 1.8 + */ + +table.classindex { + margin-left: 0; + margin-right: 0; + width: 100%; +} + +table.classindex table div.ah { + background-image: none; + background-color: initial; + border-color: var(--separator-color); + color: var(--page-foreground-color); + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-large); + padding: var(--spacing-small); +} + +div.qindex { + background-color: var(--odd-color); + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + padding: var(--spacing-small) 0; +} + +/* +Footer and nav-path + */ + +#nav-path { + width: 100%; +} + +#nav-path ul { + background-image: none; + background: var(--page-background-color); + border: none; + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + border-bottom: 0; + box-shadow: 0 0.75px 0 var(--separator-color); + font-size: var(--navigation-font-size); +} + +img.footer { + width: 60px; +} + +.navpath li.footer { + color: var(--page-secondary-foreground-color); +} + +address.footer { + color: var(--page-secondary-foreground-color); + margin-bottom: var(--spacing-large); +} + +#nav-path li.navelem { + background-image: none; + display: flex; + align-items: center; +} + +.navpath li.navelem a { + text-shadow: none; + display: inline-block; + color: var(--primary-color) !important; +} + +.navpath li.navelem b { + color: var(--primary-dark-color); + font-weight: 500; +} + +li.navelem { + padding: 0; + margin-left: -8px; +} + +li.navelem:first-child { + margin-left: var(--spacing-large); +} + +li.navelem:first-child:before { + display: none; +} + +#nav-path li.navelem:after { + content: ''; + border: 5px solid var(--page-background-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(4.2); + z-index: 10; + margin-left: 6px; +} + +#nav-path li.navelem:before { + content: ''; + border: 5px solid var(--separator-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(3.2); + margin-right: var(--spacing-small); +} + +.navpath li.navelem a:hover { + color: var(--primary-color); +} + +/* +Scrollbars for Webkit + */ + +#nav-tree::-webkit-scrollbar, +div.fragment::-webkit-scrollbar, +pre.fragment::-webkit-scrollbar, +div.memproto::-webkit-scrollbar, +.contents center::-webkit-scrollbar, +.contents .center::-webkit-scrollbar, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname)::-webkit-scrollbar { + width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); +} + +#nav-tree::-webkit-scrollbar-thumb, +div.fragment::-webkit-scrollbar-thumb, +pre.fragment::-webkit-scrollbar-thumb, +div.memproto::-webkit-scrollbar-thumb, +.contents center::-webkit-scrollbar-thumb, +.contents .center::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname)::-webkit-scrollbar-thumb { + background-color: transparent; + border: var(--webkit-scrollbar-padding) solid transparent; + border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + background-clip: padding-box; +} + +#nav-tree:hover::-webkit-scrollbar-thumb, +div.fragment:hover::-webkit-scrollbar-thumb, +pre.fragment:hover::-webkit-scrollbar-thumb, +div.memproto:hover::-webkit-scrollbar-thumb, +.contents center:hover::-webkit-scrollbar-thumb, +.contents .center:hover::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):hover::-webkit-scrollbar-thumb { + background-color: var(--webkit-scrollbar-color); +} + +#nav-tree::-webkit-scrollbar-track, +div.fragment::-webkit-scrollbar-track, +pre.fragment::-webkit-scrollbar-track, +div.memproto::-webkit-scrollbar-track, +.contents center::-webkit-scrollbar-track, +.contents .center::-webkit-scrollbar-track, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname)::-webkit-scrollbar-track { + background: transparent; +} + +#nav-tree::-webkit-scrollbar-corner { + background-color: var(--side-nav-background); +} + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) { + overflow-x: auto; + overflow-x: overlay; +} + +#nav-tree { + overflow-x: auto; + overflow-y: auto; + overflow-y: overlay; +} + +/* +Scrollbars for Firefox + */ + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) { + scrollbar-width: thin; +} + +/* +Optional Dark mode toggle button + */ + +doxygen-awesome-dark-mode-toggle { + display: inline-block; + margin: 0 0 0 var(--spacing-small); + padding: 0; + width: var(--searchbar-height); + height: var(--searchbar-height); + background: none; + border: none; + border-radius: var(--searchbar-height); + vertical-align: middle; + text-align: center; + line-height: var(--searchbar-height); + font-size: 22px; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + cursor: pointer; +} + +doxygen-awesome-dark-mode-toggle > svg { + transition: transform .1s ease-in-out; +} + +doxygen-awesome-dark-mode-toggle:active > svg { + transform: scale(.5); +} + +doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.03); +} + +html.dark-mode doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.18); +} + +/* +Optional fragment copy button + */ +.doxygen-awesome-fragment-wrapper { + position: relative; +} + +doxygen-awesome-fragment-copy-button { + opacity: 0; + background: var(--fragment-background); + width: 28px; + height: 28px; + position: absolute; + right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + border: 1px solid var(--fragment-foreground); + cursor: pointer; + border-radius: var(--border-radius-small); + display: flex; + justify-content: center; + align-items: center; +} + +.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { + opacity: .28; +} + +doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { + opacity: 1 !important; +} + +doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { + transform: scale(.91); +} + +doxygen-awesome-fragment-copy-button svg { + fill: var(--fragment-foreground); + width: 18px; + height: 18px; +} + +doxygen-awesome-fragment-copy-button.success svg { + fill: rgb(14, 168, 14); +} + +doxygen-awesome-fragment-copy-button.success { + border-color: rgb(14, 168, 14); +} + +@media screen and (max-width: 767px) { + .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { + right: 0; + } +} + +/* +Optional paragraph link button + */ + +a.anchorlink { + font-size: 90%; + margin-left: var(--spacing-small); + color: var(--page-foreground-color) !important; + text-decoration: none; + opacity: .15; + display: none; + transition: opacity .1s ease-in-out, color .1s ease-in-out; +} + +a.anchorlink svg { + fill: var(--page-foreground-color); +} + +h3 a.anchorlink svg, h4 a.anchorlink svg { + margin-bottom: -3px; + margin-top: -4px; +} + +a.anchorlink:hover { + opacity: .45; +} + +h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { + display: inline-block; +} diff --git a/triscv/docs/doxygen.conf b/triscv/docs/doxygen.conf new file mode 100644 index 0000000..3cb6ca3 --- /dev/null +++ b/triscv/docs/doxygen.conf @@ -0,0 +1,2745 @@ +# Doxyfile 1.9.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables: +# doxygen -x_noenv [configFile] + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = kmi + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = docs/output + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# numer of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = "global=\warning Global variable.^^" \ + "sideeffects=\warning Expression is evaluated multiple times.^^" + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = arch \ + common \ + include \ + lib \ + docs \ + README.md + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = arch/riscv64/conf/init.c + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = YES + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +# Personal note: riscv32 is a symlink and as such should be ignored when +# EXCLUDE_SYMLINKS = YES, but doesn't seem to be working atm. + +EXCLUDE_PATTERNS = */gen/* */riscv32/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = docs/doxygen-kmi.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 1 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using JavaScript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: +# https://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. +# +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = YES + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = DEBUG \ + __GNUC__ \ + riscv64 \ + riscv32 \ + ASSERT + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: YES. + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a +# graph for each documented class showing the direct and indirect inheritance +# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, +# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set +# to TEXT the direct and indirect inheritance relations will be shown as texts / +# links. +# Possible values are: NO, YES, TEXT and GRAPH. +# The default value is: YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. See also the chapter Grouping +# in the manual. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag UML_LOOK is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = YES + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, +# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, +# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate +# files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. +# The default value is: YES. + +DOT_CLEANUP = YES diff --git a/triscv/include/triscv/common.h b/triscv/include/triscv/common.h new file mode 100644 index 0000000..865f6e5 --- /dev/null +++ b/triscv/include/triscv/common.h @@ -0,0 +1,28 @@ +#ifndef TRISCV_COMMON_H +#define TRISCV_COMMON_H + +#include <tri.h> +#include <stdint.h> + +typedef uint64_t vm_t; +typedef uint64_t pm_t; + +/* forward declarations */ +struct cpu; +struct tmb; +struct mmu; +struct mem; +struct uart; + +enum stat { + OK = 0, + ERR_FULL, + ERR_EXISTS, + ERR_OOB, +}; + +typedef enum stat stat_t; + +const char *err_str(stat_t s); + +#endif diff --git a/triscv/include/triscv/cpu.h b/triscv/include/triscv/cpu.h new file mode 100644 index 0000000..05f8b78 --- /dev/null +++ b/triscv/include/triscv/cpu.h @@ -0,0 +1,14 @@ +#ifndef TRISCV_CPU_H +#define TRISCV_CPU_H + +#include <triscv/common.h> + +struct cpu *cpu_create(struct mmu *mmu, struct tmb *tmb); +void cpu_reset(struct cpu *cpu); +void cpu_destroy(struct cpu *cpu); + +/** @todo how should external interrupts be handled? add some list of devices to + * update after each cycle? */ +void cpu_run(struct cpu *cpu, vm_t start); + +#endif diff --git a/triscv/include/triscv/csr.h b/triscv/include/triscv/csr.h new file mode 100644 index 0000000..a805702 --- /dev/null +++ b/triscv/include/triscv/csr.h @@ -0,0 +1,8 @@ +#ifndef TRISCV_CSR_H +#define TRISCV_CSR_H + +/* first trit is sleep mode, R/W, second trit shutdown, R/W */ +#define CSR_MPOWER 0 +#define RW_MPOWER 0b1111 + +#endif diff --git a/triscv/include/triscv/mem.h b/triscv/include/triscv/mem.h new file mode 100644 index 0000000..81b5d11 --- /dev/null +++ b/triscv/include/triscv/mem.h @@ -0,0 +1,13 @@ +#ifndef TRISCV_MEM_H +#define TRISCV_MEM_H + +#include <triscv/common.h> +#include <triscv/mmu.h> + +struct mem *mem_create(size_t size); +void mem_destroy(struct mem *mem); +void mem_init(struct mem *mem, const void *buf, size_t len); + +struct dev mem_dev(struct mem *mem); + +#endif diff --git a/triscv/include/triscv/mmu.h b/triscv/include/triscv/mmu.h new file mode 100644 index 0000000..c885814 --- /dev/null +++ b/triscv/include/triscv/mmu.h @@ -0,0 +1,40 @@ +#ifndef TRISCV_MMU_H +#define TRISCV_MMU_H + +#include <triscv/common.h> +#include <triscv/cpu.h> + +typedef void (*dev_write1_t)(struct cpu *cpu, void *dev, pm_t addr, tri_t t); +typedef void (*dev_write3_t)(struct cpu *cpu, void *dev, pm_t addr, tri_t t); +typedef tri_t (*dev_read1_t)(struct cpu *cpu, void *dev, pm_t addr); +typedef tri_t (*dev_read3_t)(struct cpu *cpu, void *dev, pm_t addr); + +/* only character devices for now */ +struct dev { + void *dev; + size_t size; + dev_write1_t write1; + dev_write3_t write3; + dev_read1_t read1; + dev_read3_t read3; +}; + +struct mmu *mmu_create(); +void mmu_destroy(struct mmu *mmu); + +/* not thread safe */ +stat_t mmu_map_dev(struct mmu *mmu, pm_t start, struct dev dev); + +void mmu_enable(struct mmu *mmu); +void mmu_disable(struct mmu *mmu); + +bool mmu_valid(struct mmu *mmu, vm_t addr); + +/* mmu can raise signals, so we pass cpu along */ +tri_t mmu_read1(struct cpu *cpu, struct mmu *mmu, vm_t addr); +tri_t mmu_read3(struct cpu *cpu, struct mmu *mmu, vm_t addr); + +void mmu_write1(struct cpu *cpu, struct mmu *mmu, vm_t addr, tri_t t); +void mmu_write3(struct cpu *cpu, struct mmu *mmu, vm_t addr, tri_t t); + +#endif diff --git a/triscv/include/triscv/tmb.h b/triscv/include/triscv/tmb.h new file mode 100644 index 0000000..0c8a5b6 --- /dev/null +++ b/triscv/include/triscv/tmb.h @@ -0,0 +1,18 @@ +#ifndef TRISCV_TMB_H +#define TRISCV_TMB_H + +#include <triscv/common.h> +#include <triscv/cpu.h> + +struct tmb *tmb_create(); +void tmb_destroy(struct tmb *tmb); + +size_t tmb_size(struct cpu *cpu); + +void tmb_clear(struct cpu *cpu); +void tmb_cancel(struct cpu *cpu); +void tmb_store1(struct cpu *cpu, vm_t addr, tri_t t); +void tmb_store3(struct cpu *cpu, vm_t addr, tri_t t); +bool tmb_commit(struct cpu *cpu); + +#endif diff --git a/triscv/include/triscv/uart.h b/triscv/include/triscv/uart.h new file mode 100644 index 0000000..531da1d --- /dev/null +++ b/triscv/include/triscv/uart.h @@ -0,0 +1,12 @@ +#ifndef TRISCV_UART_H +#define TRISCV_UART_H + +#include <triscv/common.h> +#include <triscv/mmu.h> + +struct uart *uart_create(); +void uart_destroy(struct uart *uart); + +struct dev uart_dev(struct uart *uart); + +#endif diff --git a/triscv/scripts/gen-deps b/triscv/scripts/gen-deps new file mode 100755 index 0000000..f45707c --- /dev/null +++ b/triscv/scripts/gen-deps @@ -0,0 +1,37 @@ +#!/bin/sh + +PREFIX= +COMPILE=COMPILE +LINT=LINT +BUILD=build/ + +while getopts "p:c:b:l:" opt; do + case "$opt" in + p) PREFIX="$OPTARG"_;; + c) COMPILE="$OPTARG";; + l) LINT="$OPTARG";; + b) BUILD=build/"$OPTARG";; + *) echo "unrecognised option -$OPTARG" >&2; exit 1;; + esac +done + +shift $((OPTIND - 1)) + +# create all subdirectories +mkdir -p $(echo "${@}" | tr ' ' '\n' | sed "s|[^/]*$||;s|^|${BUILD}/|" | uniq) + +for s in ${@} +do + obj="${BUILD}/${s%.*}.o" + lint="${obj}.l" + dep="${obj}.d" + + echo "${PREFIX}OBJS += ${obj}" >> deps.mk + echo "${PREFIX}LINTS += ${lint}" >> deps.mk + echo "${dep}:" >> deps.mk + echo "-include ${dep}" >> deps.mk + echo "${obj}: ${s}" >> deps.mk + echo " \$(${COMPILE}) -c ${s} -o ${obj}" >> deps.mk + echo "${lint}: ${s}" >> deps.mk + echo " \$(${LINT}) -c ${s} -o /dev/null" >> deps.mk +done diff --git a/triscv/scripts/license b/triscv/scripts/license new file mode 100755 index 0000000..53bd5da --- /dev/null +++ b/triscv/scripts/license @@ -0,0 +1,16 @@ +#!/bin/sh + +SPDX="/* SPDX-License-Identifier: copyleft-next-0.3.1 */" + +for f in "$@" +do + if [ "$(head -1 "$f")" != "${SPDX}" ] + then + sed -i "1i${SPDX}\n" "$f" + fi + + if ! grep 'Copyright' "$f" > /dev/null + then + echo "Missing copyright info in $f" + fi +done diff --git a/triscv/scripts/makefile b/triscv/scripts/makefile new file mode 100644 index 0000000..50510f8 --- /dev/null +++ b/triscv/scripts/makefile @@ -0,0 +1,71 @@ +# this could be done better +RELEASE ?= 0 +OPTFLAGS != [ "$(RELEASE)" != "0" ] \ + && echo "-O3 -flto" \ + || echo "-O0" + +DEBUG ?= 1 +DEBUGFLAGS != [ "$(DEBUG)" != "0" ] \ + && echo "-DDEBUG=1" \ + || echo "-DNDEBUG=1" + +ASSERT ?= 1 +ASSERTFLAGS != [ "$(ASSERT)" != "0" ] \ + && echo "-DASSERT=1" \ + || echo + +DEPFLAGS = -MT $@ -MMD -MP -MF $@.d +LINTFLAGS = -fsyntax-only +PREPROCESS = -E + +LLVM ?= 0 +BUILD = build + +all: triscv + +# default values, overwrite if/when needed +CROSS_COMPILE = + +OBJCOPY != [ "$(LLVM)" != "0" ] \ + && echo llvm-objcopy \ + || echo $(CROSS_COMPILE)objcopy + +COMPILER != [ "$(LLVM)" != "0" ] \ + && echo clang --target="$(CROSS_COMPILE)" \ + || echo $(CROSS_COMPILE)gcc + + +OBFLAGS = -std=c17 -g +WARNFLAGS = -Wall -Wextra + +COMPILE_FLAGS = $(CFLAGS) $(WARNFLAGS) $(OPTFLAGS) $(OBFLAGS) $(ASSERTFLAGS) \ + $(DEBUGFLAGS) + +INCLUDE_FLAGS = -I include -I ../core -I deps/utf9 + +# This makes sure .bss is loaded into the binary +OBJCOPY_FLAGS ?= -Obinary -R .garbage \ + --set-section-flags .bss=alloc,load,contents + +COMPILE = $(COMPILER) \ + $(COMPILE_FLAGS) $(DEPFLAGS) $(INCLUDE_FLAGS) + +LINT = $(COMPILER) \ + $(COMPILE_FLAGS) $(LINTFLAGS) $(INCLUDE_FLAGS) + +UBSAN ?= 0 +TRISCV_FLAGS != [ "$(UBSAN)" != "0" ] \ + && echo -fsanitize=undefined \ + || echo + +COMPILE_TRISCV = $(COMPILE) $(TRISCV_FLAGS) + +-include deps.mk + +triscv: $(TRISCV_OBJS) + $(COMPILE_TRISCV) $(TRISCV_OBJS) -o $@ + + +# might lint some common things twice +.PHONY: +lint: $(TRISCV_LINTS) diff --git a/triscv/scripts/warn-undocumented b/triscv/scripts/warn-undocumented new file mode 100755 index 0000000..aa7d0f7 --- /dev/null +++ b/triscv/scripts/warn-undocumented @@ -0,0 +1,7 @@ +#!/bin/sh +# look through all files for either @file or \file +for file in $@ +do + grep -c '[@\]file' "$file" |\ + awk -F':' "\$1 == 0 {print \"Undocumented file: $file\"}" +done diff --git a/triscv/src/common.c b/triscv/src/common.c new file mode 100644 index 0000000..e73d76e --- /dev/null +++ b/triscv/src/common.c @@ -0,0 +1,13 @@ +#include <triscv/common.h> + +static const char *err_strs[] = { + [OK] = "OK", + [ERR_FULL] = "full", + [ERR_EXISTS] = "exists", + [ERR_OOB] = "out of bounds" +}; + +const char *err_str(stat_t s) +{ + return err_strs[s]; +} diff --git a/triscv/src/cpu.c b/triscv/src/cpu.c new file mode 100644 index 0000000..54e892c --- /dev/null +++ b/triscv/src/cpu.c @@ -0,0 +1,281 @@ +#include <triscv/cpu.h> +#include <triscv/mmu.h> +#include <triscv/csr.h> + +struct cpu { + vm_t pc; + struct mmu *mmu; + struct tmb *tmb; + + enum mode { + MMODE = 0, SMODE = 1, UMODE = 2 + } mode; + + /* we only have 81 registers, but 3^4 can be encoded in 2^8, and this + * way we can directly use the BCT as an index, speeding things up a bit + * + * csrs are too big, probably not worth it */ + tri_t gpr[256]; + + /* 6561 M-mode, 6561 S-mode, 6561 U-mode, maybe? so ixxxxxxxx is + * reserved for M, 0xxxxxx for S, 1xxxx... for U. Just have to map them + * to decimal/binary in a somewhat sensible manner */ + /* value */ + tri_t csr[19683]; + /* write trit, all csrs are readable? */ + tri_t csrw[19683]; +}; + +static size_t get_csr_num(tri_t csr) +{ + return tri_to(csr) + 9841; +} + +static tri_t get_csr(struct cpu *cpu, size_t i) +{ + size_t max_csr = cpu->mode * 6561; + if (i < max_csr) + return 0; /* illegal access, should maybe also raise an interrupt? */ + + return cpu->csr[i]; +} + +static void set_csr(struct cpu *cpu, size_t i, tri_t t) +{ + size_t max_csr = cpu->mode * 6561; + if (i < max_csr) + return; + + tri_t csr = cpu->csr[i]; + tri_t w = cpu->csrw[i]; + + /* clear out trits we don't have write permission for*/ + t &= w; + csr &= ~w; + csr |= t; + + cpu->csr[i] = csr; +} + +static tri_t get_gpr(struct cpu *cpu, tri_t i) +{ + /* could also add in check that i is in range, though that would + * probably add a fair bit of overhead */ + if (i == 0) + return 0; + + return cpu->gpr[i]; +} + +static void set_gpr(struct cpu *cpu, tri_t i, tri_t t) +{ + if (i == 0) + return; + + cpu->gpr[i] = t; +} + +static void csr_init(struct cpu *cpu) +{ + cpu->csr[CSR_MPOWER] = 0; + cpu->csrw[CSR_MPOWER] = RW_MPOWER; +} + +struct cpu *cpu_create(struct mmu *mmu, struct tmb *tmb) +{ + struct cpu *cpu = calloc(1, sizeof(struct cpu)); + cpu->mmu = mmu; + cpu->tmb = tmb; + csr_init(cpu); + return cpu; +} + +void cpu_destroy(struct cpu *cpu) +{ + free(cpu); +} + +static tri_t get_rd(tri_t i) +{ + i = tri_sr(i, 5); + return tri_mask(i, 4); +} + +static tri_t get_rs1(tri_t i) +{ + i = tri_sr(i, 14); + return tri_mask(i, 4); +} + +static tri_t get_rs2(tri_t i) +{ + i = tri_sr(i, 18); + return tri_mask(i, 4); +} + +static tri_t get_imm4(tri_t i) +{ + i = tri_sr(i, 5); + return tri_mask(i, 4); +} + +static tri_t get_imm5(tri_t i) +{ + i = tri_sr(i, 22); + return tri_mask(i, 5); +} + +static tri_t get_imm9(tri_t i) +{ + i = tri_sr(i, 18); + return tri_mask(i, 9); +} + +static tri_t get_imm18(tri_t i) +{ + i = tri_sr(i, 9); + return tri_mask(i, 18); +} + +static tri_t get_fn0(tri_t i) +{ + i = tri_sr(i, 9); + return tri_mask(i, 5); +} + +/** @todo these macros should be ripped out into some common repository for + * reuse in an assembler */ +/* ALL HARDCODED VALUES ARE PLACEHOLDERS FOR NOW */ + +/* 0 */ +#define OP_IMM 0b0000000000 +static void do_op_imm(struct cpu *cpu, tri_t i) +{ + tri_t rs1 = get_rs1(i); + tri_t rd = get_rd(i); + + tri_t src = get_gpr(cpu, rs1); + tri_t imm9 = get_imm9(i); + tri_t fn0 = get_fn0(i); + +#define ADDI 0 + switch (fn0) { + case ADDI: { + tri_t r = tri_add(src, imm9); + set_gpr(cpu, rd, r); + break; + } + default: fprintf(stderr, "illegal/unimplemented OP_IMM at %lx," + "aborting\n", cpu->pc); + abort(); + } + + cpu->pc += 3; +} + +/* 1 */ +#define SYSTEM 0b0000000001 +static void do_system(struct cpu *cpu, tri_t i) +{ + size_t rs1 = get_rs1(i); + size_t rd = get_rd(i); + + tri_t src = get_gpr(cpu, rs1); + tri_t csr = get_imm9(i); + tri_t fn0 = get_fn0(i); + + +#define CSRRW 0 + switch (fn0) { + case CSRRW: { + /* read existing value and replace it with rs1 */ + size_t n = get_csr_num(csr); + tri_t c = get_csr(cpu, n); + set_csr(cpu, n, src); + set_gpr(cpu, rd, c); + break; + } + + default: fprintf(stderr, "illegal/unimplemented SYSTEM at %lx," + "aborting\n", cpu->pc); + abort(); + } + + cpu->pc += 3; +} + +/* -1 */ +#define STORE 0b0000000010 +static void do_store(struct cpu *cpu, tri_t i) +{ + size_t rs1 = get_rs1(i); + size_t rs2 = get_rs2(i); + + tri_t src = get_gpr(cpu, rs2); + tri_t base = get_gpr(cpu, rs1); + tri_t imm4 = get_imm4(i); + tri_t imm5 = get_imm5(i); + tri_t fn0 = get_fn0(i); + + tri_t imm = tri_sl(imm5, 4) | imm4; + + /* should maybe check that there's zeroes in other trits in fn0? */ + int w = tri_get_trit(fn0, 4); + + /* somewhat unsure if mmu should function in trinary or binary at this + * point */ + tri_t addr = tri_add(base, imm); + vm_t a = tri_to(addr); + + switch (w) { + case 0: mmu_write1(cpu, cpu->mmu, a, src); break; + case 1: mmu_write3(cpu, cpu->mmu, a, src); break; + default: + /* illegal value */ + abort(); + } + + cpu->pc += 3; +} + +/* 3 */ +#define LUI 0b0000000100 +static void do_lui(struct cpu *cpu, tri_t i) +{ + size_t rd = get_rd(i); + tri_t imm18 = get_imm18(i); + set_gpr(cpu, rd, tri_sl(imm18, 9)); + cpu->pc += 3; +} + +void cpu_reset(struct cpu *cpu) +{ + csr_init(cpu); +} + +void cpu_run(struct cpu *cpu, vm_t start) +{ + cpu->pc = start; + + /* run while the shutdown trit is zero */ + while (!(cpu->csr[CSR_MPOWER] & 0b1100)) { + tri_t i = mmu_read3(cpu, cpu->mmu, cpu->pc); + /** @todo check for raised interrupts, illegal addr etc. */ + + /* check lowest five trits to determine opcode */ + switch (tri_mask(i, 5)) { + case LUI: do_lui(cpu, i); break; + case STORE: do_store(cpu, i); break; + case SYSTEM: do_system(cpu, i); break; + case OP_IMM: do_op_imm(cpu, i); break; + default: /** @todo raise illegal instruction exception */ + fprintf(stderr, "illegal/unimplemented " + "instruction at %lx, aborting\n", + cpu->pc); + abort(); + break; + } + + /* do_* is responsible for updating pc */ + } +} diff --git a/triscv/src/main.c b/triscv/src/main.c new file mode 100644 index 0000000..7acc958 --- /dev/null +++ b/triscv/src/main.c @@ -0,0 +1,62 @@ +#include <triscv/uart.h> +#include <triscv/cpu.h> +#include <triscv/mmu.h> +#include <triscv/tmb.h> +#include <triscv/mem.h> + +#define OPCODE(t) (t) +#define RD(t) ((t) << 10) +#define RS1(t) ((t) << 28) +#define RS2(t) ((t) << 36) +#define IMM4(t) ((t) << 10) +#define IMM5(t) ((t) << 44) +#define IMM9(t) ((t) << 36) +#define IMM18(t) ((t) << 18) + +static const tri_t prog[] = { + /* li x1, '0' (48) */ + /* or in this case, lui x1, 0, addi x1, 48 */ + OPCODE(0b0100ULL) | RD(0b01ULL) | IMM18(0b0ULL), + OPCODE(0b0000ULL) | RD(0b01ULL) | RS1(0b01ULL) | IMM9(0b0110100100ULL), + /* li x2, 19683 (uart base reg) */ + OPCODE(0b0100ULL) | RD(0b10ULL) | IMM18(0b1ULL), + OPCODE(0b0000ULL) | RD(0b10ULL) | RS1(0b10ULL) | IMM9(0ULL), + /* sw x1, 0(x2) */ + OPCODE(0b0010ULL) | RS2(0b01ULL) | RS1(0b10ULL), + /* li x1, 3 (mpower)*/ + OPCODE(0b0100ULL) | RD(0b01ULL), + OPCODE(0b0000ULL) | RD(0b01ULL) | RS1(0b01ULL) | IMM9(0b0100ULL), + /* csrrw mpower, x0, x1 */ + /* mpower = -9841, which is then internally converted to 0 */ + /* NOT FINAL CSR VALUE */ + OPCODE(0b0001ULL) | RD(0b00ULL) | RS1(0b01ULL) | IMM9(0b101010101010101010UL) +}; + +int main() +{ + /* add memory regions etc. */ + struct mmu *mmu = mmu_create(); + + /* map one trinary page */ + struct mem *mem = mem_create(19683); + mem_init(mem, prog, 8); + mmu_map_dev(mmu, 0, mem_dev(mem)); + + struct uart *uart = uart_create(); + mmu_map_dev(mmu, 19683, uart_dev(uart)); + + struct tmb *tmb = tmb_create(); + + /* one cpu for each core we want */ + struct cpu *cpu = cpu_create(mmu, tmb); + + cpu_run(cpu, 0); + + uart_destroy(uart); + cpu_destroy(cpu); + tmb_destroy(tmb); + mmu_destroy(mmu); + mem_destroy(mem); + + return 0; +} diff --git a/triscv/src/mem.c b/triscv/src/mem.c new file mode 100644 index 0000000..5d70896 --- /dev/null +++ b/triscv/src/mem.c @@ -0,0 +1,79 @@ +#include <triscv/mem.h> +#include <string.h> + +struct mem { + size_t size; + uint32_t buf[]; +}; + +struct mem *mem_create(size_t size) +{ + struct mem *mem = calloc(1, sizeof(struct mem) + size * sizeof(mem->buf[0])); + mem->size = size; + return mem; +} + +void mem_destroy(struct mem *mem) +{ + free(mem); +} + +void mem_init(struct mem *mem, const void *buf, size_t len) +{ + assert((len * 3) < mem->size); + for (size_t i = 0; i < len * 3; i += 3) { + tri_t t = ((tri_t *)buf)[i / 3]; + mem->buf[i + 0] = tri_mask(t, 9); + t = tri_sr(t, 9); + + mem->buf[i + 1] = tri_mask(t, 9); + t = tri_sr(t, 9); + + mem->buf[i + 2] = tri_mask(t, 9); + } +} + +static void mem_write1(struct cpu *cpu, struct mem *mem, pm_t addr, tri_t t) +{ + (void)cpu; + (void)mem; + (void)addr; + (void)t; +} + +static void mem_write3(struct cpu *cpu, struct mem *mem, pm_t addr, tri_t t) +{ + (void)cpu; + (void)mem; + (void)addr; + (void)t; +} + +static tri_t mem_read1(struct cpu *cpu, struct mem *mem, pm_t addr) +{ + (void)cpu; + tri_t t = (tri_t)mem->buf[addr]; + return tri_mask(t, 9); +} + +static tri_t mem_read3(struct cpu *cpu, struct mem *mem, pm_t addr) +{ + (void)cpu; + /* not necessarily ideal, but I guess it works for now */ + tri_t t0 = mem_read1(cpu, mem, addr + 0); + tri_t t1 = mem_read1(cpu, mem, addr + 1); + tri_t t2 = mem_read1(cpu, mem, addr + 2); + return t0 | tri_sl(t1, 9) | tri_sl(t2, 18); +} + +struct dev mem_dev(struct mem *mem) +{ + return (struct dev){ + .dev = mem, + .size = mem->size, + .write1 = (dev_write1_t)mem_write1, + .write3 = (dev_write3_t)mem_write3, + .read1 = (dev_read1_t)mem_read1, + .read3 = (dev_read3_t)mem_read3 + }; +} diff --git a/triscv/src/mmu.c b/triscv/src/mmu.c new file mode 100644 index 0000000..c73f91d --- /dev/null +++ b/triscv/src/mmu.c @@ -0,0 +1,151 @@ +#include <triscv/mmu.h> + +struct tlb_map { + vm_t from; + pm_t to; + bool valid; +}; + +struct dev_map { + pm_t start; + struct dev dev; +}; + +/* completely arbitrary value */ +#define MMU_SIZE 1024 +#define MAX_DEVS 16 +struct mmu { + /* virtual -> physical */ + struct tlb_map tlb[MMU_SIZE]; + + /* physical to dev */ + struct dev_map dev[MAX_DEVS]; + size_t devs; + + /* whether we should treat incoming addresses as virtual or physical */ + bool translate; +}; + +struct mmu *mmu_create() +{ + /** @todo map some backing memory as well */ + return calloc(1, sizeof(struct mmu)); +} + +void mmu_destroy(struct mmu *mmu) +{ + free(mmu); +} + +static struct dev_map *mmu_find_dev_map(struct mmu *mmu, pm_t addr) +{ + for (size_t i = 0; i < mmu->devs; ++i) { + struct dev_map *d = &mmu->dev[i]; + if (d->start > addr) + continue; + + /* slightly tricky off by one here */ + if (d->dev.size <= (addr - d->start)) + continue; + + return d; + } + + return NULL; +} + +stat_t mmu_map_dev(struct mmu *mmu, pm_t start, struct dev dev) +{ + /** @todo return status or something */ + if (mmu->devs == MAX_DEVS) + return ERR_FULL; + + if (mmu_find_dev_map(mmu, start)) + return ERR_EXISTS; + + struct dev_map *d = &mmu->dev[mmu->devs++]; + d->dev = dev; + d->start = start; + return OK; +} + +void mmu_enable(struct mmu *mmu) +{ + mmu->translate = true; +} + +void mmu_disable(struct mmu *mmu) +{ + mmu->translate = false; +} + +static bool mmu_translate(struct cpu *cpu, struct mmu *mmu, vm_t *addr) +{ + (void)cpu; + (void)mmu; + (void)addr; + /** @todo raise segfault if addr is not allowed */ + return true; +} + +void mmu_write1(struct cpu *cpu, struct mmu *mmu, vm_t addr, tri_t t) +{ + if (mmu->translate) { + if (!mmu_translate(cpu, mmu, &addr)) + return; + } + + struct dev_map *d = mmu_find_dev_map(mmu, addr); + if (!d || !d->dev.write1) { + /** @todo raise bus (?) error */ + } + + d->dev.write1(cpu, d->dev.dev, addr - d->start, t); +} + +void mmu_write3(struct cpu *cpu, struct mmu *mmu, vm_t addr, tri_t t) +{ + if (mmu->translate) { + if (!mmu_translate(cpu, mmu, &addr)) + return; + } + + struct dev_map *d = mmu_find_dev_map(mmu, addr); + if (!d || !d->dev.write3) { + /** @todo raise bus error */ + } + + d->dev.write3(cpu, d->dev.dev, addr - d->start, t); +} + +tri_t mmu_read1(struct cpu *cpu, struct mmu *mmu, vm_t addr) +{ + if (mmu->translate) { + if (!mmu_translate(cpu, mmu, &addr)) + return 0; + } + + struct dev_map *d = mmu_find_dev_map(mmu, addr); + if (!d || !d->dev.read1) { + /** @todo raise bus error */ + return 0; + } + + return d->dev.read1(cpu, d->dev.dev, addr - d->start); +} + +tri_t mmu_read3(struct cpu *cpu, struct mmu *mmu, vm_t addr) +{ + if (mmu->translate) { + if (!mmu_translate(cpu, mmu, &addr)) + return 0; + } + + struct dev_map *d = mmu_find_dev_map(mmu, addr); + if (!d || !d->dev.read3) { + /** @todo raise bus error */ + return 0; + } + + return d->dev.read3(cpu, d->dev.dev, addr - d->start); +} diff --git a/triscv/src/source.mk b/triscv/src/source.mk new file mode 100644 index 0000000..3b8724f --- /dev/null +++ b/triscv/src/source.mk @@ -0,0 +1,2 @@ +SRC_LOCAL != echo src/*.c +TRISCV_SOURCES += $(SRC_LOCAL) diff --git a/triscv/src/tmb.c b/triscv/src/tmb.c new file mode 100644 index 0000000..3f6c037 --- /dev/null +++ b/triscv/src/tmb.c @@ -0,0 +1,29 @@ +#include <triscv/tmb.h> + +struct map { + vm_t to; + tri_t val; + size_t width; + bool valid; +}; + +#define TMB_SIZE 3 +struct tmb { + struct map map[TMB_SIZE]; +}; + +struct tmb *tmb_create() +{ + return calloc(1, sizeof(struct tmb)); +} + +void tmb_destroy(struct tmb *tmb) +{ + free(tmb); +} + +size_t tmb_size(struct cpu *cpu) +{ + (void)cpu; + return TMB_SIZE; +} diff --git a/triscv/src/uart.c b/triscv/src/uart.c new file mode 100644 index 0000000..492f0dd --- /dev/null +++ b/triscv/src/uart.c @@ -0,0 +1,44 @@ +#include <triscv/uart.h> +#include <utf9.h> + +struct uart { + /* guess this doesn't need much for now, at least until I add some state + * stuff to it */ +}; + +struct uart *uart_create() +{ + return calloc(1, sizeof(struct uart)); +} + +void uart_destroy(struct uart *uart) +{ + free(uart); +} + +static void uart_write1(struct cpu *cpu, struct uart *uart, pm_t addr, tri_t t) +{ + (void)cpu; + (void)uart; + (void)addr; + +#define U8_LEN 16 + uint8_t u8[U8_LEN] = {0}; + size_t u9_read = 0; + size_t l = utf9_to_utf8(u8, U8_LEN, &t, 1, &u9_read); + + for (size_t i = 0; i < l; ++i) + putchar(u8[i]); +} + +struct dev uart_dev(struct uart *uart) +{ + return (struct dev){ + .dev = uart, + .size = 1, + .write1 = (dev_write1_t)uart_write1, + .write3 = NULL, /* illegal */ + .read1 = NULL, /* not supported for now */ + .read3 = NULL + }; +} diff --git a/utf9/README.md b/utf9/README.md new file mode 100644 index 0000000..3dfd8c1 --- /dev/null +++ b/utf9/README.md @@ -0,0 +1,47 @@ +# utf9, trinary utf8 + +utf9 can be seen as a thin wrapper around utf8, in that each tryte can be +expanded to either one or two utf8 bytes. Each tryte contains a header with +enough information to relatively easily perform the expansion. Current +four-level utf8 fits snugly into two trytes, with 2+2 bytes mapped. utf8 can +still be extended up to six bytes, as can utf9, though that is still reserved. + +| Prefix | Condition | Bytes mapped | Info +|--------|-----------|--------------| +| 00 | Start/End | 1+0 | +| 01 | Start/End | 2+0 | +| 0i | End | 0+1 | +| 10 | Start | 2+1 | +| 11 | Start | 2+2 | +| 1i? | Start | ??? | Reserved for extensions +| i | End | 0+2 | + +# design + +The main design consideration is ease of translation to utf8. Given one tryte, +you can always repackage it as one or two valid utf8 bytes (valid in format, +missing start/end bytes may still show up). + +There are some peculiarities, possibly most annoyingly that to fit trailing +utf8 bytes into this scheme, the two byte mapping end tryte can only have one +prefix trit. + +All multitryte codepoints start with a one, which is nifty, but checking if a +codepoint is contained in a single tryte requires two checks, which is somewhat +slower than I would've liked. Still, to keep open the possibility of extending +the scheme, the single end tryte has to share the same leading zero as single +tryte sequences. In a trinary computer, the check can be a bit quicker, +construct a mask of 01 and filter with OPO OOO OOP (or something similar), +this should leave you with 11 only in the case of single tryte code points. + +The extension reservation actually reserves the range [1ii, 1i1], probably with +each element referring to 5, 6 and 7 bytes respectively, covering the utf8 +extension space. At these ranges, the first utf8 byte codes small enough values +that we can use a three trit flag without issues. + +# symmetry + +Currently there's a nice symmetry between start and stop conditions, in that one +start can be mapped to one end, and they always follow oneanother. With possible +extensions this might not be the case though, so to future-proof your code, +don't assume this. diff --git a/utf9/main.c b/utf9/main.c new file mode 100644 index 0000000..54be9dd --- /dev/null +++ b/utf9/main.c @@ -0,0 +1,24 @@ +#include <utf9.h> + +#define STRING "𐍈𐍈𐍈𐍈" +int main() +{ + /* not strictly portable, assumes locale is utf8, etc. */ + const char *s = STRING; + tri_t t[20]; + size_t c = 0; + /* note 20 * 3, as t is in tri words but each word is three 'chars' */ + /* unsure if this is more or less confusing than using the word sizes + * directly */ + size_t l = utf8_to_utf9(t, 20 * 3, s, sizeof(STRING), &c); + printf("utf8->utf9: %llu characters to %llu\n", c, l); + + char r[20]; + /* hmm, currently it's kind of difficult to tell if we just ran out of + * buffer space or failed due to some other issue. */ + l = utf9_to_utf8(r, 20, t, l, &c); + printf("utf9->utf8: %llu characters to %llu\n", c, l); + + printf("original : %s\n", s); + printf("converted : %s\n", r); +} diff --git a/utf9/utf9.c b/utf9/utf9.c new file mode 100644 index 0000000..65d709c --- /dev/null +++ b/utf9/utf9.c @@ -0,0 +1,346 @@ +#include <tri.h> + +static size_t legal_utf8(const uint8_t *u8, size_t pos, size_t len) +{ + if (pos >= len) + return 0; + + u8 += pos; + + uint8_t c = u8[0]; + if (~c & 0x80) + return 1; + + if (~c & 0x40) + return 0; + + /* we know 0b11xxxxxx, so we must have at least two bytes */ + size_t bytes = 2; + if (~c & 0x20) bytes = 2; + else if (~c & 0x10) bytes = 3; + else if (~c & 0x08) bytes = 4; + + /* too short, code point is cut off */ + if (len < bytes) + return 0; + + for (size_t i = 0; i < bytes - 1; ++i) { + /* invalid continuation byte */ + uint8_t top_two_bits = u8[1 + i] >> 6; + /* don't know if we sign extended, so mask lowest two bits */ + if ((top_two_bits & 0x3) != 2) + return 0; + } + + return bytes; +} + +static tri_t get_tryte(const tri_t *t, size_t p) +{ + size_t idx = p / 3; + size_t shift = (p % 3) * 9; + tri_t e = t[idx]; + + e = tri_sr(e, shift); + e = tri_mask(e, 9); + return e; +} + +static size_t legal_utf9(const tri_t *t, size_t p9, size_t len) +{ + if (p9 >= len) + return 0; + + tri_t e = get_tryte(t, p9); + int top = tri_get_trit(e, 8); + + /* continuation tryte as first tryte, not allowed */ + if (top == -1) + return 0; + + /* one tryte codepoint */ + if (top == 0) { + switch (tri_get_trit(e, 7)) { + case -1: return 0; /* illegal */ + case 0: return 1; + case 1: return 2; + } + + /* shouldn't be possible but just to make sure */ + return 0; + } + + /* two tryte codepoint */ + if (p9 + 1 >= len) + return 0; + + tri_t n = get_tryte(t, p9 + 1); + int d0 = tri_get_trit(n, 8); + + switch (tri_get_trit(e, 7)) { + case -1: return 0; /* reserved for now */ + case 0: { + int d1 = tri_get_trit(n, 7); + if (d0 == 0 && d1 == -1) + return 3; + + return 0; + } + + case 1: { + if (d0 == -1) + return 4; + + return 0; + } + } + + return 0; +} + +static int64_t extract_bits_utf8(const uint8_t *u8, size_t pos, size_t bytes) +{ + u8 += pos; + + /* feels like some repetition could be dealt with, but as long as this works I + * guess */ + switch (bytes) { + case 1: return u8[0] & 0x7f; + case 2: { + int64_t b0 = u8[0] & 0x1f; + int64_t b1 = u8[1] & 0x3f; + return (b0 << 6) | b1; + } + + case 3: { + int64_t b0 = u8[0] & 0xf; + int64_t b1 = u8[1] & 0x3f; + int64_t b2 = u8[2] & 0x3f; + return (b0 << 12) | (b1 << 6) | b2; + } + + case 4: { + int64_t b0 = u8[0] & 0x7; + int64_t b1 = u8[1] & 0x3f; + int64_t b2 = u8[2] & 0x3f; + int64_t b3 = u8[3] & 0x3f; + return (b0 << 18) | (b1 << 12) | (b2 << 6) | b3; + } + } + + abort(); + return 0; +} + +static int64_t extract_bits_utf9(const tri_t *u9, size_t p9, size_t bytes) +{ + tri_t e = get_tryte(u9, p9); + /* clear out header trits */ + e = tri_mask(e, 7); + + int64_t r = tri_to(e); + switch (bytes) { + case 1: return r & 0x7f; + case 2: return r & 0x7ff; + case 3: { + int64_t b0 = r & 0x3ff; + tri_t t = get_tryte(u9, p9 + 1); + t = tri_mask(t, 7); + int64_t b1 = tri_to(t) & 0x3f; + return (b0 << 6) + b1; + } + case 4: { + int64_t b0 = r & 0x1ff; + /* four byte case is kind of special, as it only has a single + * trit as a marker */ + tri_t t = get_tryte(u9, p9 + 1); + t = tri_mask(t, 8); + int64_t b1 = tri_to(t) & 0x7ff; + return (b0 << 12) + b1; + } + } + + /* shouldn't be possible */ + return 0; +} + +static void set_utf9(tri_t *u9, size_t p9, tri_t t, const char *s, size_t len) +{ + /* should this prefer get_tryte and set_trit or something? */ + size_t idx = p9 / 3; + size_t shift = (p9 % 3) * 9; + + tri_t e = u9[idx]; + + /* should only have lowest tryte, but just to be sure */ + t = tri_mask(t, 9); + + /* clear out our shift destination */ + tri_t tmp = tri_mask(e, shift); + e = tri_discard(e, shift + 9); + e |= tmp; + + /* set prefixes, assumes i01 */ + for (size_t i = 0; i < len; ++i) { + char c = s[i]; + + switch (c) { + case '1': t = tri_set_trit(t, 8 - i, 1); break; + case 'i': t = tri_set_trit(t, 8 - i, -1); break; + } + } + + t = tri_sl(t, shift); + e |= t; + u9[idx] = e; +} + +static void set_utf8(uint8_t *u8, size_t p8, int64_t b, const char *s, size_t len) +{ + /* set prefixes */ + for (size_t i = 0; i < len; ++i) { + char c = s[i]; + switch (c) { + case '1': b |= (1 << (7 - i)); break; + case '0': b &= ~(1 << (7 - i)); break; + } + } + + u8[p8] = b; +} + +size_t utf8_to_utf9(tri_t *u9, size_t u9_len, const uint8_t *u8, size_t u8_len, size_t *u8_read) +{ + size_t p8 = 0; + size_t p9 = 0; + + while (true) { + if (p9 == u9_len) + break; + + if (p8 == u8_len) + break; + + size_t bytes = 0; + /* also checks that we have enough space to work with */ + if ((bytes = legal_utf8(u8, p8, u8_len)) == 0) + return 0; + + /* round up */ + size_t trytes = (bytes + 1) / 2; + + /* not enough space for result */ + if (p9 + trytes >= u9_len) + return 0; + + int64_t bits = extract_bits_utf8(u8, p8, bytes); + switch (bytes) { + case 1: { + tri_t t = tri_from(bits & 0x7f); + set_utf9(u9, p9++, t, "00", 2); + break; + } + + case 2: { + tri_t t = tri_from(bits & 0x7ff); + set_utf9(u9, p9++, t, "01", 2); + break; + } + + case 3: { + tri_t t0 = tri_from(bits & 0x3f); + tri_t t1 = tri_from((bits >> 6) & 0x3ff); + set_utf9(u9, p9++, t1, "10", 2); + set_utf9(u9, p9++, t0, "0i", 2); + break; + } + + case 4: { + tri_t t0 = tri_from(bits & 0x3ff); + tri_t t1 = tri_from((bits >> 12) & 0x1f); + set_utf9(u9, p9++, t1, "11", 2); + set_utf9(u9, p9++, t0, "i", 1); + break; + } + default: abort(); + } + + p8 += bytes; + } + + if (u8_read) + *u8_read = p8; + + return p9; +} + +size_t utf9_to_utf8(uint8_t *u8, size_t u8_len, const tri_t *u9, size_t u9_len, size_t *u9_read) +{ + size_t p8 = 0; + size_t p9 = 0; + + while (true) { + if (p9 == u9_len) + break; + + if (p8 == u8_len) + break; + + size_t bytes = 0; + if ((bytes = legal_utf9(u9, p9, u9_len)) == 0) + return 0; + + size_t trytes = (bytes + 1) / 2; + if (p8 + bytes >= u8_len) + return 0; + + int64_t bits = extract_bits_utf9(u9, p9, bytes); + /* moving this switch into something like encode_bits_utf8() + * could be useful if we want to iterate over all codepoints */ + switch (bytes) { + case 1: { + int64_t b0 = bits & 0x7f; + set_utf8(u8, p8++, b0, "0", 1); + break; + } + + case 2: { + int64_t b1 = bits & 0x3f; + int64_t b0 = (bits >> 6) & 0x1f; + set_utf8(u8, p8++, b0, "110", 3); + set_utf8(u8, p8++, b1, "10", 2); + break; + } + + case 3: { + int64_t b2 = bits & 0x3f; + int64_t b1 = (bits >> 6) & 0x3f; + int64_t b0 = (bits >> 12) & 0xf; + set_utf8(u8, p8++, b0, "1110", 4); + set_utf8(u8, p8++, b1, "10", 2); + set_utf8(u8, p8++, b2, "10", 2); + break; + } + + case 4: { + int64_t b3 = bits & 0x3f; + int64_t b2 = (bits >> 6) & 0x3f; + int64_t b1 = (bits >> 12) & 0x3f; + int64_t b0 = (bits >> 18) & 0x07; + set_utf8(u8, p8++, b0, "11110", 5); + set_utf8(u8, p8++, b1, "10", 2); + set_utf8(u8, p8++, b2, "10", 2); + set_utf8(u8, p8++, b3, "10", 2); + break; + } + } + + p9 += trytes; + + } + + if (u9_read) + *u9_read = p9; + + return p8; +} diff --git a/utf9/utf9.h b/utf9/utf9.h new file mode 100644 index 0000000..73a1576 --- /dev/null +++ b/utf9/utf9.h @@ -0,0 +1,11 @@ +#ifndef UTF9_H +#define UTF9_H + +#include <stddef.h> +#include <tri.h> + +size_t utf8_to_utf9(tri_t *u9, size_t u9_len, const uint8_t *u8, size_t u8_len, size_t *u8_read); + +size_t utf9_to_utf8(uint8_t *u8, size_t u8_len, const tri_t *u9, size_t u9_len, size_t *u9_read); + +#endif |
