From b27d1ee9fe9f75f2af783e4f9574366879f5e849 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 10 Oct 2016 21:40:27 +0300 Subject: [PATCH] writing the machine parser --- src/gear.cc | 9 +- src/gear.h | 3 +- src/mparser.cc | 293 ++++++++++++++++++++++++++++++++++++++++---------------- src/mparser.h | 3 +- 4 files changed, 222 insertions(+), 86 deletions(-) diff --git a/src/gear.cc b/src/gear.cc index c00b411..44c04d3 100644 --- a/src/gear.cc +++ b/src/gear.cc @@ -8,14 +8,14 @@ Gear::Gear() { pdist = 0; angle = 0; - nteeth = 42; - radius = 80; teeth_length = 5; thickness = 5; bevel = 1.5; init_angle = 0; xform_valid = false; + set_teeth(42, 10); + supergear = 0; mesh = 0; @@ -78,6 +78,11 @@ float Gear::get_angular_offset() const void Gear::set_teeth(int nt, float tooth_pitch) { + if(tooth_pitch <= 0) { + tooth_pitch = this->tooth_pitch; + } else { + this->tooth_pitch = tooth_pitch; + } float circ = tooth_pitch * nt; radius = circ / (2.0 * M_PI); nteeth = nt; diff --git a/src/gear.h b/src/gear.h index f6058a1..fac245c 100644 --- a/src/gear.h +++ b/src/gear.h @@ -58,6 +58,7 @@ public: float angle; // current angle of the gear int nteeth; // number of teeth + float tooth_pitch; float radius; // total radius of the gear, including teeth float teeth_length; // how far teeth extend past the radius @@ -87,7 +88,7 @@ public: // sets the supplied number of teeth, and calculates the radius // of the gear, to achieve the required tooth pitch - void set_teeth(int nt, float tooth_pitch); + void set_teeth(int nt, float tooth_pitch = 0.0f); void set_axis(const Vec3 &axis); const Vec3 &get_axis() const; void set_position(const Vec3 &pos); diff --git a/src/mparser.cc b/src/mparser.cc index b39df1a..90c1b6d 100644 --- a/src/mparser.cc +++ b/src/mparser.cc @@ -1,47 +1,55 @@ -#include +#include +#include +#include #include "mparser.h" #include "machine.h" -enum ASTNodeType { - AST_MACHINE, - AST_GEAR, - AST_STATEMENT, - AST_IDENT, - AST_NUMBER, - AST_VECTOR, - AST_FCALL -}; - -struct ASTNode { - std::vector children; +enum ValueType { VAL_NUM, VAL_VEC, VAL_STR }; +struct Value { + ValueType type; + char *str; + float v[4]; }; struct ParserState { FILE *fp; const char *fname; + int nline, nerrors; Machine *mcn; int nextc; int savedc; - bool error; + std::stack val; + std::map var; + std::string last_mod_var; + + std::map gears; }; +#define MAX_ID_LEN 31 + static bool machine(ParserState *ps); static bool expect(ParserState *ps, char c); -static bool expect_alpha(ParserState *ps); -static bool expect_digit(ParserState *ps); -static bool expect_alnum(ParserState *ps); -static bool match_str(ParserState *ps, const char *str); -static bool match_char(ParserState *ps, char c); -static bool mstatement(ParserState *ps); +static bool statement(ParserState *ps); static bool ident(ParserState *ps, std::string *s); static bool gear(ParserState *ps); static bool expression(ParserState *ps); +static char *get_ident(ParserState *ps, char *buf, int bsz); + static bool nextchar(ParserState *ps); static void putback(ParserState *ps, char c); +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 update_gear_vars(ParserState *ps, Gear *gear); +static bool set_gear_var(Gear *gear, const char *name, const Value &val); + bool parse_machine(Machine *mcn, const char *fname) { FILE *fp = fopen(fname, "rb"); @@ -49,11 +57,12 @@ bool parse_machine(Machine *mcn, const char *fname) ParserState pstate; pstate.fname = fname; + pstate.nline = 1; + pstate.nerrors = 0; pstate.fp = fp; pstate.mcn = mcn; - pstate.savedc = -1; pstate.nextc = fgetc(fp); // prime the parser - pstate.error = false; + pstate.savedc = -1; bool res = machine(&pstate); fclose(fp); @@ -62,11 +71,18 @@ bool parse_machine(Machine *mcn, const char *fname) static bool machine(ParserState *ps) { - matchstr(ps, "machine"); + char tok[MAX_ID_LEN + 1]; + if(strcmp(get_ident(ps, tok, sizeof tok), "machine") != 0) { + expected(ps, "machine"); + return false; + } expect(ps, '{'); - while(mstatement(ps)); - + while(ps->nextc != '}') { + if(!statement(ps)) { + return false; + } + } expect(ps, '}'); return true; } @@ -74,87 +90,79 @@ static bool machine(ParserState *ps) static bool expect(ParserState *ps, int c) { if(c != ps->nextc) { - ps->error = true; + char buf[2] = {0, 0}; + buf[0] = c; + expected(ps, buf); return false; } nextchar(ps); return true; } -static bool expect_alpha(ParserState *ps) +static bool statement(ParserState *ps) { - if(!isalpha(ps->nextc)) { - ps->error = true; + char id[MAX_ID_LEN + 1]; + if(!get_ident(ps, id, sizeof id)) { return false; } - nextchar(ps); - return true; -} -static bool expect_digit(ParserState *ps) -{ - if(!isdigit(ps->nextc)) { - ps->error = true; - return false; - } - nextchar(ps); - return true; -} + if(strcmp(id, "gear") == 0) { + if(!get_ident(ps, id, sizeof id)) { + fprintf(stderr, "gear name missing\n"); + return false; + } + expect(ps, '{'); -static bool expect_alnum(ParserState *ps) -{ - if(!isalnum(ps->nextc)) { - ps->error = true; - return false; - } - nextchar(ps); - return true; -} + Gear *gear = new Gear; + gear->name = id; + ps->gears[id] = gear; + update_gear_vars(ps, gear); -static bool match_str(ParserState *ps, const char *str) -{ - while(*str && match_char(ps, *str++)); - return !feof(ps->fp); -} + while(ps->nextc != '}') { + if(!statement(ps)) { + return false; + } + update_gear_vars(ps, gear); + } + expect(ps, '}'); -static bool match_char(ParserState *ps, int c) -{ - if(ps->nextc != c) { - return false; + ps->mcn->add_gear(gear); } - nextchar(ps); - return true; -} - -static bool expression(ParserState *ps); - -#define CHECK(x) if(!(x)) return false -static bool mstatement(ParserState *ps) -{ - std::string id; - - CHECK(ident(ps, &id)); - if(id == "gear") { - gear(ps); - } else { + if(ps->nextc == '=') { expect(ps, '='); - expression(ps); + if(!expression(ps)) { + return false; + } + expect(ps, ';'); + + set_var(ps, id, ps->val.top()); + ps->val.pop(); + ps->last_mod_var = id; } } static bool expression(ParserState *ps) { + // TODO } -static bool ident(ParserState *ps, std::string *s) +static char *get_ident(ParserState *ps, char *buf, int bsz) { - CHECK(expect_alpha(ps)); - while(isalnum(ps->nextc) || ps->nextc == '_') { - s->append((char)ps->nextc); - CHECK(nextchar(ps)); + char *ptr = buf; + if(!isalpha(ps->nextc)) { + expected(ps, "identifier"); + return 0; } - return true; + while((isalnum(ps->nextc) || ps->nextc == '_')) { + if(bsz > 1) { + *ptr++ = ps->nextc; + --bsz; + } + nextchar(ps); + } + *ptr = 0; + return buf; } static bool skip_line(FILE *fp) @@ -174,11 +182,17 @@ static bool nextchar(ParserState *ps) while((ps->nextc = fgetc(ps->fp)) != -1) { if(ps->nextc == '#') { - CHECK(skip_line(ps->fp)); + if(!skip_line(ps->fp)) { + return false; + } + ++ps->nline; } if(!isspace(ps->nextc)) { break; } + if(ps->nextc == '\n') { + ++ps->nline; + } } return ps->nextc != -1; @@ -189,3 +203,118 @@ static void putback(ParserState *ps, char c) ps->savedc = ps->nextc; ps->nextc = c; } + +static void expected(ParserState *ps, const char *str) +{ + fprintf(stderr, "%s line %d error, expected: %s\n", ps->fname, ps->nline, str); + ++ps->nerrors; +} + +static void set_var(ParserState *ps, const char *name, const Value &value) +{ + ps->var[name] = value; +} + +static bool have_var(ParserState *ps, const char *name) +{ + return ps->var.find(name) != ps->var.end(); +} + +static const Value &get_var(ParserState *ps, const char *name) +{ + return ps->var[name]; +} + +static void print_value(const Value &val, FILE *fp) +{ + switch(val.type) { + case VAL_NUM: + fprintf(fp, "%f", val.v[0]); + break; + + case VAL_VEC: + fprintf(fp, "[%f %f %f %f]", val.v[0], val.v[1], val.v[2], val.v[3]); + break; + + case VAL_STR: + fprintf(fp, "\"%s\"", val.str); + break; + + default: + fprintf(fp, ""); + } +} + +// Gear-specific stuff + +static void update_gear_vars(ParserState *ps, Gear *gear) +{ + 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; + } + + std::map::const_iterator it = ps->var.begin(); + while(it != ps->var.end()) { + set_gear_var(gear, it->first.c_str(), it->second); + ++it; + } +} + + +#define ASSERT_TYPE(v, t) \ + do { \ + if((v).type != (t)) { \ + fprintf(stderr, "type mismatch while trying to set %s to value: ", name); \ + print_value(val, stderr); \ + fputc('\n', stderr); \ + return false; \ + } \ + } while(0) + +#define VVEC3(val) Vec3((val).v[0], (val).v[1], (val).v[2]) +#define VVEC4(val) Vec4((val).v[0], (val).v[1], (val).v[2], (val).v[3]) + +static bool set_gear_var(Gear *gear, const char *name, const Value &val) +{ + if(strcmp(name, "position") == 0) { + ASSERT_TYPE(val, VAL_VEC); + gear->pos = VVEC3(val); + + } else if(strcmp(name, "plane") == 0) { + ASSERT_TYPE(val, VAL_VEC); + gear->axis = VVEC3(val); + gear->pdist = val.v[3]; + + } else if(strcmp(name, "thickness") == 0) { + ASSERT_TYPE(val, VAL_NUM); + gear->thickness = val.v[0]; + + } else if(strcmp(name, "teeth") == 0) { + ASSERT_TYPE(val, VAL_NUM); + gear->set_teeth(val.v[0]); // set teeth and recalc radius + + } else if(strcmp(name, "teeth_length") == 0) { + ASSERT_TYPE(val, VAL_NUM); + gear->teeth_length = val.v[0]; + + } else if(strcmp(name, "pitch") == 0) { + ASSERT_TYPE(val, VAL_NUM); + gear->set_teeth(gear->nteeth, val.v[0]); // set pitch and recalc radius + + } else if(strcmp(name, "color") == 0) { + ASSERT_TYPE(val, VAL_VEC); + gear->color = VVEC3(val); + + } else if(strcmp(name, "roughness") == 0) { + ASSERT_TYPE(val, VAL_NUM); + gear->roughness = val.v[0]; + + } else { + return false; + } + + return true; +} diff --git a/src/mparser.h b/src/mparser.h index 7fa1b6f..eb64f1b 100644 --- a/src/mparser.h +++ b/src/mparser.h @@ -2,7 +2,8 @@ #define MPARSER_H_ #include +#include "machine.h" -int parse_machine(Machine *mcn, const char *fname); +bool parse_machine(Machine *mcn, const char *fname); #endif /* MPARSER_H_ */ -- 1.7.10.4