clox/src/parser.hpp

232 lines
5.8 KiB
C++

#pragma once
#include "tokens.hpp"
#include <cstdarg>
#include <iostream>
#include <vector>
enum class ExprType { Binary, Grouping, Unary, Literal, None };
class Expression {
public:
virtual ExprType type() { return ExprType::None; };
virtual std::string to_string() { return "Expression()"; };
virtual ~Expression() {}
};
class Binary : public Expression {
public:
ExprType type() override { return ExprType::Binary; }
std::string to_string() override {
return "(" + token_name(op->tokentype) + " " + left->to_string() + " " +
right->to_string() + ")";
}
Expression *left;
Token *op;
Expression *right;
Binary(Expression *_left, Token *_operator, Expression *_right)
: left(_left), op(_operator), right(_right){};
~Binary() override {
delete left;
delete right;
delete op;
}
};
class Grouping : public Expression {
public:
ExprType type() override { return ExprType::Grouping; }
std::string to_string() override { return "(" + expr->to_string() + ")"; }
Expression *expr;
Grouping(Expression *_expr) : expr(_expr){};
~Grouping() override { delete expr; }
};
class Unary : public Expression {
public:
ExprType type() override { return ExprType::Unary; }
std::string to_string() override {
return token_name(op->tokentype) + right->to_string();
}
Token *op;
Expression *right;
Unary(Token *_operator, Expression *_right) : op(_operator), right(_right){};
~Unary() override {
delete right;
delete op;
}
};
class Void {};
class Literal : public Expression {
public:
ExprType type() override { return ExprType::Literal; }
std::string to_string() override {
std::string text;
switch (valuetype) {
case String:
text = "\"" + value.str + "\"";
break;
case Numeric:
text = std::to_string(value.numeric);
break;
case Boolean:
text = value.boolean ? "True" : "False";
break;
case Nil:
text = "NULL";
break;
}
return text;
}
enum ValueType { String, Numeric, Boolean, Nil } valuetype;
union Value {
double_t numeric;
bool boolean;
std::string str;
Void dummy;
Value(double_t _numeric) : numeric(_numeric) {}
Value(bool _boolean) : boolean(_boolean) {}
Value(std::string _str) : str(_str) {}
Value(Void v) : dummy(v) {}
~Value() {}
} value;
Literal(Void v) : valuetype(ValueType::Nil), value(v) {}
Literal(double_t _numeric) : valuetype(ValueType::Numeric), value(_numeric) {}
Literal(std::string _str) : valuetype(ValueType::String), value(_str) {}
Literal(bool _boolean) : valuetype(ValueType::Boolean), value(_boolean) {}
};
class Parser {
private:
std::vector<Expression> expressions;
std::vector<Token> tokens;
int current_token;
Token peek() { return tokens[current_token]; };
bool is_at_end() { return peek().tokentype == Token::END_OF_FILE; };
Token *previous() { return &tokens[current_token - 1]; };
Token *advance() {
if (!is_at_end())
current_token += 1;
return previous();
}
bool check(Token::Type type) {
if (is_at_end()) {
return false;
}
return peek().tokentype == type;
}
bool match(int count, ...) {
va_list list;
va_start(list, count);
for (int i = 0; i < count; i++) {
Token::Type ttc = va_arg(list, Token::Type);
// std::cout << token_name(ttc) << "\n";
if (check(ttc)) {
advance();
return true;
}
}
return false;
};
Token *consume(Token::Type typ, std::string message) {
if (check(typ)) {
return advance();
}
throw error(peek(), message);
}
std::runtime_error error(Token token, std::string message) {
std::cout << token.to_string() << " " << message;
return std::runtime_error(message);
}
Expression *primary() {
if (match(1, Token::Type::FALSE))
return new Literal(false);
if (match(1, Token::Type::TRUE))
return new Literal(true);
if (match(1, Token::Type::NIL))
return new Literal(new Void());
if (match(1, Token::Type::NUMBER)) {
return new Literal(std::stod(previous()->literal));
}
if (match(1, Token::Type::STRING)) {
return new Literal(previous()->literal);
}
if (match(1, Token::Type::LEFT_PAREN)) {
Expression *e = expression();
consume(Token::Type::RIGHT_PAREN, "Expect ')'.");
return new Grouping(e);
}
throw std::runtime_error("Expected an expression");
}
public:
Expression *parse(std::vector<Token> tokenlist);
Expression *unary() {
if (match(2, Token::BANG, Token::Type::MINUS)) {
Token *op = previous();
Expression *right = unary();
return new Unary(op, right);
}
return primary();
}
Expression *expression() { return equality(); }
Expression *factor() {
Expression *expr = unary();
while (match(2, Token::Type::SLASH, Token::Type::STAR)) {
Token *op = previous();
Expression *right = unary();
expr = new Binary(expr, op, right);
}
return expr;
}
Expression *term() {
Expression *expr = factor();
while (match(2, Token::Type::MINUS, Token::Type::PLUS)) {
Token *op = previous();
Expression *right = unary();
expr = new Binary(expr, op, right);
}
return expr;
}
Expression *equality(void) {
Expression *expr = comparison();
while (match(2, Token::Type::BANG_EQUAL, Token::Type::BANG_EQUAL)) {
Token *op = previous();
Expression *right = comparison();
return new Binary(expr, op, right);
}
return expr;
}
Expression *comparison(void) {
Expression *expr = term();
while (match(4, Token::Type::GREATER, Token::Type::GREATER_EQUAL,
Token::Type::LESS, Token::Type::LESS_EQUAL)) {
Token *op = previous();
Expression *right = term();
expr = new Binary(expr, op, right);
}
return expr;
}
};