Switch to macros for better readability and add printer.hh
This commit is contained in:
parent
a6e129eb12
commit
1118e825f3
@ -18,13 +18,13 @@ int main(int argc, char *argv[]) {
|
|||||||
// run_interpreter(argc, argv);
|
// run_interpreter(argc, argv);
|
||||||
|
|
||||||
Token unary_op{TokenType::MINUS, "-", Object{}, 1};
|
Token unary_op{TokenType::MINUS, "-", Object{}, 1};
|
||||||
Expr left{unary_op, Expr{123}};
|
Expr left{Unary(unary_op, Literal(123))};
|
||||||
|
|
||||||
Token op{TokenType::STAR, "*", Object{}, 1};
|
Token op{TokenType::STAR, "*", Object{}, 1};
|
||||||
|
|
||||||
Expr right{Expr{45.67}, nullptr};
|
Expr right{Grouping(Literal(45.67))};
|
||||||
|
|
||||||
Expr expr{left, op, right};
|
Expr expr{Binary(left, op, right)};
|
||||||
|
|
||||||
AstPrinter printer{};
|
AstPrinter printer{};
|
||||||
std::cout << printer.print(expr) << '\n';
|
std::cout << printer.print(expr) << '\n';
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
#define PARSER_CC
|
#define PARSER_CC
|
||||||
|
|
||||||
#include "parser/expr.cc"
|
#include "parser/expr.cc"
|
||||||
|
#include "parser/printer.cc"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
#define PARSER_HH
|
#define PARSER_HH
|
||||||
|
|
||||||
#include "parser/expr.hh"
|
#include "parser/expr.hh"
|
||||||
|
#include "parser/printer.hh"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,101 +2,176 @@
|
|||||||
#include "../tokenizer.hh"
|
#include "../tokenizer.hh"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
|
||||||
#include <sstream>
|
Expr::Expr(ExprType type, ExprVariant value) : type{type}, value{value} {}
|
||||||
|
|
||||||
// Copy constructor
|
// Copy constructor
|
||||||
Expr::Expr(const Expr &other) : type{other.type} {
|
Expr::Expr(const Expr &other) : type{other.type} {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case ExprType::BINARY: {
|
case ExprType::BINARY: {
|
||||||
std::shared_ptr<Binary> ptr = std::get<std::shared_ptr<Binary>>(other.value);
|
std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(other.value);
|
||||||
value = std::make_shared<Binary>(*ptr);
|
value = std::make_shared<_Binary>(*ptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExprType::GROUPING: {
|
case ExprType::GROUPING: {
|
||||||
std::shared_ptr<Grouping> ptr = std::get<std::shared_ptr<Grouping>>(other.value);
|
std::shared_ptr<_Grouping> ptr = std::get<std::shared_ptr<_Grouping>>(other.value);
|
||||||
value = std::make_shared<Grouping>(*ptr);
|
value = std::make_shared<_Grouping>(*ptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExprType::LITERAL: {
|
case ExprType::LITERAL: {
|
||||||
std::shared_ptr<Literal> ptr = std::get<std::shared_ptr<Literal>>(other.value);
|
std::shared_ptr<_Literal> ptr = std::get<std::shared_ptr<_Literal>>(other.value);
|
||||||
value = std::make_shared<Literal>(*ptr);
|
value = std::make_shared<_Literal>(*ptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExprType::UNARY: {
|
case ExprType::UNARY: {
|
||||||
std::shared_ptr<Unary> ptr = std::get<std::shared_ptr<Unary>>(other.value);
|
std::shared_ptr<_Unary> ptr = std::get<std::shared_ptr<_Unary>>(other.value);
|
||||||
value = std::make_shared<Unary>(*ptr);
|
value = std::make_shared<_Unary>(*ptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move constructor
|
// Move constructor
|
||||||
Expr::Expr(const Expr &&other) : type{other.type}, value{std::move(other.value)} {}
|
Expr::Expr(const Expr &&other) : type{other.type}, value{std::move(other.value)} {
|
||||||
|
switch(type) {
|
||||||
// Binary expressoin
|
|
||||||
Expr::Expr(const Expr &left, Token op, const Expr &right)
|
|
||||||
: type{ExprType::BINARY}, value{std::make_shared<Binary>(left, op, right)} {}
|
|
||||||
|
|
||||||
// Literal expression
|
|
||||||
Expr::Expr(Object value)
|
|
||||||
: type{ExprType::LITERAL}, value{std::make_shared<Literal>(value)} {}
|
|
||||||
|
|
||||||
// Unary expressoin
|
|
||||||
Expr::Expr(Token op, const Expr &right)
|
|
||||||
: type{ExprType::UNARY}, value{std::make_shared<Unary>(op, right)} {}
|
|
||||||
|
|
||||||
// Group expression
|
|
||||||
// Has to take an extra parameter to avoid conflicting with copy constructor
|
|
||||||
Expr::Expr(const Expr &expr, void *ptr)
|
|
||||||
: type{ExprType::GROUPING}, value{std::make_shared<Grouping>(expr)} { (void)ptr; }
|
|
||||||
|
|
||||||
std::string AstPrinter::print(const Expr &expr) {
|
|
||||||
switch (expr.type) {
|
|
||||||
case ExprType::BINARY: {
|
case ExprType::BINARY: {
|
||||||
std::shared_ptr<Binary> binary = std::get<std::shared_ptr<Binary>>(expr.value);
|
std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(other.value);
|
||||||
assert(binary != nullptr);
|
ptr.reset();
|
||||||
return parenthesize(binary->op.lexeme, {&binary->left, &binary->right});
|
break;
|
||||||
}
|
}
|
||||||
case ExprType::GROUPING: {
|
case ExprType::GROUPING: {
|
||||||
std::shared_ptr<Grouping> group = std::get<std::shared_ptr<Grouping>>(expr.value);
|
std::shared_ptr<_Grouping> ptr = std::get<std::shared_ptr<_Grouping>>(other.value);
|
||||||
assert(group != nullptr);
|
ptr.reset();
|
||||||
return parenthesize("group", {&group->expr});
|
break;
|
||||||
}
|
}
|
||||||
case ExprType::LITERAL: {
|
case ExprType::LITERAL: {
|
||||||
std::shared_ptr<Literal> literal = std::get<std::shared_ptr<Literal>>(expr.value);
|
std::shared_ptr<_Literal> ptr = std::get<std::shared_ptr<_Literal>>(other.value);
|
||||||
assert(literal != nullptr);
|
ptr.reset();
|
||||||
switch (literal->value.type) {
|
break;
|
||||||
case ObjectType::NIL:
|
|
||||||
return "nil";
|
|
||||||
case ObjectType::IDENTIFIER:
|
|
||||||
case ObjectType::STRING_LIT: {
|
|
||||||
std::string value = std::get<std::string>(literal->value.value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
case ObjectType::NUMBER: {
|
|
||||||
double value = std::get<double>(literal->value.value);
|
|
||||||
return std::to_string(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case ExprType::UNARY: {
|
case ExprType::UNARY: {
|
||||||
std::shared_ptr<Unary> unary = std::get<std::shared_ptr<Unary>>(expr.value);
|
std::shared_ptr<_Unary> ptr = std::get<std::shared_ptr<_Unary>>(other.value);
|
||||||
assert(unary != nullptr);
|
ptr.reset();
|
||||||
return parenthesize(unary->op.lexeme, {&unary->right});
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AstPrinter::parenthesize(const std::string &name, std::vector<const Expr *> exprs) {
|
// Copy assignment
|
||||||
std::stringstream ss{};
|
Expr &Expr::operator=(const Expr &other) {
|
||||||
ss << '(' << name;
|
if (this == &other) {
|
||||||
for (const Expr *expr : exprs) {
|
return *this;
|
||||||
ss << ' ' << print(*expr);
|
|
||||||
}
|
}
|
||||||
ss << ')';
|
|
||||||
|
|
||||||
return ss.str();
|
switch(type) {
|
||||||
|
case ExprType::BINARY: {
|
||||||
|
std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(value);
|
||||||
|
ptr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::GROUPING: {
|
||||||
|
std::shared_ptr<_Grouping> ptr = std::get<std::shared_ptr<_Grouping>>(value);
|
||||||
|
ptr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::LITERAL: {
|
||||||
|
std::shared_ptr<_Literal> ptr = std::get<std::shared_ptr<_Literal>>(value);
|
||||||
|
ptr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::UNARY: {
|
||||||
|
std::shared_ptr<_Unary> ptr = std::get<std::shared_ptr<_Unary>>(value);
|
||||||
|
ptr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type = other.type;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case ExprType::BINARY: {
|
||||||
|
std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(other.value);
|
||||||
|
value = std::make_shared<_Binary>(*ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::GROUPING: {
|
||||||
|
std::shared_ptr<_Grouping> ptr = std::get<std::shared_ptr<_Grouping>>(other.value);
|
||||||
|
value = std::make_shared<_Grouping>(*ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::LITERAL: {
|
||||||
|
std::shared_ptr<_Literal> ptr = std::get<std::shared_ptr<_Literal>>(other.value);
|
||||||
|
value = std::make_shared<_Literal>(*ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::UNARY: {
|
||||||
|
std::shared_ptr<_Unary> ptr = std::get<std::shared_ptr<_Unary>>(other.value);
|
||||||
|
value = std::make_shared<_Unary>(*ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move assignment
|
||||||
|
Expr &Expr::operator=(const Expr &&other) {
|
||||||
|
if (this == &other) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case ExprType::BINARY: {
|
||||||
|
std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(value);
|
||||||
|
ptr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::GROUPING: {
|
||||||
|
std::shared_ptr<_Grouping> ptr = std::get<std::shared_ptr<_Grouping>>(value);
|
||||||
|
ptr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::LITERAL: {
|
||||||
|
std::shared_ptr<_Literal> ptr = std::get<std::shared_ptr<_Literal>>(value);
|
||||||
|
ptr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::UNARY: {
|
||||||
|
std::shared_ptr<_Unary> ptr = std::get<std::shared_ptr<_Unary>>(value);
|
||||||
|
ptr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type = other.type;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case ExprType::BINARY: {
|
||||||
|
std::shared_ptr<_Binary> optr = std::get<std::shared_ptr<_Binary>>(other.value);
|
||||||
|
value = std::move(other.value);
|
||||||
|
optr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::GROUPING: {
|
||||||
|
std::shared_ptr<_Grouping> optr = std::get<std::shared_ptr<_Grouping>>(other.value);
|
||||||
|
value = std::move(other.value);
|
||||||
|
optr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::LITERAL: {
|
||||||
|
std::shared_ptr<_Literal> optr = std::get<std::shared_ptr<_Literal>>(other.value);
|
||||||
|
value = std::move(other.value);
|
||||||
|
optr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExprType::UNARY: {
|
||||||
|
std::shared_ptr<_Unary> optr = std::get<std::shared_ptr<_Unary>>(other.value);
|
||||||
|
value = std::move(other.value);
|
||||||
|
optr.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,13 @@
|
|||||||
|
|
||||||
#include "../tokenizer.hh"
|
#include "../tokenizer.hh"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
struct Expr;
|
struct Expr;
|
||||||
struct Binary;
|
struct _Binary;
|
||||||
struct Grouping;
|
struct _Grouping;
|
||||||
struct Literal;
|
struct _Literal;
|
||||||
struct Unary;
|
struct _Unary;
|
||||||
|
|
||||||
enum class ExprType {
|
enum class ExprType {
|
||||||
BINARY,
|
BINARY,
|
||||||
@ -20,64 +19,57 @@ enum class ExprType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
using ExprVariant = std::variant<
|
using ExprVariant = std::variant<
|
||||||
std::shared_ptr<Binary>,
|
std::shared_ptr<_Binary>,
|
||||||
std::shared_ptr<Grouping>,
|
std::shared_ptr<_Grouping>,
|
||||||
std::shared_ptr<Literal>,
|
std::shared_ptr<_Literal>,
|
||||||
std::shared_ptr<Unary>
|
std::shared_ptr<_Unary>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
#define Binary(LEFT, OP, RIGHT) (Expr{ExprType::BINARY, std::make_shared<_Binary>(LEFT, OP, RIGHT)})
|
||||||
|
#define Grouping(EXPR) (Expr{ExprType::GROUPING, std::make_shared<_Grouping>(EXPR)})
|
||||||
|
#define Literal(VALUE) (Expr{ExprType::LITERAL, std::make_shared<_Literal>(VALUE)})
|
||||||
|
#define Unary(OP, RIGHT) (Expr{ExprType::UNARY, std::make_shared<_Unary>(OP, RIGHT)})
|
||||||
|
|
||||||
struct Expr {
|
struct Expr {
|
||||||
|
Expr(ExprType type, ExprVariant value);
|
||||||
|
|
||||||
// Copy constructor
|
// Copy constructor
|
||||||
Expr(const Expr &other);
|
Expr(const Expr &other);
|
||||||
|
|
||||||
// Move constructor
|
// Move constructor
|
||||||
Expr(const Expr &&other);
|
Expr(const Expr &&other);
|
||||||
|
|
||||||
// Binary expressoin
|
// Copy assignment
|
||||||
Expr(const Expr &left, Token op, const Expr &right);
|
Expr &operator=(const Expr &other);
|
||||||
|
|
||||||
// Literal expression
|
// Move assignment
|
||||||
Expr(Object value);
|
Expr &operator=(const Expr &&other);
|
||||||
|
|
||||||
// Unary expressoin
|
|
||||||
Expr(Token op, const Expr &right);
|
|
||||||
|
|
||||||
// Group expression
|
|
||||||
// Has to take an extra parameter to avoid conflicting with copy constructor
|
|
||||||
Expr(const Expr &expr, void *ptr);
|
|
||||||
|
|
||||||
ExprType type;
|
ExprType type;
|
||||||
ExprVariant value;
|
ExprVariant value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Binary {
|
struct _Binary {
|
||||||
Binary(const Expr &left, Token op, const Expr &right) : left{left}, op{op}, right{right} {}
|
_Binary(const Expr &left, Token op, const Expr &right) : left{left}, op{op}, right{right} {}
|
||||||
Expr left;
|
Expr left;
|
||||||
Token op;
|
Token op;
|
||||||
Expr right;
|
Expr right;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Grouping {
|
struct _Grouping {
|
||||||
Grouping(const Expr &expr) : expr{expr} {}
|
_Grouping(const Expr &expr) : expr{expr} {}
|
||||||
Expr expr;
|
Expr expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Literal {
|
struct _Literal {
|
||||||
Literal(Object value) : value{value} {}
|
_Literal(Object value) : value{value} {}
|
||||||
Object value;
|
Object value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Unary {
|
struct _Unary {
|
||||||
Unary(Token op, const Expr &right) : op{op}, right{right} {}
|
_Unary(Token op, const Expr &right) : op{op}, right{right} {}
|
||||||
Token op;
|
Token op;
|
||||||
Expr right;
|
Expr right;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstPrinter {
|
|
||||||
public:
|
|
||||||
std::string print(const Expr &expr);
|
|
||||||
private:
|
|
||||||
std::string parenthesize(const std::string &name, std::vector<const Expr *> exprs);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
53
cclox_src/parser/printer.cc
Normal file
53
cclox_src/parser/printer.cc
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include "printer.hh"
|
||||||
|
#include "expr.hh"
|
||||||
|
#include <cassert>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
std::string AstPrinter::print(const Expr &expr) {
|
||||||
|
switch (expr.type) {
|
||||||
|
case ExprType::BINARY: {
|
||||||
|
std::shared_ptr<_Binary> binary = std::get<std::shared_ptr<_Binary>>(expr.value);
|
||||||
|
assert(binary != nullptr);
|
||||||
|
return parenthesize(binary->op.lexeme, {&binary->left, &binary->right});
|
||||||
|
}
|
||||||
|
case ExprType::GROUPING: {
|
||||||
|
std::shared_ptr<_Grouping> group = std::get<std::shared_ptr<_Grouping>>(expr.value);
|
||||||
|
assert(group != nullptr);
|
||||||
|
return parenthesize("group", {&group->expr});
|
||||||
|
}
|
||||||
|
case ExprType::LITERAL: {
|
||||||
|
std::shared_ptr<_Literal> literal = std::get<std::shared_ptr<_Literal>>(expr.value);
|
||||||
|
assert(literal != nullptr);
|
||||||
|
switch (literal->value.type) {
|
||||||
|
case ObjectType::NIL:
|
||||||
|
return "nil";
|
||||||
|
case ObjectType::IDENTIFIER:
|
||||||
|
case ObjectType::STRING_LIT: {
|
||||||
|
std::string value = std::get<std::string>(literal->value.value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
case ObjectType::NUMBER: {
|
||||||
|
double value = std::get<double>(literal->value.value);
|
||||||
|
return std::to_string(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ExprType::UNARY: {
|
||||||
|
std::shared_ptr<_Unary> unary = std::get<std::shared_ptr<_Unary>>(expr.value);
|
||||||
|
assert(unary != nullptr);
|
||||||
|
return parenthesize(unary->op.lexeme, {&unary->right});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AstPrinter::parenthesize(const std::string &name, std::vector<const Expr *> exprs) {
|
||||||
|
std::stringstream ss{};
|
||||||
|
ss << '(' << name;
|
||||||
|
for (const Expr *expr : exprs) {
|
||||||
|
ss << ' ' << print(*expr);
|
||||||
|
}
|
||||||
|
ss << ')';
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
14
cclox_src/parser/printer.hh
Normal file
14
cclox_src/parser/printer.hh
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef PRINTER_HH
|
||||||
|
#define PRINTER_HH
|
||||||
|
|
||||||
|
#include "expr.hh"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class AstPrinter {
|
||||||
|
public:
|
||||||
|
std::string print(const Expr &expr);
|
||||||
|
private:
|
||||||
|
std::string parenthesize(const std::string &name, std::vector<const Expr *> exprs);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user