diff --git a/ast.cc b/ast.cc index 124533e..3b0c729 100644 --- a/ast.cc +++ b/ast.cc @@ -36,12 +36,48 @@ void EvalVisitor::visit(Unary* expr) { EvalVisitor v(context); v.visit(expr->child); Expr* e = v.value; + Number* n = dynamic_cast(e); + Boolean* b = dynamic_cast(e); + Variable* var = dynamic_cast(expr->child); switch (expr->op.tokenType) { case MINUS: - value = new Number(-dynamic_cast(e)->value); + value = new Number(-n->value); break; case BANG: - value = new Boolean(dynamic_cast(e)->isTruthy()); + value = new Boolean(!b->isTruthy()); + break; + case PLUSPLUS: + assert(var); + value = new Number(n->value + 1); + context.set(var->name, value); + break; + case MINUSMINUS: + assert(var); + value = new Number(n->value - 1); + context.set(var->name, value); + break; + default: + throw RuntimeError(); + break; + } +} + +void EvalVisitor::visit(Postfix* expr) { + EvalVisitor v(context); + v.visit(expr->child); + Expr* e = v.value; + Number* n = dynamic_cast(e); + Variable* var = dynamic_cast(expr->child); + assert(n); + assert(var); + switch (expr->op.tokenType) { + case PLUSPLUS: + value = new Number(n->value); + context.set(var->name, new Number(n->value + 1)); + break; + case MINUSMINUS: + value = new Number(n->value); + context.set(var->name, new Number(n->value - 1)); break; default: throw RuntimeError(); diff --git a/ast.h b/ast.h index 752805d..0f7c210 100644 --- a/ast.h +++ b/ast.h @@ -10,6 +10,7 @@ class Expr; class Literal; class Binary; class Unary; +class Postfix; class Variable; class Call; @@ -69,6 +70,7 @@ class ExprVisitor { virtual void visit(Literal* expr) = 0; virtual void visit(Binary* expr) = 0; virtual void visit(Unary* expr) = 0; + virtual void visit(Postfix* expr) = 0; virtual void visit(Variable* expr) = 0; virtual void visit(Call* expr) = 0; }; @@ -92,6 +94,7 @@ class EvalVisitor : public ExprVisitor { void visit(Literal* expr); void visit(Binary* expr); void visit(Unary* expr); + void visit(Postfix* expr); void visit(Variable* expr); void visit(Call* expr); Literal* getValue() { return value; } @@ -282,6 +285,20 @@ class Unary : public Expr { friend class EvalVisitor; }; +class Postfix : public Expr { + protected: + Token op; + Expr* child; + + public: + Postfix(Token op, Expr* child) : op(op), child(child){}; + operator std::string() { return "postfix " + op.lexeme; }; + bool isLval() const override { return false; } + + void accept(ExprVisitor* v) { v->visit(this); } + friend class EvalVisitor; +}; + class Literal : public Expr { public: virtual bool isTruthy() = 0; diff --git a/parser.cc b/parser.cc index 443b813..2bb061f 100644 --- a/parser.cc +++ b/parser.cc @@ -3,6 +3,7 @@ #include #include #include +#include void Parser::checkEof() { if (eof()) { @@ -347,12 +348,27 @@ Expr* Parser::factor() { } Expr* Parser::unary() { - if (match(2, MINUS, BANG)) { + std::stack st; + while (match(4, MINUS, BANG, PLUSPLUS, MINUSMINUS)) { Token op = advance(); - return new Unary(op, primary()); - } else { - return call(); + st.push(op); } + Expr* e = postfix(); + while (!st.empty()) { + auto op = st.top(); + st.pop(); + e = new Unary(op, e); + } + return e; +} + +Expr* Parser::postfix() { + Expr* p = call(); + while (match(2, PLUSPLUS, MINUSMINUS)) { + Token op = advance(); + p = new Postfix(op, p); + } + return p; } Expr* Parser::call() { diff --git a/parser.h b/parser.h index 856d4f3..84ca429 100644 --- a/parser.h +++ b/parser.h @@ -33,14 +33,15 @@ class Parser { Args args(); // ID (, ID)* RealArgs real_args(); // EXPR (, EXPR)* - Expr* expression(); - Expr* assignment(); - Expr* equality(); - Expr* comparsion(); - Expr* term(); - Expr* factor(); - Expr* unary(); // UNARY = CALL | (! | -) CALL - Expr* call(); // CALL = PRIM ('(' ARGS? ')')* + Expr* expression(); // ASSIGN + Expr* assignment(); // LVAL '=' EQUALITY | EQUALITY + Expr* equality(); // COMP ('==' | '!=') COMP | COMP + Expr* comparsion(); // TERM ('>' | '>=' | '<' | '<=') TERM | TERM + Expr* term(); // FACTOR (('+' | '-') FACTOR)* + Expr* factor(); // UNARY (('/' | '*') UNARY)* + Expr* unary(); // (! | - | -- | ++)* POSTFIX + Expr* postfix(); // CALL (++ | --)* + Expr* call(); // PRIM ('(' ARGS? ')')* Expr* primary(); public: diff --git a/scanner.cc b/scanner.cc index 43b59d3..ea16a07 100644 --- a/scanner.cc +++ b/scanner.cc @@ -71,10 +71,10 @@ void Scanner::scanToken() { addToken(STAR); break; case '+': - addToken(PLUS); + addToken(match('+') ? PLUSPLUS : PLUS); break; case '-': - addToken(MINUS); + addToken(match('-') ? MINUSMINUS : MINUS); break; case '/': if (match('/')) { diff --git a/token.h b/token.h index d4d05f0..0910e8c 100644 --- a/token.h +++ b/token.h @@ -28,6 +28,8 @@ enum TokenType { GREATER_EQUAL, LESS, LESS_EQUAL, + PLUSPLUS, + MINUSMINUS, // Literals. IDENTIFIER,