From: John Tsiombikas Date: Tue, 11 Oct 2016 11:35:11 +0000 (+0300) Subject: parser sortof-works X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=antikythera;a=commitdiff_plain;h=6879b81017c2662b0c5a0b9027df8cf13b10545a parser sortof-works --- diff --git a/src/machine.cc b/src/machine.cc index 3d4dd73..441826e 100644 --- a/src/machine.cc +++ b/src/machine.cc @@ -47,6 +47,15 @@ void Machine::add_motor(int gearidx, float speed_hz) motors.push_back(m); } +int Machine::get_gear_index(Gear *g) const +{ + std::map::const_iterator it = gearidx.find(g); + if(it == gearidx.end()) { + return -1; + } + return it->second; +} + void Machine::invalidate_meshing() { meshing_valid = false; diff --git a/src/machine.h b/src/machine.h index e0f2155..097157d 100644 --- a/src/machine.h +++ b/src/machine.h @@ -29,6 +29,8 @@ public: void add_gear(Gear *g); /* takes ownership */ void add_motor(int gearidx, float speed_hz); + int get_gear_index(Gear *g) const; + void invalidate_meshing(); void calc_meshing(); diff --git a/src/main.cc b/src/main.cc index 772b63c..2aec0a0 100644 --- a/src/main.cc +++ b/src/main.cc @@ -13,6 +13,7 @@ #include "texture.h" #include "machine.h" #include "meshgen.h" +#include "mparser.h" static bool init(); static void cleanup(); @@ -88,7 +89,12 @@ static bool init() Mesh::use_custom_sdr_attr = false; machine = new Machine; + if(!parse_machine(machine, "data/test.machine")) { + fprintf(stderr, "failed to parse machine\n"); + return false; + } + /* const float pitch = 10.0f; Gear *gear1 = new Gear; @@ -119,6 +125,7 @@ static bool init() gear2->attach(subgear); machine->add_gear(subgear); subgear->color = Vec3(0.8, 0.7, 0.5); + */ machine->add_motor(0, 1.0); diff --git a/src/mparser.cc b/src/mparser.cc index 90c1b6d..10ea6ba 100644 --- a/src/mparser.cc +++ b/src/mparser.cc @@ -1,3 +1,6 @@ +#include +#include +#include #include #include #include @@ -7,10 +10,19 @@ enum ValueType { VAL_NUM, VAL_VEC, VAL_STR }; struct Value { ValueType type; - char *str; + std::string s; float v[4]; }; +struct ParserState; + +typedef bool (*Func)(ParserState*); + +struct FuncDesc { + Func func; + int arity; +}; + struct ParserState { FILE *fp; const char *fname; @@ -22,9 +34,11 @@ struct ParserState { std::stack val; std::map var; - std::string last_mod_var; + std::map func; std::map gears; + std::stack cur_gear; + Motor *cur_motor; }; #define MAX_ID_LEN 31 @@ -32,24 +46,43 @@ struct ParserState { static bool machine(ParserState *ps); static bool expect(ParserState *ps, char c); static bool statement(ParserState *ps); -static bool ident(ParserState *ps, std::string *s); -static bool gear(ParserState *ps); static bool expression(ParserState *ps); +static bool term(ParserState *ps); +static bool vector(ParserState *ps); +static bool function(ParserState *ps, const char *name); static char *get_ident(ParserState *ps, char *buf, int bsz); +static bool get_number(ParserState *ps, float *num); +static char *get_string(ParserState *ps, char *buf, int bsz); static bool nextchar(ParserState *ps); static void putback(ParserState *ps, char c); +static void errmsg(ParserState *ps, const char *fmt, ...); static void expected(ParserState *ps, const char *str); static void set_var(ParserState *ps, const char *name, const Value &value); static bool have_var(ParserState *ps, const char *name); static const Value &get_var(ParserState *ps, const char *name); +static void set_func(ParserState *ps, const char *name, Func func, int nargs = 0); +static bool have_func(ParserState *ps, const char *name); +static Func get_func(ParserState *ps, const char *name); +static int get_func_arity(ParserState *ps, const char *name); + +static Gear *begin_gear(ParserState *ps); +static bool end_gear(ParserState *ps); +static Gear *this_gear(ParserState *ps); static void update_gear_vars(ParserState *ps, Gear *gear); static bool set_gear_var(Gear *gear, const char *name, const Value &val); +static void update_motor_vars(ParserState *ps, Motor *motor); +static bool set_motor_var(ParserState *ps, Motor *motor, const char *name, const Value &val); + +// built-in functions +static bool func_adjacent(ParserState *ps); + + bool parse_machine(Machine *mcn, const char *fname) { FILE *fp = fopen(fname, "rb"); @@ -61,9 +94,14 @@ bool parse_machine(Machine *mcn, const char *fname) pstate.nerrors = 0; pstate.fp = fp; pstate.mcn = mcn; - pstate.nextc = fgetc(fp); // prime the parser + pstate.nextc = 0; pstate.savedc = -1; + pstate.cur_motor = 0; + + // init built-in function table + set_func(&pstate, "adjacent", func_adjacent, 2); + nextchar(&pstate); bool res = machine(&pstate); fclose(fp); return res; @@ -87,7 +125,7 @@ static bool machine(ParserState *ps) return true; } -static bool expect(ParserState *ps, int c) +static bool expect(ParserState *ps, char c) { if(c != ps->nextc) { char buf[2] = {0, 0}; @@ -107,26 +145,51 @@ static bool statement(ParserState *ps) } if(strcmp(id, "gear") == 0) { - if(!get_ident(ps, id, sizeof id)) { - fprintf(stderr, "gear name missing\n"); + if(!expect(ps, '{')) { return false; } - expect(ps, '{'); - Gear *gear = new Gear; - gear->name = id; - ps->gears[id] = gear; + Gear *gear = begin_gear(ps); + if(!gear) return false; + update_gear_vars(ps, gear); while(ps->nextc != '}') { if(!statement(ps)) { return false; } - update_gear_vars(ps, gear); } expect(ps, '}'); - ps->mcn->add_gear(gear); + if(!end_gear(ps)) { + return false; + } + return true; + } + + if(strcmp(id, "motor") == 0) { + if(!expect(ps, '{')) { + return false; + } + if(ps->cur_motor) { + errmsg(ps, "nested motors not allowed"); + return false; + } + + ps->cur_motor = new Motor; + update_motor_vars(ps, ps->cur_motor); + + while(ps->nextc != '}') { + if(!statement(ps)) { + return false; + } + } + expect(ps, '}'); + + ps->mcn->add_motor(ps->cur_motor->drive, ps->cur_motor->speed); + delete ps->cur_motor; + ps->cur_motor = 0; + return true; } if(ps->nextc == '=') { @@ -138,13 +201,172 @@ static bool statement(ParserState *ps) set_var(ps, id, ps->val.top()); ps->val.pop(); - ps->last_mod_var = id; + return true; } + + expected(ps, "expression"); + return false; } static bool expression(ParserState *ps) { - // TODO + return term(ps); +} + +static bool term(ParserState *ps) +{ + if(ps->nextc == '+') { + expect(ps, '+'); + return expression(ps); + } + if(ps->nextc == '-') { + expect(ps, '-'); + if(!expression(ps)) { + return false; + } + + Value &v = ps->val.top(); + switch(v.type) { + case VAL_VEC: + v.v[3] = -v.v[3]; + v.v[2] = -v.v[2]; + v.v[1] = -v.v[1]; + case VAL_NUM: + v.v[0] = -v.v[0]; + break; + + default: + expected(ps, "number or vector after an unary -"); + return false; + } + return true; + } + if(isalpha(ps->nextc)) { + char buf[MAX_ID_LEN]; + if(!get_ident(ps, buf, sizeof buf)) { + return false; + } + + if(ps->nextc == '(') { + if(!function(ps, buf)) { + return false; + } + } else if(have_var(ps, buf)) { + ps->val.push(get_var(ps, buf)); + } else { + errmsg(ps, "unknown identifier: %s", buf); + return false; + } + return true; + } + if(isdigit(ps->nextc)) { + float num; + if(!get_number(ps, &num)) { + return false; + } + + Value v; + v.type = VAL_NUM; + v.v[0] = num; + ps->val.push(v); + return true; + } + if(ps->nextc == '[') { + return vector(ps); + } + if(ps->nextc == '"') { + char buf[MAX_ID_LEN]; + if(!get_string(ps, buf, sizeof buf)) { + return false; + } + + Value v; + v.type = VAL_STR; + v.s = buf; + ps->val.push(v); + return true; + } + + expected(ps, "term"); + return false; +} + +static bool vector(ParserState *ps) +{ + int nelem; + if(!expect(ps, '[') || + !expression(ps) || + !expect(ps, ',') || + !expression(ps) || + !expect(ps, ',') || + !expression(ps)) { + return false; + } + + if(ps->nextc == ']') { + expect(ps, ']'); + nelem = 3; + } else { + if(!expect(ps, ',') || !expression(ps) || !expect(ps, ']')) { + return false; + } + nelem = 4; + } + + Value vec; + vec.type = VAL_VEC; + vec.v[3] = 1.0f; + + for(int i=0; ival.top(); + if(tmp.type != VAL_NUM) { + expected(ps, "numbers as vector elements"); + return false; + } + vec.v[i] = tmp.v[0]; + ps->val.pop(); + } + + ps->val.push(vec); + return true; +} + +static bool function(ParserState *ps, const char *name) +{ + if(!expect(ps, '(')) { + return false; + } + + if(!have_func(ps, name)) { + errmsg(ps, "unknown function: %s", name); + return false; + } + + int nargs = 0; + while(ps->nextc != ')') { + if(nargs && !expect(ps, ',')) { + return false; + } + if(!expression(ps)) { + return false; + } + ++nargs; + } + expect(ps, ')'); + + int arity = get_func_arity(ps, name); + if(arity != nargs) { + errmsg(ps, "function %s expects %d arguments", name, arity); + return false; + } + Func func = get_func(ps, name); + assert(func); + + if(!func(ps)) { + errmsg(ps, "function %s failed", name); + return false; + } + return true; } static char *get_ident(ParserState *ps, char *buf, int bsz) @@ -154,7 +376,7 @@ static char *get_ident(ParserState *ps, char *buf, int bsz) expected(ps, "identifier"); return 0; } - while((isalnum(ps->nextc) || ps->nextc == '_')) { + while(isalnum(ps->nextc) || ps->nextc == '_') { if(bsz > 1) { *ptr++ = ps->nextc; --bsz; @@ -162,14 +384,72 @@ static char *get_ident(ParserState *ps, char *buf, int bsz) nextchar(ps); } *ptr = 0; + printf("get_ident -> \"%s\"\n", buf); + return buf; +} + +static bool get_number(ParserState *ps, float *num) +{ + char buf[256], *ptr = buf, *end = buf + sizeof buf; + bool found_point = false; + + if(!isdigit(ps->nextc)) { + expected(ps, "number"); + return false; + } + + while(isdigit(ps->nextc) || (ps->nextc == '.' && !found_point)) { + if(ptr < end) { + *ptr++ = ps->nextc; + } + if(ps->nextc == '.') { + found_point = true; + } + nextchar(ps); + } + *ptr = 0; + + *num = atof(buf); + printf("get_number -> %f\n", *num); + return true; +} + +static char *get_string(ParserState *ps, char *buf, int bsz) +{ + char *ptr = buf; + if(!expect(ps, '"')) { + return 0; + } + + while(ps->nextc != -1 && ps->nextc != '"') { + if(bsz > 1) { + *ptr++ = ps->nextc; + --bsz; + } + if((ps->nextc = fgetc(ps->fp)) == '\n') { + ++ps->nline; + } + } + *ptr = 0; + + if(ps->nextc == -1) { + return 0; + } + nextchar(ps); + + printf("get_string -> \"%s\"\n", buf); return buf; } -static bool skip_line(FILE *fp) +static bool skip_line(ParserState *ps) { int c; - while((c = fgetc(fp)) != -1 && c != '\n'); - return c != -1; + while((c = fgetc(ps->fp)) != -1 && c != '\n'); + if(c != -1) { + ps->nextc = fgetc(ps->fp); + return true; + } + return false; } static bool nextchar(ParserState *ps) @@ -182,7 +462,7 @@ static bool nextchar(ParserState *ps) while((ps->nextc = fgetc(ps->fp)) != -1) { if(ps->nextc == '#') { - if(!skip_line(ps->fp)) { + if(!skip_line(ps)) { return false; } ++ps->nline; @@ -195,6 +475,11 @@ static bool nextchar(ParserState *ps) } } + /*if(ps->nextc != -1) { + printf("DBG: nextchar -> %c\n", ps->nextc); + } else { + printf("DBG: nextchar -> EOF\n"); + }*/ return ps->nextc != -1; } @@ -204,15 +489,36 @@ static void putback(ParserState *ps, char c) ps->nextc = c; } +static void errmsg(ParserState *ps, const char *fmt, ...) +{ + fprintf(stderr, "%s line %d error: ", ps->fname, ps->nline); + + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fputc('\n', stderr); +} + static void expected(ParserState *ps, const char *str) { - fprintf(stderr, "%s line %d error, expected: %s\n", ps->fname, ps->nline, str); + errmsg(ps, "expected: %s", str); ++ps->nerrors; } static void set_var(ParserState *ps, const char *name, const Value &value) { ps->var[name] = value; + + Gear *gear = this_gear(ps); + if(gear) { + set_gear_var(gear, name, value); + } + + if(ps->cur_motor) { + set_motor_var(ps, ps->cur_motor, name, value); + } } static bool have_var(ParserState *ps, const char *name) @@ -225,6 +531,29 @@ static const Value &get_var(ParserState *ps, const char *name) return ps->var[name]; } +static void set_func(ParserState *ps, const char *name, Func func, int nargs) +{ + FuncDesc fdesc; + fdesc.func = func; + fdesc.arity = nargs; + ps->func[name] = fdesc; +} + +static bool have_func(ParserState *ps, const char *name) +{ + return ps->func.find(name) != ps->func.end(); +} + +static Func get_func(ParserState *ps, const char *name) +{ + return ps->func[name].func; +} + +static int get_func_arity(ParserState *ps, const char *name) +{ + return ps->func[name].arity; +} + static void print_value(const Value &val, FILE *fp) { switch(val.type) { @@ -237,7 +566,7 @@ static void print_value(const Value &val, FILE *fp) break; case VAL_STR: - fprintf(fp, "\"%s\"", val.str); + fprintf(fp, "\"%s\"", val.s.c_str()); break; default: @@ -247,15 +576,42 @@ static void print_value(const Value &val, FILE *fp) // Gear-specific stuff -static void update_gear_vars(ParserState *ps, Gear *gear) +static Gear *begin_gear(ParserState *ps) +{ + Gear *res = new Gear; + ps->cur_gear.push(res); + return res; +} + +static bool end_gear(ParserState *ps) { - if(!ps->last_mod_var.empty()) { - const char *name = ps->last_mod_var.c_str(); - set_gear_var(gear, name, get_var(ps, name)); - ps->last_mod_var.clear(); - return; + if(ps->cur_gear.empty()) { + errmsg(ps, "parser error: unbalanced end_gear"); + return false; + } + Gear *gear = ps->cur_gear.top(); + ps->cur_gear.pop(); + + printf("DBG: end_gear: %s\n", gear->name.c_str()); + + if(gear->name.empty() || ps->gears[gear->name]) { + char buf[32]; + sprintf(buf, "gear%04d", (int)ps->gears.size()); + gear->name = buf; } + printf("DBG: adding gear: %s\n", gear->name.c_str()); + ps->gears[gear->name] = gear; + ps->mcn->add_gear(gear); + return true; +} +static Gear *this_gear(ParserState *ps) +{ + return ps->cur_gear.empty() ? 0 : ps->cur_gear.top(); +} + +static void update_gear_vars(ParserState *ps, Gear *gear) +{ std::map::const_iterator it = ps->var.begin(); while(it != ps->var.end()) { set_gear_var(gear, it->first.c_str(), it->second); @@ -263,7 +619,6 @@ static void update_gear_vars(ParserState *ps, Gear *gear) } } - #define ASSERT_TYPE(v, t) \ do { \ if((v).type != (t)) { \ @@ -279,7 +634,11 @@ static void update_gear_vars(ParserState *ps, Gear *gear) static bool set_gear_var(Gear *gear, const char *name, const Value &val) { - if(strcmp(name, "position") == 0) { + if(strcmp(name, "name") == 0) { + ASSERT_TYPE(val, VAL_STR); + gear->name = val.s; + + } else if(strcmp(name, "position") == 0) { ASSERT_TYPE(val, VAL_VEC); gear->pos = VVEC3(val); @@ -318,3 +677,81 @@ static bool set_gear_var(Gear *gear, const char *name, const Value &val) return true; } + + +// motor stuff + +static void update_motor_vars(ParserState *ps, Motor *motor) +{ + std::map::const_iterator it = ps->var.begin(); + while(it != ps->var.end()) { + set_motor_var(ps, motor, it->first.c_str(), it->second); + ++it; + } +} + +static bool set_motor_var(ParserState *ps, Motor *motor, const char *name, const Value &val) +{ + if(strcmp(name, "drive") == 0) { + ASSERT_TYPE(val, VAL_STR); + Gear *gear = ps->gears[val.s]; + if(!gear) { + errmsg(ps, "undefined gear: %s", val.s.c_str()); + return false; + } + int idx = ps->mcn->get_gear_index(gear); + assert(idx >= 0); + motor->drive = idx; + + } else if(strcmp(name, "speed") == 0) { + ASSERT_TYPE(val, VAL_NUM); + motor->speed = val.v[0]; + + } else { + return false; + } + return true; +} + + +// built-in functions +static bool func_adjacent(ParserState *ps) +{ + Value val_dir = ps->val.top(); ps->val.pop(); + Value val_gear_name = ps->val.top(); ps->val.pop(); + + if(val_gear_name.type != VAL_STR) { + expected(ps, "gear name (string) as 1st arg to adjacent"); + return false; + } + if(val_dir.type != VAL_VEC) { + expected(ps, "direction vector as 2nd arg to adjacent"); + return false; + } + + Gear *gthis = this_gear(ps); + if(!gthis) { + errmsg(ps, "adjacent: called outside of a gear block"); + return false; + } + + Gear *gother = ps->gears[val_gear_name.s]; + if(!gother) { + errmsg(ps, "adjacent: gear \"%s\" not found", val_gear_name.s.c_str()); + return false; + } + + Vec3 dir = Vec3(val_dir.v[0], val_dir.v[1], val_dir.v[2]); + + float sum_radii = gthis->radius + gother->radius; + float avg_teeth_len = (gthis->teeth_length + gother->teeth_length) * 0.5; + Vec3 pos = gother->pos + normalize(dir) * (sum_radii - avg_teeth_len * 0.75); + + Value res; + res.type = VAL_VEC; + res.v[0] = pos.x; + res.v[1] = pos.y; + res.v[2] = pos.z; + ps->val.push(res); + return true; +}