+ 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; i<nelem; i++) {
+ const Value &tmp = ps->val.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;