-#include <vector>
+#include <string>
+#include <map>
+#include <stack>
#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<ASTNode*> 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<Value> val;
+ std::map<std::string, Value> var;
+ std::string last_mod_var;
+
+ std::map<std::string, Gear*> 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");
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);
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;
}
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)
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;
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, "<invalid>");
+ }
+}
+
+// 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<std::string, Value>::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;
+}