#ifdef HAVE_CONFIG_H # include #endif #include "yuck.hh" #include "error.hh" #include "expr.hh" #include extern bool debug; Yuck::Yuck(Tokenizer *tokenizer) : _tokenizer(tokenizer), _tpos(0), _tfull(0), _bound_vars(-1), _n_bound_vars(0) { } const Token & Yuck::lex() { int p = _tpos; if (_tpos == _tfull) { _tcircle[p] = _tokenizer->get_token(); //fprintf(stderr, "%s:%u\n", _tcircle[p].cc(), _tcircle[p].landmark().column()); _tfull = (_tfull + 1) % TCircleSize; } _tpos = (_tpos + 1) % TCircleSize; return _tcircle[p]; } inline void Yuck::unlex(const Token &t) { _tcircle[_tfull] = t; _tfull = (_tfull + 1) % TCircleSize; assert(_tfull != _tpos); } Landmark Yuck::last_lexed_landmark() const { int p = (_tfull + TCircleSize - 1) % TCircleSize; return _tcircle[p].end_landmark(); } void Yuck::skip(int t1, int t2) { Token t; do { t = lex(); } while (!t.is(t1) && !t.is(t2) && !t.is('}') && t); } bool Yuck::expect(int kind, bool report_error) { Token t = lex(); if (!t.is(kind)) { if (report_error) error(t, "expected `%o', found `%o'", kind, (int)t.kind()); unlex(t); //*((int *)0) = 1; return false; } else return true; } Landmark Yuck::landmark() const { if (_tpos == _tfull) return _tokenizer->landmark(); else return _tcircle[_tpos].landmark(); } int Yuck::semi_or_comma() { Token t = lex(); if (t.is(',')) return ','; else if (t.is(';')) return ';'; else { unlex(t); return opNone; } } Logic * Yuck::handle_binds(Logic *binds) { if (SensorExpr *sensor = binds->cast_sensor_expr()) { PermString name = sensor->name(); int v = _n_bound_vars++; _bound_vars.insert(name, v); return new BinaryExpr(new BoundExpr(v), opAssign, new ConstExpr(0)); } else if (BinaryExpr *binary = binds->cast_binary_expr()) { if (binary->op() == ',') { Logic *left = handle_binds(binary->left()); Logic *right = handle_binds(binary->right()); if (left && right) return new BinaryExpr(left, ',', right); else return (left ? left : right); } else if (binary->op() == opAssign) { if (SensorExpr *sensor = binary->left()->cast_sensor_expr()) { PermString name = sensor->name(); int v = _n_bound_vars++; _bound_vars.insert(name, v); return new BinaryExpr(new BoundExpr(v), opAssign, binary->right()); } } } error(*this, "!!!!!!!!!!"); return 0; } Logic * Yuck::ylet_expr() { HashMap save_bound_vars = _bound_vars; int save_n_bound_vars = _n_bound_vars; Logic *binds = yexpr(-1, opIn); expect(opIn); if (binds) binds = handle_binds(binds); Logic *bound = yexpr(-1, opEnd); expect(opEnd); _bound_vars = save_bound_vars; _n_bound_vars = save_n_bound_vars; if (binds && bound) return new BinaryExpr(binds, ',', bound); else return 0; } // Warning: can consume 0 tokens. #define ABORT do { unlex(t); goto done; } while (0) #define DONE goto done Logic * Yuck::yexpr(int precedence, int terminator) { Logic *left = 0; while (1) { Token t = lex(); if (t.kind() == terminator) ABORT; // used to be DONE: now you're expected to read the term yourself if (t.is_operator()) { // Find a prefix operator only if left is nonexistent right now. Operator op = t.vopgroup()->find(left == 0); if (!op) { // Report an error if operator used in wrong context. error(t, "`%o' %s be used as a prefix operator", (int)t.voperator(), left ? "can only" : "can't"); ABORT; } if (op.precedence() < precedence || (op.precedence() == precedence && !op.right_assoc())) if (!op.prefix()) ABORT; Logic *right = 0; if (int new_terminator = op.terminator()) { if (op.prefix()) { left = yexpr(-1, new_terminator); expect(new_terminator); } else if (op.takes_special()) /* do nothing */; else { right = yexpr(-1, new_terminator); expect(new_terminator); } } else { if (op.prefix()) left = yexpr(op.precedence(), terminator); else if (!op.unary()) right = yexpr(op.precedence(), terminator); } switch ((int)op) { case '?': { // Ternary ?: Logic *falsecase = yexpr(op.precedence(), terminator); if (right && falsecase) left = new ConditionalExpr(left, right, falsecase); break; } case '(': // Unary '(': only grouping break; default: if (op.unary()) left = new UnaryExpr(op, left); else if (right) left = new BinaryExpr(left, op, right); break; } } else if (t.is(opIdentifier)) { if (left) ABORT; int bound = _bound_vars[t]; if (bound >= 0) left = new BoundExpr(bound); else left = new SensorExpr(t); } else if (t.is(opExpr)) { if (left) ABORT; left = t.vexpr(); } else if (t.is(opLet)) { if (left) ABORT; left = ylet_expr(); } else ABORT; } done: return left; } #undef ABORT #undef DONE