10 enum ValueType { VAL_NUM, VAL_VEC, VAL_STR };
19 typedef bool (*Func)(ParserState*);
35 std::stack<Value> val;
36 std::map<std::string, Value> var;
37 std::map<std::string, FuncDesc> func;
39 std::map<std::string, Gear*> gears;
40 std::vector<Gear*> cur_gear;
46 static bool machine(ParserState *ps);
47 static bool expect(ParserState *ps, char c);
48 static bool statement(ParserState *ps);
49 static bool expression(ParserState *ps);
50 static bool term(ParserState *ps);
51 static bool vector(ParserState *ps);
52 static bool function(ParserState *ps, const char *name);
54 static char *get_ident(ParserState *ps, char *buf, int bsz);
55 static bool get_number(ParserState *ps, float *num);
56 static char *get_string(ParserState *ps, char *buf, int bsz);
58 static bool nextchar(ParserState *ps);
59 static void putback(ParserState *ps, char c);
61 static void errmsg(ParserState *ps, const char *fmt, ...);
62 static void expected(ParserState *ps, const char *str);
64 static void set_var(ParserState *ps, const char *name, const Value &value);
65 static bool have_var(ParserState *ps, const char *name);
66 static const Value &get_var(ParserState *ps, const char *name);
68 static void set_func(ParserState *ps, const char *name, Func func, int nargs = 0);
69 static bool have_func(ParserState *ps, const char *name);
70 static Func get_func(ParserState *ps, const char *name);
71 static int get_func_arity(ParserState *ps, const char *name);
73 static Gear *begin_gear(ParserState *ps);
74 static bool end_gear(ParserState *ps);
75 static Gear *this_gear(ParserState *ps);
76 static Gear *find_gear(ParserState *ps, const char *name);
77 static void update_gear_vars(ParserState *ps, Gear *gear);
78 static bool set_gear_var(Gear *gear, const char *name, const Value &val);
80 static void update_motor_vars(ParserState *ps, Motor *motor);
81 static bool set_motor_var(ParserState *ps, Motor *motor, const char *name, const Value &val);
84 static bool func_adjacent(ParserState *ps);
85 static bool func_coaxial(ParserState *ps);
88 bool parse_machine(Machine *mcn, const char *fname)
90 FILE *fp = fopen(fname, "rb");
101 pstate.cur_motor = 0;
103 // init built-in function table
104 set_func(&pstate, "adjacent", func_adjacent, 2);
105 set_func(&pstate, "coaxial", func_coaxial, 2);
108 bool res = machine(&pstate);
113 static bool machine(ParserState *ps)
115 char tok[MAX_ID_LEN + 1];
116 if(strcmp(get_ident(ps, tok, sizeof tok), "machine") != 0) {
117 expected(ps, "machine");
122 while(ps->nextc != '}') {
131 static bool expect(ParserState *ps, char c)
134 char buf[2] = {0, 0};
143 static bool statement(ParserState *ps)
145 char id[MAX_ID_LEN + 1];
146 if(!get_ident(ps, id, sizeof id)) {
150 if(strcmp(id, "gear") == 0) {
151 if(!expect(ps, '{')) {
155 Gear *gear = begin_gear(ps);
156 if(!gear) return false;
158 update_gear_vars(ps, gear);
160 while(ps->nextc != '}') {
173 if(strcmp(id, "motor") == 0) {
174 if(!expect(ps, '{')) {
178 errmsg(ps, "nested motors not allowed");
182 ps->cur_motor = new Motor;
183 update_motor_vars(ps, ps->cur_motor);
185 while(ps->nextc != '}') {
192 ps->mcn->add_motor(ps->cur_motor->drive, ps->cur_motor->speed);
193 delete ps->cur_motor;
198 if(ps->nextc == '=') {
200 if(!expression(ps)) {
205 set_var(ps, id, ps->val.top());
210 expected(ps, "expression");
214 static bool expression(ParserState *ps)
216 return term(ps); // TODO expand
219 static bool term(ParserState *ps)
221 if(ps->nextc == '+') {
223 return expression(ps);
225 if(ps->nextc == '-') {
227 if(!expression(ps)) {
231 Value &v = ps->val.top();
242 expected(ps, "number or vector after an unary -");
247 if(isalpha(ps->nextc)) {
248 char buf[MAX_ID_LEN];
249 if(!get_ident(ps, buf, sizeof buf)) {
253 if(ps->nextc == '(') {
254 if(!function(ps, buf)) {
257 } else if(have_var(ps, buf)) {
258 ps->val.push(get_var(ps, buf));
260 errmsg(ps, "unknown identifier: %s", buf);
265 if(isdigit(ps->nextc)) {
267 if(!get_number(ps, &num)) {
277 if(ps->nextc == '[') {
280 if(ps->nextc == '"') {
281 char buf[MAX_ID_LEN];
282 if(!get_string(ps, buf, sizeof buf)) {
293 expected(ps, "term");
297 static bool vector(ParserState *ps)
300 if(!expect(ps, '[') ||
309 if(ps->nextc == ']') {
313 if(!expect(ps, ',') || !expression(ps) || !expect(ps, ']')) {
323 for(int i=0; i<nelem; i++) {
324 const Value &tmp = ps->val.top();
325 if(tmp.type != VAL_NUM) {
326 expected(ps, "numbers as vector elements");
329 vec.v[nelem - i - 1] = tmp.v[0];
337 static bool function(ParserState *ps, const char *name)
339 if(!expect(ps, '(')) {
343 if(!have_func(ps, name)) {
344 errmsg(ps, "unknown function: %s", name);
349 while(ps->nextc != ')') {
350 if(nargs && !expect(ps, ',')) {
353 if(!expression(ps)) {
360 int arity = get_func_arity(ps, name);
362 errmsg(ps, "function %s expects %d arguments", name, arity);
365 Func func = get_func(ps, name);
369 errmsg(ps, "function %s failed", name);
375 static char *get_ident(ParserState *ps, char *buf, int bsz)
378 if(!isalpha(ps->nextc)) {
379 expected(ps, "identifier");
382 while(isalnum(ps->nextc) || ps->nextc == '_') {
390 printf("get_ident -> \"%s\"\n", buf);
394 static bool get_number(ParserState *ps, float *num)
396 char buf[256], *ptr = buf, *end = buf + sizeof buf;
397 bool found_point = false;
399 if(!isdigit(ps->nextc)) {
400 expected(ps, "number");
404 while(isdigit(ps->nextc) || (ps->nextc == '.' && !found_point)) {
408 if(ps->nextc == '.') {
416 printf("get_number -> %f\n", *num);
420 static char *get_string(ParserState *ps, char *buf, int bsz)
423 if(!expect(ps, '"')) {
427 while(ps->nextc != -1 && ps->nextc != '"') {
432 if((ps->nextc = fgetc(ps->fp)) == '\n') {
438 if(ps->nextc == -1) {
443 printf("get_string -> \"%s\"\n", buf);
447 static bool skip_line(ParserState *ps)
450 while((c = fgetc(ps->fp)) != -1 && c != '\n');
452 ps->nextc = fgetc(ps->fp);
458 static bool nextchar(ParserState *ps)
460 if(ps->savedc != -1) {
461 ps->nextc = ps->savedc;
466 while((ps->nextc = fgetc(ps->fp)) != -1) {
467 if(ps->nextc == '#') {
473 if(!isspace(ps->nextc)) {
476 if(ps->nextc == '\n') {
481 /*if(ps->nextc != -1) {
482 printf("DBG: nextchar -> %c\n", ps->nextc);
484 printf("DBG: nextchar -> EOF\n");
486 return ps->nextc != -1;
489 static void putback(ParserState *ps, char c)
491 ps->savedc = ps->nextc;
495 static void errmsg(ParserState *ps, const char *fmt, ...)
497 fprintf(stderr, "%s line %d error: ", ps->fname, ps->nline);
501 vfprintf(stderr, fmt, ap);
507 static void expected(ParserState *ps, const char *str)
509 errmsg(ps, "expected: %s", str);
513 static void set_var(ParserState *ps, const char *name, const Value &value)
515 ps->var[name] = value;
517 Gear *gear = this_gear(ps);
519 set_gear_var(gear, name, value);
523 set_motor_var(ps, ps->cur_motor, name, value);
527 static bool have_var(ParserState *ps, const char *name)
529 return ps->var.find(name) != ps->var.end();
532 static const Value &get_var(ParserState *ps, const char *name)
534 return ps->var[name];
537 static void set_func(ParserState *ps, const char *name, Func func, int nargs)
542 ps->func[name] = fdesc;
545 static bool have_func(ParserState *ps, const char *name)
547 return ps->func.find(name) != ps->func.end();
550 static Func get_func(ParserState *ps, const char *name)
552 return ps->func[name].func;
555 static int get_func_arity(ParserState *ps, const char *name)
557 return ps->func[name].arity;
560 static void print_value(const Value &val, FILE *fp)
564 fprintf(fp, "%f", val.v[0]);
568 fprintf(fp, "[%f %f %f %f]", val.v[0], val.v[1], val.v[2], val.v[3]);
572 fprintf(fp, "\"%s\"", val.s.c_str());
576 fprintf(fp, "<invalid>");
580 // Gear-specific stuff
582 static Gear *begin_gear(ParserState *ps)
584 Gear *res = new Gear;
585 ps->cur_gear.push_back(res);
589 static bool end_gear(ParserState *ps)
591 if(ps->cur_gear.empty()) {
592 errmsg(ps, "parser error: unbalanced end_gear");
595 Gear *gear = ps->cur_gear.back();
596 ps->cur_gear.pop_back();
598 printf("DBG: end_gear: %s\n", gear->name.c_str());
600 if(gear->name.empty() || ps->gears[gear->name]) {
602 sprintf(buf, "gear%04d", (int)ps->gears.size());
605 printf("DBG: adding gear: %s\n", gear->name.c_str());
606 ps->gears[gear->name] = gear;
607 ps->mcn->add_gear(gear);
609 if(!ps->cur_gear.empty()) {
610 ps->cur_gear.back()->attach(gear);
615 static Gear *this_gear(ParserState *ps)
617 return ps->cur_gear.empty() ? 0 : ps->cur_gear.back();
620 static Gear *find_gear(ParserState *ps, const char *name)
622 // search progressively wider lexical scopes
623 std::vector<Gear*>::const_reverse_iterator it = ps->cur_gear.rbegin();
624 while(it != ps->cur_gear.rend()) {
626 if(g->name == std::string(name)) {
631 return ps->gears[name];
634 static void update_gear_vars(ParserState *ps, Gear *gear)
636 std::map<std::string, Value>::const_iterator it = ps->var.begin();
637 while(it != ps->var.end()) {
638 set_gear_var(gear, it->first.c_str(), it->second);
643 #define ASSERT_TYPE(v, t) \
645 if((v).type != (t)) { \
646 fprintf(stderr, "type mismatch while trying to set %s to value: ", name); \
647 print_value(val, stderr); \
648 fputc('\n', stderr); \
653 #define VVEC3(val) Vec3((val).v[0], (val).v[1], (val).v[2])
654 #define VVEC4(val) Vec4((val).v[0], (val).v[1], (val).v[2], (val).v[3])
656 static bool set_gear_var(Gear *gear, const char *name, const Value &val)
658 if(strcmp(name, "name") == 0) {
659 ASSERT_TYPE(val, VAL_STR);
662 } else if(strcmp(name, "position") == 0) {
663 ASSERT_TYPE(val, VAL_VEC);
664 gear->pos = VVEC3(val);
666 } else if(strcmp(name, "plane") == 0) {
667 ASSERT_TYPE(val, VAL_VEC);
668 gear->axis = VVEC3(val);
669 gear->pdist = val.v[3];
670 printf("setting plane eqn: %f %f %f %f\n", val.v[0], val.v[1], val.v[2], val.v[3]);
672 } else if(strcmp(name, "thickness") == 0) {
673 ASSERT_TYPE(val, VAL_NUM);
674 gear->thickness = val.v[0];
676 } else if(strcmp(name, "teeth") == 0) {
677 ASSERT_TYPE(val, VAL_NUM);
678 gear->set_teeth(val.v[0]); // set teeth and recalc radius
680 } else if(strcmp(name, "teeth_length") == 0) {
681 ASSERT_TYPE(val, VAL_NUM);
682 gear->teeth_length = val.v[0];
684 } else if(strcmp(name, "pitch") == 0) {
685 ASSERT_TYPE(val, VAL_NUM);
686 gear->set_teeth(gear->nteeth, val.v[0]); // set pitch and recalc radius
688 } else if(strcmp(name, "color") == 0) {
689 ASSERT_TYPE(val, VAL_VEC);
690 gear->color = VVEC3(val);
692 } else if(strcmp(name, "roughness") == 0) {
693 ASSERT_TYPE(val, VAL_NUM);
694 gear->roughness = val.v[0];
706 static void update_motor_vars(ParserState *ps, Motor *motor)
708 std::map<std::string, Value>::const_iterator it = ps->var.begin();
709 while(it != ps->var.end()) {
710 set_motor_var(ps, motor, it->first.c_str(), it->second);
715 static bool set_motor_var(ParserState *ps, Motor *motor, const char *name, const Value &val)
717 if(strcmp(name, "drive") == 0) {
718 ASSERT_TYPE(val, VAL_STR);
719 Gear *gear = ps->gears[val.s];
721 errmsg(ps, "undefined gear: %s", val.s.c_str());
724 int idx = ps->mcn->get_gear_index(gear);
728 } else if(strcmp(name, "speed") == 0) {
729 ASSERT_TYPE(val, VAL_NUM);
730 motor->speed = val.v[0];
739 // built-in functions
740 static bool func_adjacent(ParserState *ps)
742 Value val_angle = ps->val.top(); ps->val.pop();
743 Value val_gear_name = ps->val.top(); ps->val.pop();
745 if(val_gear_name.type != VAL_STR) {
746 expected(ps, "gear name (string) as 1st arg to adjacent");
749 if(val_angle.type != VAL_NUM) {
750 expected(ps, "angle as 2nd arg to adjacent");
754 Gear *gthis = this_gear(ps);
756 errmsg(ps, "adjacent: called outside of a gear block");
760 Gear *gother = ps->gears[val_gear_name.s];
762 errmsg(ps, "adjacent: gear \"%s\" not found", val_gear_name.s.c_str());
767 xform.rotation(deg_to_rad(val_angle.v[0]), gother->axis);
768 Vec3 dir = xform * Vec3(0, 1, 0);
770 float sum_radii = gthis->radius + gother->radius;
771 float avg_teeth_len = (gthis->teeth_length + gother->teeth_length) * 0.5;
772 Vec3 pos = gother->pos + dir * (sum_radii - avg_teeth_len * 0.75);
783 static bool func_coaxial(ParserState *ps)
785 Value val_dist = ps->val.top(); ps->val.pop();
786 Value val_gear_name = ps->val.top(); ps->val.pop();
788 if(val_gear_name.type != VAL_STR) {
789 expected(ps, "gear name (string) as 1st arg to func_coaxial");
792 if(val_dist.type != VAL_NUM) {
793 expected(ps, "stacking distance as 2nd arg to func_coaxial");
797 Gear *gthis = this_gear(ps);
799 errmsg(ps, "coaxial: called outside of a gear block");
803 Gear *gother = find_gear(ps, val_gear_name.s.c_str());
805 errmsg(ps, "coaxial: gear \"%s\" not found", val_gear_name.s.c_str());
809 float avg_thickness = (gthis->thickness + gother->thickness) * 0.5;
810 Vec3 pos = gother->pos + gother->axis * val_dist.v[0] * avg_thickness;