git.haldean.org wallbot / e64cd8c
more stuff with parsing haldean 3 years ago
10 changed file(s) with 434 addition(s) and 57 deletion(s). Raw diff Collapse all Expand all
0 *.d
1 *.o
2 libmeka.a
3 test/pack
4 test/parse
5 test/tokenize
0 c_sources = meka.c
0 MEKA_CFLAGS := $(CFLAGS) -Werror -Wall -Wextra -pedantic -Wswitch-enum
11
22 %.o: %.c
3 $(CC) -c -fPIC -MD -o $@ -I. $<
4
5 -include meka.d
3 $(CC) $(MEKA_CFLAGS) -c -fPIC -MD -o $@ -I. $<
64
75 libmeka.a: meka.o
86 $(AR) rcs $@ $<
97
108 test/tokenize: test/tokenize.o libmeka.a
11 $(CC) -o $@ $^
9 $(CC) $(MEKA_CFLAGS) -o $@ $^
10
11 test/pack: test/pack.o libmeka.a
12 $(CC) $(MEKA_CFLAGS) -o $@ $^
13
14 test/parse: test/parse.o libmeka.a
15 $(CC) $(MEKA_CFLAGS) -o $@ $^
16
17 -include meka.d
18 -include test/pack.d
19 -include test/parse.d
20 -include test/tokenize.d
21
22 check: test/pack test/parse
23 test/pack
24 test/parse
1225
1326 clean:
14 rm -f libmeka.a test/tokenize meka.o meka.d test/tokenize.o test/tokenize.d
27 rm -f \
28 libmeka.a \
29 meka.d \
30 meka.o \
31 test/pack \
32 test/pack.d \
33 test/pack.o \
34 test/parse \
35 test/parse.d \
36 test/parse.o \
37 test/tokenize \
38 test/tokenize.d \
39 test/tokenize.o
1540
1641 .PHONY: clean
77 dimension n (fixed at compile time), represents robot position
88 - register
99 static storage whose value influences the behavior of the whole system
10 - signal
11 a triple of high-period, low-period (in milliseconds) and pulse count. A
12 signal with a period of zero and a nonzero pulse count represents an
13 always-on signal. A signal with a period of zero and a zero pulse count
14 represents an always-off signal.
15
16 3v3__ _________________________ ______
17 | | |
18 | | |
19 | | |
20 | | |
21 0__ ___/ \__________________/
22
23 |< high period >|< low period >|
24 |< one pulse >|
25
2610 - channel
2711 hardware output channel with a buffer, takes signals as input
2812 - channelset
138122 true loop
139123
140124 All measurements done in whole microns to avoid floating point
125
126 Signals:
127
128 Signals are a triple of high-period, low-period (in milliseconds) and pulse
129 count, and are the input into channels. There are a few special-cases:
130
131 high-period low-period pulses meaning
132 > 0 > 0 > 0 regular signal
133 > 0 = 0 = 0 high forever
134 = 0 > 0 = 0 low forever
135 = 0 = 0 = 0 state unchanged
136
137 Any of the three values being negative is an invalid request, and the
138 interpreter should halt.
139
140 3v3__ _________________________ ______
141 | | |
142 | | |
143 | | |
144 | | |
145 0__ ___/ \__________________/
146
147 |< high period >|< low period >|
148 |< one pulse >|
149
0 /*
1 * meka.c: meka runtime
2 * Copyright (C) 2018, Haldean Brown
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
019 #include "meka.h"
20 #include "meka_internal.h"
121
222 #define _is_whitespace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r')
323
24 static meka_word p[4096];
25 static uint16_t pn = 0;
26
427 void
5 meka_skip_to_token(struct meka_prog *prog)
28 meka_skip_to_token(meka_source *src)
629 {
730 char c;
8 while (prog->next != prog->end)
31 while (src->next != src->end)
932 {
10 c = *prog->next;
33 c = *src->next;
1134 if (_is_whitespace(c))
1235 continue;
1336 if (c == '#')
1437 {
15 for (; prog->next != prog->end && *prog->next != '\n';
16 prog->next++);
38 for (; src->next != src->end && *src->next != '\n';
39 src->next++);
1740 continue;
1841 }
1942 return;
2144 }
2245
2346 int
24 meka_next_token(struct meka_token *res, struct meka_prog *prog)
47 meka_next_token(meka_token *res, meka_source *src)
2548 {
2649 char c;
2750
28 meka_skip_to_token(prog);
29 if (prog->next == prog->end)
51 meka_skip_to_token(src);
52 if (src->next == src->end)
3053 return 0;
3154
32 res->data = prog->next;
33 for (res->len = 0; prog->next != prog->end; res->len++)
55 res->marker = 0xFF & meka_tag_none;
56 res->data = src->next;
57 for (res->len = 0; src->next != src->end; res->len++)
3458 {
35 c = *prog->next++;
59 c = *src->next++;
3660 if (_is_whitespace(c) || c == '#')
3761 break;
3862 }
3963 return res->len > 0;
4064 }
65
66 meka_value
67 meka_parse_number(meka_token *t)
68 {
69 int32_t res;
70 int8_t s;
71 int8_t i;
72 char c;
73
74 res = 0;
75 i = 0;
76 s = 1;
77
78 c = *t->data;
79 if (c == '-')
80 {
81 s = -1;
82 i++;
83 }
84 else if (c == '+')
85 {
86 i++;
87 }
88
89 /* Strip leading zeroes */
90 while (t->data[i] == '0')
91 i++;
92
93 /* The largest 28-bit integer is 268435456, which is 9 digits long. Any
94 * number larger than 9 digits will overflow our 28-bit type, so I
95 * early-reject those and then don't have to check for overflow when
96 * building the 32-bit intermediate result. */
97 if (t->len - i > 9)
98 return meka_bad_value;
99
100 for (; i < t->len; i++)
101 {
102 c = t->data[i];
103 if ('0' <= c && c <= '9')
104 res = res * 10 + (c - '0');
105 else
106 return meka_bad_value;
107 }
108
109 if (res > 0xFFFFFFF)
110 return meka_bad_value;
111 return meka_pack(int, s * res);
112 }
113
114 int
115 meka_load(meka_source *src)
116 {
117 meka_token tok;
118 meka_value v;
119
120 pn = 0;
121 while (meka_next_token(&tok, src))
122 {
123 v = meka_parse_number(&tok);
124 if (v != meka_bad_value)
125 {
126 p[pn++].v = v;
127 continue;
128 }
129 }
130
131 return pn;
132 }
0 /*
1 * meka.h: meka interface
2 * Copyright (C) 2018, Haldean Brown
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #pragma once
020 #include <stdint.h>
121
2 static const uint32_t meka_tag_bool = 0x00000000;
3 static const uint32_t meka_tag_int = 0x00000001;
4 static const uint32_t meka_tag_qvec = 0x00000002;
5 static const uint32_t meka_tag_rvec = 0x00000003;
6 static const uint32_t meka_tag_reg = 0x00000004;
7 static const uint32_t meka_tag_sig = 0x00000005;
8 static const uint32_t meka_tag_chan = 0x00000006;
9 static const uint32_t meka_tag_cset = 0x00000007;
10 static const uint32_t meka_tag_mask = 0xFFFFFFF8;
22 static const uint32_t meka_tag_bool = 0x00000000;
23 static const uint32_t meka_tag_int = 0x00000001;
24 static const uint32_t meka_tag_qvec = 0x00000002;
25 static const uint32_t meka_tag_rvec = 0x00000003;
26 static const uint32_t meka_tag_reg = 0x00000004;
27 static const uint32_t meka_tag_chan = 0x00000005;
28 static const uint32_t meka_tag_cset = 0x00000006;
29 static const uint32_t meka_tag_none = 0x00000007;
30 static const uint32_t meka_tag_mask = 0xFFFFFFF8;
1131
1232 typedef uint32_t meka_value;
1333
14 #define meka_unpack(v) ((v) >> 3)
15 #define meka_pack(t, v) (((v) << 3) | meka_tag_ # v)
34 static const uint32_t meka_bad_value = 0x00000000;
35 static const uint32_t meka_true = 0x00000010;
36 static const uint32_t meka_false = 0x00000020;
1637
17 struct meka_token
18 {
19 char *data;
20 uint_least16_t len;
21 };
38 #define meka_pack(t, v) (((uint32_t) (v) << 3) | meka_tag_ ## t)
39 #define meka_tag(v) (~meka_tag_mask & (v))
2240
23 struct meka_prog
41 /* Need to use a signed shift for ints to do sign extension */
42 #define meka_unpack(v) ((v) & meka_tag_int \
43 ? (uint32_t) (((int32_t) (v)) >> 3) \
44 : (v) >> 3)
45
46 typedef struct
2447 {
2548 char *buf;
2649 char *next;
2750 char *end;
28 };
51 } meka_source;
2952
3053 int
31 meka_next_token(struct meka_token *res, struct meka_prog *prog);
54 meka_load(meka_source *src);
0 /*
1 * meka_internal.h: internal meka interfaces for testing
2 * Copyright (C) 2018, Haldean Brown
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #pragma once
20 #include "meka.h"
21
22 typedef struct
23 {
24 char *data;
25 uint8_t len;
26 /* this is here so that meka_token and meka_value can be distinguished
27 * from one another in a union */
28 uint8_t marker;
29 } meka_token;
30
31 static const uint8_t meka_word_none = 0x00;
32 static const uint8_t meka_word_int = 0x01;
33 static const uint8_t meka_word_reg = 0x02;
34 static const uint8_t meka_word_txt = 0x03;
35
36 typedef struct
37 {
38 union
39 {
40 meka_value v;
41 meka_token t;
42 };
43 } meka_word;
0 /*
1 * pack.c: tests for value packing and unpacking
2 * Copyright (C) 2018, Haldean Brown
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include "meka.h"
20 #include "unit.h"
21
22 test_t
23 pack_positive_int()
24 {
25 meka_value v;
26 for (int i = 0; i < (1 << 28); i++)
27 {
28 v = meka_pack(int, i);
29 assert((int32_t) meka_unpack(v) == i);
30 assert(meka_tag(v) == meka_tag_int);
31 }
32 return ok;
33 }
34
35 test_t
36 pack_negative_int()
37 {
38 meka_value v;
39
40 for (int i = 0; i > -(1 << 28); i--)
41 {
42 v = meka_pack(int, i);
43 assert((int32_t) meka_unpack(v) == i);
44 assert(meka_tag(v) == meka_tag_int);
45 }
46 return ok;
47 }
48
49 int main()
50 {
51 init();
52 run(pack_positive_int);
53 run(pack_negative_int);
54 finish();
55 }
0 /*
1 * parse.c: tests for token parsing
2 * Copyright (C) 2018, Haldean Brown
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include "meka.h"
20 #include "meka_internal.h"
21 #include "unit.h"
22
23 extern meka_value meka_parse_number(meka_token *t);
24
25 test_t
26 parse_number()
27 {
28 meka_token t;
29
30 t.data = "0"; t.len = 1;
31 assert(meka_parse_number(&t) == meka_pack(int, 0));
32
33 t.data = "1"; t.len = 1;
34 assert(meka_parse_number(&t) == meka_pack(int, 1));
35
36 t.data = "+1"; t.len = 2;
37 assert(meka_parse_number(&t) == meka_pack(int, 1));
38
39 t.data = "-1"; t.len = 2;
40 assert(meka_parse_number(&t) == meka_pack(int, -1));
41
42 t.data = "00000"; t.len = 5;
43 assert(meka_parse_number(&t) == meka_pack(int, 0));
44
45 /* Not a digit overflow, because they're all "leading" zeroes */
46 t.data = "0000000000000000"; t.len = 16;
47 assert(meka_parse_number(&t) == meka_pack(int, 0));
48
49 /* Digit overflow */
50 t.data = "1000000000000000"; t.len = 16;
51 assert(meka_parse_number(&t) == meka_bad_value);
52
53 /* 28-bit overflow, with admissable number of digits */
54 t.data = "268435457"; t.len = 9;
55 assert(meka_parse_number(&t) == meka_bad_value);
56
57 /* 28-bit int-max */
58 t.data = "268435455"; t.len = 9;
59 assert(meka_parse_number(&t) == meka_pack(int, 268435455));
60
61 /* 28-bit int-min */
62 t.data = "-268435455"; t.len = 10;
63 assert(meka_parse_number(&t) == meka_pack(int, -268435455));
64
65 return ok;
66 }
67
68 int
69 main()
70 {
71 init();
72 run(parse_number);
73 finish();
74 }
77 int
88 main()
99 {
10 struct meka_prog prog;
10 struct meka_source source;
1111 struct meka_token tok;
1212 size_t n;
1313
1414 n = fread(buf, 1, BUF_SIZE, stdin);
15 prog.buf = buf;
16 prog.next = prog.buf;
17 prog.end = prog.buf + n;
15 source.buf = buf;
16 source.next = source.buf;
17 source.end = source.buf + n;
1818
19 while (meka_next_token(&tok, &prog))
19 while (meka_next_token(&tok, &source))
2020 {
2121 fwrite(tok.data, 1, tok.len, stdout);
2222 printf(" (%" PRIuLEAST16 ")\n", tok.len);
0 /*
1 * unit.h: header-only unit testing "library"
2 * Copyright (C) 2015, Haldean Brown
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include <stdio.h>
20
21 typedef struct
22 {
23 char *msg;
24 int line;
25 } test_t;
26
27 #define assert(x) if (!(x)) return (test_t){.msg = #x, .line = __LINE__}
28 #define assert_jump(x) if (!(x)) { \
29 __res = (test_t){.msg = #x, .line = __LINE__}; \
30 goto assert_failed; }
31 #define jump_init() test_t __res = ok;
32 #define jump_done() return __res;
33 #define run(x) { \
34 test_t __unit_res = (x)(); __n_tests++; \
35 if (__unit_res.msg != NULL) { \
36 printf("fail: %s line %d: %s\n", #x, __unit_res.line, __unit_res.msg); \
37 __n_errs++;\
38 } else printf("ok: %s\n", #x); }
39 #define init() int __n_errs = 0, __n_tests = 0;
40 #define finish() \
41 if (__n_errs != 0) \
42 printf("%d of %d tests succeeded\n", __n_tests - __n_errs, __n_tests); \
43 return __n_errs;
44 #define ok (test_t){.msg = NULL, .line = __LINE__}
45
46 #define run_single(test) int main() { init(); run(test); finish(); }