writing the machine parser
[antikythera] / src / mparser.cc
1 #include <string>
2 #include <map>
3 #include <stack>
4 #include "mparser.h"
5 #include "machine.h"
6
7 enum ValueType { VAL_NUM, VAL_VEC, VAL_STR };
8 struct Value {
9         ValueType type;
10         char *str;
11         float v[4];
12 };
13
14 struct ParserState {
15         FILE *fp;
16         const char *fname;
17         int nline, nerrors;
18         Machine *mcn;
19
20         int nextc;
21         int savedc;
22
23         std::stack<Value> val;
24         std::map<std::string, Value> var;
25         std::string last_mod_var;
26
27         std::map<std::string, Gear*> gears;
28 };
29
30 #define MAX_ID_LEN      31
31
32 static bool machine(ParserState *ps);
33 static bool expect(ParserState *ps, char c);
34 static bool statement(ParserState *ps);
35 static bool ident(ParserState *ps, std::string *s);
36 static bool gear(ParserState *ps);
37 static bool expression(ParserState *ps);
38
39 static char *get_ident(ParserState *ps, char *buf, int bsz);
40
41 static bool nextchar(ParserState *ps);
42 static void putback(ParserState *ps, char c);
43
44 static void expected(ParserState *ps, const char *str);
45
46 static void set_var(ParserState *ps, const char *name, const Value &value);
47 static bool have_var(ParserState *ps, const char *name);
48 static const Value &get_var(ParserState *ps, const char *name);
49
50 static void update_gear_vars(ParserState *ps, Gear *gear);
51 static bool set_gear_var(Gear *gear, const char *name, const Value &val);
52
53 bool parse_machine(Machine *mcn, const char *fname)
54 {
55         FILE *fp = fopen(fname, "rb");
56         if(!fp) return false;
57
58         ParserState pstate;
59         pstate.fname = fname;
60         pstate.nline = 1;
61         pstate.nerrors = 0;
62         pstate.fp = fp;
63         pstate.mcn = mcn;
64         pstate.nextc = fgetc(fp);       // prime the parser
65         pstate.savedc = -1;
66
67         bool res = machine(&pstate);
68         fclose(fp);
69         return res;
70 }
71
72 static bool machine(ParserState *ps)
73 {
74         char tok[MAX_ID_LEN + 1];
75         if(strcmp(get_ident(ps, tok, sizeof tok), "machine") != 0) {
76                 expected(ps, "machine");
77                 return false;
78         }
79         expect(ps, '{');
80
81         while(ps->nextc != '}') {
82                 if(!statement(ps)) {
83                         return false;
84                 }
85         }
86         expect(ps, '}');
87         return true;
88 }
89
90 static bool expect(ParserState *ps, int c)
91 {
92         if(c != ps->nextc) {
93                 char buf[2] = {0, 0};
94                 buf[0] = c;
95                 expected(ps, buf);
96                 return false;
97         }
98         nextchar(ps);
99         return true;
100 }
101
102 static bool statement(ParserState *ps)
103 {
104         char id[MAX_ID_LEN + 1];
105         if(!get_ident(ps, id, sizeof id)) {
106                 return false;
107         }
108
109         if(strcmp(id, "gear") == 0) {
110                 if(!get_ident(ps, id, sizeof id)) {
111                         fprintf(stderr, "gear name missing\n");
112                         return false;
113                 }
114                 expect(ps, '{');
115
116                 Gear *gear = new Gear;
117                 gear->name = id;
118                 ps->gears[id] = gear;
119                 update_gear_vars(ps, gear);
120
121                 while(ps->nextc != '}') {
122                         if(!statement(ps)) {
123                                 return false;
124                         }
125                         update_gear_vars(ps, gear);
126                 }
127                 expect(ps, '}');
128
129                 ps->mcn->add_gear(gear);
130         }
131
132         if(ps->nextc == '=') {
133                 expect(ps, '=');
134                 if(!expression(ps)) {
135                         return false;
136                 }
137                 expect(ps, ';');
138
139                 set_var(ps, id, ps->val.top());
140                 ps->val.pop();
141                 ps->last_mod_var = id;
142         }
143 }
144
145 static bool expression(ParserState *ps)
146 {
147         // TODO
148 }
149
150 static char *get_ident(ParserState *ps, char *buf, int bsz)
151 {
152         char *ptr = buf;
153         if(!isalpha(ps->nextc)) {
154                 expected(ps, "identifier");
155                 return 0;
156         }
157         while((isalnum(ps->nextc) || ps->nextc == '_')) {
158                 if(bsz > 1) {
159                         *ptr++ = ps->nextc;
160                         --bsz;
161                 }
162                 nextchar(ps);
163         }
164         *ptr = 0;
165         return buf;
166 }
167
168 static bool skip_line(FILE *fp)
169 {
170         int c;
171         while((c = fgetc(fp)) != -1 && c != '\n');
172         return c != -1;
173 }
174
175 static bool nextchar(ParserState *ps)
176 {
177         if(ps->savedc != -1) {
178                 ps->nextc = ps->savedc;
179                 ps->savedc = -1;
180                 return true;
181         }
182
183         while((ps->nextc = fgetc(ps->fp)) != -1) {
184                 if(ps->nextc == '#') {
185                         if(!skip_line(ps->fp)) {
186                                 return false;
187                         }
188                         ++ps->nline;
189                 }
190                 if(!isspace(ps->nextc)) {
191                         break;
192                 }
193                 if(ps->nextc == '\n') {
194                         ++ps->nline;
195                 }
196         }
197
198         return ps->nextc != -1;
199 }
200
201 static void putback(ParserState *ps, char c)
202 {
203         ps->savedc = ps->nextc;
204         ps->nextc = c;
205 }
206
207 static void expected(ParserState *ps, const char *str)
208 {
209         fprintf(stderr, "%s line %d error, expected: %s\n", ps->fname, ps->nline, str);
210         ++ps->nerrors;
211 }
212
213 static void set_var(ParserState *ps, const char *name, const Value &value)
214 {
215         ps->var[name] = value;
216 }
217
218 static bool have_var(ParserState *ps, const char *name)
219 {
220         return ps->var.find(name) != ps->var.end();
221 }
222
223 static const Value &get_var(ParserState *ps, const char *name)
224 {
225         return ps->var[name];
226 }
227
228 static void print_value(const Value &val, FILE *fp)
229 {
230         switch(val.type) {
231         case VAL_NUM:
232                 fprintf(fp, "%f", val.v[0]);
233                 break;
234
235         case VAL_VEC:
236                 fprintf(fp, "[%f %f %f %f]", val.v[0], val.v[1], val.v[2], val.v[3]);
237                 break;
238
239         case VAL_STR:
240                 fprintf(fp, "\"%s\"", val.str);
241                 break;
242
243         default:
244                 fprintf(fp, "<invalid>");
245         }
246 }
247
248 // Gear-specific stuff
249
250 static void update_gear_vars(ParserState *ps, Gear *gear)
251 {
252         if(!ps->last_mod_var.empty()) {
253                 const char *name = ps->last_mod_var.c_str();
254                 set_gear_var(gear, name, get_var(ps, name));
255                 ps->last_mod_var.clear();
256                 return;
257         }
258
259         std::map<std::string, Value>::const_iterator it = ps->var.begin();
260         while(it != ps->var.end()) {
261                 set_gear_var(gear, it->first.c_str(), it->second);
262                 ++it;
263         }
264 }
265
266
267 #define ASSERT_TYPE(v, t) \
268         do { \
269                 if((v).type != (t)) { \
270                         fprintf(stderr, "type mismatch while trying to set %s to value: ", name); \
271                         print_value(val, stderr); \
272                         fputc('\n', stderr); \
273                         return false; \
274                 } \
275         } while(0)
276
277 #define VVEC3(val) Vec3((val).v[0], (val).v[1], (val).v[2])
278 #define VVEC4(val) Vec4((val).v[0], (val).v[1], (val).v[2], (val).v[3])
279
280 static bool set_gear_var(Gear *gear, const char *name, const Value &val)
281 {
282         if(strcmp(name, "position") == 0) {
283                 ASSERT_TYPE(val, VAL_VEC);
284                 gear->pos = VVEC3(val);
285
286         } else if(strcmp(name, "plane") == 0) {
287                 ASSERT_TYPE(val, VAL_VEC);
288                 gear->axis = VVEC3(val);
289                 gear->pdist = val.v[3];
290
291         } else if(strcmp(name, "thickness") == 0) {
292                 ASSERT_TYPE(val, VAL_NUM);
293                 gear->thickness = val.v[0];
294
295         } else if(strcmp(name, "teeth") == 0) {
296                 ASSERT_TYPE(val, VAL_NUM);
297                 gear->set_teeth(val.v[0]);      // set teeth and recalc radius
298
299         } else if(strcmp(name, "teeth_length") == 0) {
300                 ASSERT_TYPE(val, VAL_NUM);
301                 gear->teeth_length = val.v[0];
302
303         } else if(strcmp(name, "pitch") == 0) {
304                 ASSERT_TYPE(val, VAL_NUM);
305                 gear->set_teeth(gear->nteeth, val.v[0]); // set pitch and recalc radius
306
307         } else if(strcmp(name, "color") == 0) {
308                 ASSERT_TYPE(val, VAL_VEC);
309                 gear->color = VVEC3(val);
310
311         } else if(strcmp(name, "roughness") == 0) {
312                 ASSERT_TYPE(val, VAL_NUM);
313                 gear->roughness = val.v[0];
314
315         } else {
316                 return false;
317         }
318
319         return true;
320 }