X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=antikythera;a=blobdiff_plain;f=src%2Fmparser.cc;fp=src%2Fmparser.cc;h=90c1b6dfc1622466fb9a442837c724ed0a200baa;hp=b39df1ae6bd0fba9c67cca8da4a662fc87f8bb49;hb=b27d1ee9fe9f75f2af783e4f9574366879f5e849;hpb=ffda3e942f7a41a9ac348cfe60ae27e211545ba3 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; +}