From 090dc27a4b0e580a680f7f126edc326f6c4e229a Mon Sep 17 00:00:00 2001
From: Emiliano Nunez
Date: Mon, 22 Jan 2018 14:41:22 -0300
Subject: [PATCH] first commit
---
README.md | 1 +
chapter01/interpreter.cpp | 106 +++++++++++++++++++
chapter02/interpreter.cpp | 140 ++++++++++++++++++++++++
chapter03/interpreter.cpp | 142 +++++++++++++++++++++++++
chapter04/interpreter.cpp | 159 ++++++++++++++++++++++++++++
chapter05/interpreter.cpp | 190 +++++++++++++++++++++++++++++++++
chapter06/interpreter.cpp | 217 ++++++++++++++++++++++++++++++++++++++
chapter07/interpreter.hpp | 46 ++++++++
chapter07/lexer.hpp | 99 +++++++++++++++++
chapter07/main.cpp | 39 +++++++
chapter07/parser.hpp | 147 ++++++++++++++++++++++++++
chapter07/printer.hpp | 67 ++++++++++++
12 files changed, 1353 insertions(+)
create mode 100644 README.md
create mode 100644 chapter01/interpreter.cpp
create mode 100644 chapter02/interpreter.cpp
create mode 100644 chapter03/interpreter.cpp
create mode 100644 chapter04/interpreter.cpp
create mode 100644 chapter05/interpreter.cpp
create mode 100644 chapter06/interpreter.cpp
create mode 100644 chapter07/interpreter.hpp
create mode 100644 chapter07/lexer.hpp
create mode 100644 chapter07/main.cpp
create mode 100644 chapter07/parser.hpp
create mode 100644 chapter07/printer.hpp
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..796a49c
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+## C++ Version of https://ruslanspivak.com/lsbasi-part1/
diff --git a/chapter01/interpreter.cpp b/chapter01/interpreter.cpp
new file mode 100644
index 0000000..a87d687
--- /dev/null
+++ b/chapter01/interpreter.cpp
@@ -0,0 +1,106 @@
+#include
+#include
+#include
+#include
+
+namespace lsbasi {
+
+ enum TokenType {
+ _INTEGER,
+ _PLUS,
+ _EOF
+ };
+
+ class Token{
+ public:
+ TokenType type;
+ char value;
+ Token(TokenType type, char value): type(type), value(value){}
+ };
+
+ class Interpreter {
+
+ private:
+
+ std::string text;
+ int pos;
+ Token * current_token;
+
+ int error(){
+ throw std::runtime_error("Error parsing input");
+ }
+
+ Token * get_next_token(){
+
+ if (pos > text.size() - 1)
+ return new Token(_EOF, 0);
+
+ char current_char = text[pos];
+
+ if (std::isdigit(current_char)){
+ pos++;
+ return new Token (_INTEGER, current_char);
+ }
+
+ if (current_char == '+'){
+ pos++;
+ return new Token (_PLUS, current_char);
+ }
+
+ error();
+
+ }
+
+ void eat (TokenType type){
+ if (current_token->type == type)
+ current_token = get_next_token();
+ else
+ error();
+ }
+
+
+ public:
+
+ Interpreter(std::string text): text(text), pos(0), current_token(NULL){}
+
+ int expr(){
+
+ current_token = get_next_token();
+ Token * left = current_token;
+ eat(_INTEGER);
+
+ Token * op = current_token;
+ eat(_PLUS);
+
+ Token * right = current_token;
+ eat(_INTEGER);
+
+ int result = (left->value - '0') + (right->value - '0');
+
+ delete right;
+ delete op;
+ delete left;
+
+ return result;
+ }
+
+ };
+
+};
+
+int main (){
+
+ while(true){
+
+ std::string text;
+ std::cout << "calc> ";
+ std::cin >> text;
+ lsbasi::Interpreter interpreter(text);
+ std::cout << interpreter.expr() << std::endl;
+
+ //ctrl+c to exit
+
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/chapter02/interpreter.cpp b/chapter02/interpreter.cpp
new file mode 100644
index 0000000..ce39e8c
--- /dev/null
+++ b/chapter02/interpreter.cpp
@@ -0,0 +1,140 @@
+#include
+#include
+#include
+#include
+
+namespace lsbasi {
+
+ enum TokenType {
+ _INTEGER,
+ _PLUS,
+ _MINUS,
+ _EOF
+ };
+
+ class Token{
+ public:
+ TokenType type;
+ std::string value;
+ Token(TokenType type, std::string value): type(type), value(value){}
+ };
+
+ class Interpreter {
+
+ private:
+
+ std::string text;
+ int pos;
+ Token * current_token;
+ char current_char;
+
+ int error () {
+ throw std::runtime_error("Error parsing input");
+ }
+
+ void advance () {
+ pos++;
+ if (pos > text.size() - 1)
+ current_char = 0;
+ else
+ current_char = text[pos];
+ }
+
+ void skip_whitespace () {
+ while((current_char != 0) && (current_char == ' '))
+ advance();
+ }
+
+ std::string integer () {
+ std::string result;
+ while((current_char != 0) && std::isdigit(current_char)){
+ result += current_char;
+ advance();
+ }
+ return result;
+ }
+
+ Token * get_next_token () {
+
+ while(current_char != 0){
+ skip_whitespace();
+ if (std::isdigit(current_char))
+ return new Token(_INTEGER, integer());
+
+ if (current_char == '+'){
+ advance();
+ return new Token (_PLUS, "+");
+ }
+
+ if (current_char == '-'){
+ advance();
+ return new Token (_MINUS, "-");
+ }
+
+ error();
+
+ }
+
+ }
+
+ void eat (TokenType type){
+ if (current_token->type == type)
+ current_token = get_next_token();
+ else
+ error();
+ }
+
+
+ public:
+
+ Interpreter(std::string text): text(text), pos(0), current_token(NULL), current_char(text[pos]) {}
+
+ int expr(){
+
+ int result;
+
+ current_token = get_next_token();
+ Token * left = current_token;
+ eat(_INTEGER);
+
+ Token * op = current_token;
+ if (op->type == _PLUS)
+ eat(_PLUS);
+ else
+ eat(_MINUS);
+
+ Token * right = current_token;
+ eat(_INTEGER);
+
+ if(op->type == _PLUS)
+ result = std::stoi(left->value) + std::stoi(right->value);
+ else
+ result = std::stoi(left->value) - std::stoi(right->value);
+
+ delete right;
+ delete op;
+ delete left;
+
+ return result;
+ }
+
+ };
+
+};
+
+int main (){
+
+ while(true){
+
+ std::string text;
+ std::cout << "calc> ";
+ std::cin >> text;
+ lsbasi::Interpreter interpreter(text);
+ std::cout << interpreter.expr() << std::endl;
+
+ //ctrl+c to exit
+
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/chapter03/interpreter.cpp b/chapter03/interpreter.cpp
new file mode 100644
index 0000000..b16651a
--- /dev/null
+++ b/chapter03/interpreter.cpp
@@ -0,0 +1,142 @@
+#include
+#include
+#include
+#include
+
+namespace lsbasi {
+
+ enum TokenType {
+ _INTEGER,
+ _PLUS,
+ _MINUS,
+ _EOF
+ };
+
+ class Token{
+ public:
+ TokenType type;
+ std::string value;
+ Token(TokenType type, std::string value): type(type), value(value){}
+ };
+
+ class Interpreter {
+
+ private:
+
+ std::string text;
+ int pos;
+ Token * current_token;
+ char current_char;
+
+ int error () {
+ throw std::runtime_error("Error parsing input");
+ }
+
+ void advance () {
+ pos++;
+ if (pos > text.size() - 1)
+ current_char = 0;
+ else
+ current_char = text[pos];
+ }
+
+ void skip_whitespace () {
+ while((current_char != 0) && (current_char == ' '))
+ advance();
+ }
+
+ std::string integer () {
+ std::string result;
+ while((current_char != 0) && std::isdigit(current_char)){
+ result += current_char;
+ advance();
+ }
+ return result;
+ }
+
+ Token * get_next_token () {
+
+ while(current_char != 0){
+ skip_whitespace();
+ if (std::isdigit(current_char))
+ return new Token (_INTEGER, integer());
+
+ if (current_char == '+'){
+ advance();
+ return new Token (_PLUS, "+");
+ }
+
+ if (current_char == '-'){
+ advance();
+ return new Token (_MINUS, "-");
+ }
+
+ error();
+
+ }
+
+ return new Token(_EOF, "");
+
+ }
+
+ void eat (TokenType type){
+ if (current_token->type == type){
+ delete current_token;
+ current_token = get_next_token();
+ }else
+ error();
+ }
+
+ int term(){
+ std::string res = current_token->value;
+ eat(_INTEGER);
+ return std::stoi(res);
+ }
+
+
+ public:
+
+ Interpreter(std::string text): text(text), pos(0), current_token(NULL), current_char(text[pos]) {}
+
+ int expr(){
+
+ current_token = get_next_token();
+
+ int result = term();
+
+ while((current_token->type == _PLUS) || (current_token->type == _MINUS)){
+
+ Token * tk = current_token;
+ if (tk->type == _PLUS){
+ eat(_PLUS);
+ result += term();
+ }
+ if (tk->type == _MINUS){
+ eat(_MINUS);
+ result -= term();
+ }
+ }
+
+ return result;
+ }
+
+ };
+
+};
+
+int main (){
+
+ while(true){
+
+ std::string text;
+ std::cout << "calc> ";
+ std::cin >> text;
+ lsbasi::Interpreter interpreter(text);
+ std::cout << interpreter.expr() << std::endl;
+
+ //ctrl+c to exit
+
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/chapter04/interpreter.cpp b/chapter04/interpreter.cpp
new file mode 100644
index 0000000..1e40334
--- /dev/null
+++ b/chapter04/interpreter.cpp
@@ -0,0 +1,159 @@
+/**
+ * Grammar:
+ * expr : factor ((MUL | DIV) factor ) *
+ * factor: INTEGER
+ */
+
+
+#include
+#include
+#include
+#include
+
+namespace lsbasi {
+
+ enum TokenType {
+ _INTEGER,
+ _MUL,
+ _DIV,
+ _EOF
+ };
+
+ class Token{
+ public:
+ TokenType type;
+ std::string value;
+ Token(TokenType type, std::string value): type(type), value(value){}
+ };
+
+ class Lexer {
+
+ private:
+
+ std::string text;
+ int pos;
+ char current_char;
+
+ int error () {
+ throw std::runtime_error("Invalid character");
+ }
+
+ void advance () {
+ pos++;
+ if (pos > text.size() - 1)
+ current_char = 0;
+ else
+ current_char = text[pos];
+ }
+
+ void skip_whitespace () {
+ while((current_char != 0) && (current_char == ' '))
+ advance();
+ }
+
+ std::string integer () {
+ std::string result;
+ while((current_char != 0) && std::isdigit(current_char)){
+ result += current_char;
+ advance();
+ }
+ return result;
+ }
+
+ public:
+
+ Token * get_next_token () {
+ while(current_char != 0){
+ skip_whitespace();
+ if (std::isdigit(current_char))
+ return new Token (_INTEGER, integer());
+ if (current_char == '*'){
+ advance();
+ return new Token (_MUL, "*");
+ }
+ if (current_char == '/'){
+ advance();
+ return new Token (_DIV, "/");
+ }
+ error();
+ }
+ return new Token(_EOF, "");
+ }
+
+ Lexer(std::string text): text(text), pos(0), current_char(text[pos]) {}
+
+ };
+
+ class Interpreter {
+
+ private:
+
+ Token * current_token;
+ Lexer lexer;
+
+ int error () {
+ throw std::runtime_error("Invalid Syntax");
+ }
+
+ void eat (TokenType type){
+ if (current_token->type == type){
+ delete current_token;
+ current_token = lexer.get_next_token();
+ }else
+ error();
+ }
+
+ int factor(){
+ std::string res = current_token->value;
+ eat(_INTEGER);
+ return std::stoi(res);
+ }
+
+
+ public:
+
+ Interpreter(lsbasi::Lexer& lexer): lexer(lexer) {
+ current_token = this->lexer.get_next_token();
+ }
+
+ int expr(){
+
+ int result = factor();
+
+ while((current_token->type == _MUL) || (current_token->type == _DIV)){
+
+ Token * tk = current_token;
+ if (tk->type == _MUL){
+ eat(_MUL);
+ result *= factor();
+ }
+ if (tk->type == _DIV){
+ eat(_DIV);
+ result /= factor();
+ }
+ }
+
+ return result;
+ }
+
+ };
+
+};
+
+int main (){
+
+ while(true){
+
+ std::string text;
+ std::cout << "calc> ";
+ std::cin >> text;
+ lsbasi::Lexer lexer(text);
+ lsbasi::Interpreter interpreter(lexer);
+ std::cout << interpreter.expr() << std::endl;
+
+ //ctrl+c to exit
+
+ }
+
+ return 0;
+}
diff --git a/chapter05/interpreter.cpp b/chapter05/interpreter.cpp
new file mode 100644
index 0000000..b45a7ad
--- /dev/null
+++ b/chapter05/interpreter.cpp
@@ -0,0 +1,190 @@
+/**
+ * Grammar:
+ * expr : term ((PLUS | MINUS) term ) *
+ * term : factor ((MUL | DIV) factor ) *
+ * factor: INTEGER
+ */
+
+
+#include
+#include
+#include
+#include
+
+namespace lsbasi {
+
+ enum TokenType {
+ _INTEGER,
+ _PLUS,
+ _MINUS,
+ _MUL,
+ _DIV,
+ _EOF
+ };
+
+ class Token{
+ public:
+ TokenType type;
+ std::string value;
+ Token(TokenType type, std::string value): type(type), value(value){}
+ };
+
+ class Lexer {
+
+ private:
+
+ std::string text;
+ int pos;
+ char current_char;
+
+ int error () {
+ throw std::runtime_error("Invalid character");
+ }
+
+ void advance () {
+ pos++;
+ if (pos > text.size() - 1)
+ current_char = 0;
+ else
+ current_char = text[pos];
+ }
+
+ void skip_whitespace () {
+ while((current_char != 0) && (current_char == ' '))
+ advance();
+ }
+
+ std::string integer () {
+ std::string result;
+ while((current_char != 0) && std::isdigit(current_char)){
+ result += current_char;
+ advance();
+ }
+ return result;
+ }
+
+ public:
+
+ Token * get_next_token () {
+ while(current_char != 0){
+ skip_whitespace();
+ if (std::isdigit(current_char))
+ return new Token (_INTEGER, integer());
+ if (current_char == '+'){
+ advance();
+ return new Token (_PLUS, "+");
+ }
+ if (current_char == '-'){
+ advance();
+ return new Token (_MINUS, "-");
+ }
+ if (current_char == '*'){
+ advance();
+ return new Token (_MUL, "*");
+ }
+ if (current_char == '/'){
+ advance();
+ return new Token (_DIV, "/");
+ }
+ error();
+ }
+ return new Token(_EOF, "");
+ }
+
+ Lexer(std::string text): text(text), pos(0), current_char(text[pos]) {}
+
+ };
+
+ class Interpreter {
+
+ private:
+
+ Token * current_token;
+ Lexer lexer;
+
+ int error () {
+ throw std::runtime_error("Invalid Syntax");
+ }
+
+ void eat (TokenType type){
+ if (current_token->type == type){
+ delete current_token;
+ current_token = lexer.get_next_token();
+ }else
+ error();
+ }
+
+ int factor(){
+ std::string res = current_token->value;
+ eat(_INTEGER);
+ return std::stoi(res);
+ }
+
+ int term(){
+
+ int result = factor();
+
+ while((current_token->type == _MUL) || (current_token->type == _DIV)){
+
+ Token * tk = current_token;
+ if (tk->type == _MUL){
+ eat(_MUL);
+ result *= factor();
+ }
+ if (tk->type == _DIV){
+ eat(_DIV);
+ result /= factor();
+ }
+ }
+
+ return result;
+ }
+
+
+ public:
+
+ Interpreter(lsbasi::Lexer& lexer): lexer(lexer) {
+ current_token = this->lexer.get_next_token();
+ }
+
+ int expr(){
+
+ int result = term();
+
+ while((current_token->type == _PLUS) || (current_token->type == _MINUS)){
+
+ Token * tk = current_token;
+ if (tk->type == _PLUS){
+ eat(_PLUS);
+ result += term();
+ }
+ if (tk->type == _MINUS){
+ eat(_MINUS);
+ result -= term();
+ }
+ }
+
+ return result;
+ }
+
+ };
+
+};
+
+int main (){
+
+ while(true){
+
+ std::string text;
+ std::cout << "calc> ";
+ std::cin >> text;
+ lsbasi::Lexer lexer(text);
+ lsbasi::Interpreter interpreter(lexer);
+ std::cout << interpreter.expr() << std::endl;
+
+ //ctrl+c to exit
+
+ }
+
+ return 0;
+}
diff --git a/chapter06/interpreter.cpp b/chapter06/interpreter.cpp
new file mode 100644
index 0000000..57c0eea
--- /dev/null
+++ b/chapter06/interpreter.cpp
@@ -0,0 +1,217 @@
+/**
+ * Grammar:
+ * expr : term ((PLUS | MINUS) term ) *
+ * term : factor ((MUL | DIV) factor ) *
+ * factor: INTEGER | LPAREN expr RPAREN
+ */
+
+
+#include
+#include
+#include
+#include
+
+namespace lsbasi {
+
+ enum TokenType {
+ _INTEGER,
+ _PLUS,
+ _MINUS,
+ _MUL,
+ _DIV,
+ _EOF,
+ _RPAREN,
+ _LPAREN
+ };
+
+ class Token{
+ public:
+ TokenType type;
+ std::string value;
+ Token(TokenType type, std::string value): type(type), value(value){}
+ };
+
+ class Lexer {
+
+ private:
+
+ std::string text;
+ int pos;
+ char current_char;
+
+ int error () {
+ throw std::runtime_error("Invalid character");
+ }
+
+ void advance () {
+ pos++;
+ if (pos > text.size() - 1)
+ current_char = 0;
+ else
+ current_char = text[pos];
+ }
+
+ void skip_whitespace () {
+ while((current_char != 0) && (current_char == ' '))
+ advance();
+ }
+
+ std::string integer () {
+ std::string result;
+ while((current_char != 0) && std::isdigit(current_char)){
+ result += current_char;
+ advance();
+ }
+ return result;
+ }
+
+ public:
+
+ Token * get_next_token () {
+ while(current_char != 0){
+ skip_whitespace();
+ if (std::isdigit(current_char))
+ return new Token (_INTEGER, integer());
+ if (current_char == '+'){
+ advance();
+ return new Token (_PLUS, "+");
+ }
+ if (current_char == '-'){
+ advance();
+ return new Token (_MINUS, "-");
+ }
+ if (current_char == '*'){
+ advance();
+ return new Token (_MUL, "*");
+ }
+ if (current_char == '/'){
+ advance();
+ return new Token (_DIV, "/");
+ }
+ if (current_char == '('){
+ advance();
+ return new Token (_LPAREN, "(");
+ }
+ if (current_char == ')'){
+ advance();
+ return new Token (_RPAREN, ")");
+ }
+ error();
+ }
+ return new Token(_EOF, "");
+ }
+
+ Lexer(std::string text): text(text), pos(0), current_char(text[pos]) {}
+
+ };
+
+ class Interpreter {
+
+ private:
+
+ Token * current_token;
+ Lexer lexer;
+
+ int error () {
+ throw std::runtime_error("Invalid Syntax");
+ }
+
+ void eat (TokenType type){
+ if (current_token->type == type){
+ delete current_token;
+ current_token = lexer.get_next_token();
+ }else
+ error();
+ }
+
+ int factor(){
+
+ int ret;
+ std::string res;
+
+ switch(current_token->type){
+ case _INTEGER:
+ res = current_token->value;
+ eat(_INTEGER);
+ ret = std::stoi(res);
+ break;
+ case _LPAREN:
+ eat(_LPAREN);
+ ret = expr();
+ eat(_RPAREN);
+ break;
+ default:
+ error();
+ }
+
+ return ret;
+ }
+
+ int term(){
+
+ int result = factor();
+
+ while((current_token->type == _MUL) || (current_token->type == _DIV)){
+
+ Token * tk = current_token;
+ if (tk->type == _MUL){
+ eat(_MUL);
+ result *= factor();
+ }
+ if (tk->type == _DIV){
+ eat(_DIV);
+ result /= factor();
+ }
+ }
+
+ return result;
+ }
+
+
+ public:
+
+ Interpreter(lsbasi::Lexer& lexer): lexer(lexer) {
+ current_token = this->lexer.get_next_token();
+ }
+
+ int expr(){
+
+ int result = term();
+
+ while((current_token->type == _PLUS) || (current_token->type == _MINUS)){
+
+ Token * tk = current_token;
+ if (tk->type == _PLUS){
+ eat(_PLUS);
+ result += term();
+ }
+ if (tk->type == _MINUS){
+ eat(_MINUS);
+ result -= term();
+ }
+ }
+
+ return result;
+ }
+
+ };
+
+};
+
+int main (){
+
+ while(true){
+
+ std::string text;
+ std::cout << "calc> ";
+ std::cin >> text;
+ lsbasi::Lexer lexer(text);
+ lsbasi::Interpreter interpreter(lexer);
+ std::cout << interpreter.expr() << std::endl;
+
+ //ctrl+c to exit
+
+ }
+
+ return 0;
+}
diff --git a/chapter07/interpreter.hpp b/chapter07/interpreter.hpp
new file mode 100644
index 0000000..37e4f7d
--- /dev/null
+++ b/chapter07/interpreter.hpp
@@ -0,0 +1,46 @@
+#include
+#include
+#include
+#include
+#include
+
+namespace lsbasi {
+
+ class Interpreter: public VisitorInterpreter {
+
+ AST *ast;
+ int dispatcher(AST *node){
+ return node->handler(this);
+ }
+
+ int visit(Num *node){
+ return node->value;
+ }
+
+ int visit(BinOp *node){
+ int ret = 0;
+
+ switch(node->token->type){
+ case Token::_PLUS:
+ ret = dispatcher(node->left) + dispatcher(node->right);
+ break;
+ case Token::_MINUS:
+ ret = dispatcher(node->left) - dispatcher(node->right);
+ break;
+ case Token::_MUL:
+ ret = dispatcher(node->left) * dispatcher(node->right);
+ break;
+ case Token::_DIV:
+ ret = dispatcher(node->left) / dispatcher(node->right);
+ break;
+ }
+ return ret;
+ }
+
+ public:
+ Interpreter(AST * ast): ast(ast){}
+ int interpret (){
+ return dispatcher(ast);
+ }
+ };
+};
\ No newline at end of file
diff --git a/chapter07/lexer.hpp b/chapter07/lexer.hpp
new file mode 100644
index 0000000..1e6b15d
--- /dev/null
+++ b/chapter07/lexer.hpp
@@ -0,0 +1,99 @@
+#include
+#include
+#include
+#include
+#include
+
+namespace lsbasi {
+
+ struct Token {
+
+ enum TokenType {
+ _INTEGER,
+ _PLUS,
+ _MINUS,
+ _MUL,
+ _DIV,
+ _RPAREN,
+ _LPAREN,
+ _EOF
+ };
+
+ TokenType type;
+ std::string value;
+ Token(TokenType type, std::string value): type(type), value(value){}
+ };
+
+ class Lexer {
+
+ std::string text;
+ int pos;
+ char current_char;
+
+ int error () {
+ throw std::runtime_error("Invalid character");
+ }
+
+ void advance () {
+ pos++;
+ if (pos > text.size() - 1)
+ current_char = 0;
+ else
+ current_char = text[pos];
+ }
+
+ void skip_whitespace () {
+ while((current_char != 0) && (current_char == ' '))
+ advance();
+ }
+
+ std::string integer () {
+ std::string result;
+ while((current_char != 0) && std::isdigit(current_char)){
+ result += current_char;
+ advance();
+ }
+ return result;
+ }
+
+ public:
+
+ Token * get_next_token () {
+ while(current_char != 0){
+ skip_whitespace();
+ if (std::isdigit(current_char))
+ return new Token (Token::_INTEGER, integer());
+ if (current_char == '+'){
+ advance();
+ return new Token (Token::_PLUS, "+");
+ }
+ if (current_char == '-'){
+ advance();
+ return new Token (Token::_MINUS, "-");
+ }
+ if (current_char == '*'){
+ advance();
+ return new Token (Token::_MUL, "*");
+ }
+ if (current_char == '/'){
+ advance();
+ return new Token (Token::_DIV, "/");
+ }
+ if (current_char == '('){
+ advance();
+ return new Token (Token::_LPAREN, "(");
+ }
+ if (current_char == ')'){
+ advance();
+ return new Token (Token::_RPAREN, ")");
+ }
+ error();
+ }
+ return new Token(Token::_EOF, "");
+ }
+
+ Lexer(std::string text): text(text), pos(0), current_char(text[pos]) {}
+
+ };
+
+};
\ No newline at end of file
diff --git a/chapter07/main.cpp b/chapter07/main.cpp
new file mode 100644
index 0000000..c077382
--- /dev/null
+++ b/chapter07/main.cpp
@@ -0,0 +1,39 @@
+#include
+#include "lexer.hpp"
+#include "parser.hpp"
+#include "printer.hpp"
+#include "interpreter.hpp"
+
+int main (){
+
+ while(true){
+
+ /** Read Input Expression **/
+
+ std::string text;
+ std::cout << "ctrl+c to exit" << std::endl;
+ std::cout << "calc> ";
+ std::cin >> text;
+
+ /** Apply Lexer and Parser, Return AST **/
+
+ lsbasi::Lexer lexer(text);
+ lsbasi::Parser parser(lexer);
+ lsbasi::AST *ast = parser.expr();
+
+ /** Print AST in three different formats **/
+
+ lsbasi::Printer printer(ast);
+ std::cout << printer.print(lsbasi::Printer::_RPN_STYLE) << std::endl;
+ std::cout << printer.print(lsbasi::Printer::_LISP_STYLE) << std::endl;
+ std::cout << printer.print(lsbasi::Printer::_TREE) << std::endl;
+
+ /** Intepret AST **/
+
+ lsbasi::Interpreter interpreter(ast);
+ std::cout << interpreter.interpret() << std::endl;
+
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/chapter07/parser.hpp b/chapter07/parser.hpp
new file mode 100644
index 0000000..e4c268f
--- /dev/null
+++ b/chapter07/parser.hpp
@@ -0,0 +1,147 @@
+/**
+ * Grammar:
+ * expr : term ((PLUS | MINUS) term ) *
+ * term : factor ((MUL | DIV) factor ) *
+ * factor: INTEGER | LPAREN expr RPAREN
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+namespace lsbasi {
+
+ struct VisitorPrint {
+ virtual std::stringstream visit(class Num *ast, int deep) = 0;
+ virtual std::stringstream visit(class BinOp *ast, int deep) = 0;
+ };
+
+ struct VisitorInterpreter {
+ virtual int visit(class Num *ast) = 0;
+ virtual int visit(class BinOp *ast) = 0;
+ };
+
+ struct AST {
+ virtual std::stringstream handler(VisitorPrint * v, int deep) = 0;
+ virtual int handler(VisitorInterpreter * v) = 0;
+ };
+
+ struct Num: public AST {
+ Token * token;
+ int value;
+ Num(Token * token):token(token){
+ value = std::stoi(token->value);
+ }
+ std::stringstream handler(VisitorPrint * v, int deep){
+ return v->visit(this, deep);
+ }
+ int handler(VisitorInterpreter * v){
+ return v->visit(this);
+ }
+ };
+
+ struct BinOp: public AST {
+ AST * left;
+ Token * token;
+ std::string op;
+ AST * right;
+ BinOp(Token * token, AST * left, AST * right): token(token), left(left), right(right), op(token->value){}
+ std::stringstream handler(VisitorPrint * v, int deep){
+ return v->visit(this, deep);
+ }
+ int handler(VisitorInterpreter * v){
+ return v->visit(this);
+ }
+ };
+
+ class Parser {
+
+ Token * current_token;
+ Lexer lexer;
+
+ int error () {
+ throw std::runtime_error("Invalid Syntax");
+ }
+
+ void eat (Token::TokenType type){
+ if (current_token->type == type)
+ current_token = lexer.get_next_token();
+ else
+ error();
+ }
+
+ AST * factor(){
+
+ AST * ast;
+
+ switch(current_token->type){
+ case Token::_INTEGER:
+ ast = new Num(current_token);
+ eat(Token::_INTEGER);
+ break;
+ case Token::_LPAREN:
+ eat(Token::_LPAREN);
+ ast = expr();
+ eat(Token::_RPAREN);
+ break;
+ default:
+ error();
+ }
+
+ return ast;
+ }
+
+ AST * term(){
+
+ AST * ast = factor();
+
+ while((current_token->type == Token::_MUL) || (current_token->type == Token::_DIV)){
+
+ Token * tk;
+ tk = current_token;
+
+ if (current_token->type == Token::_MUL)
+ eat(Token::_MUL);
+
+ if (current_token->type == Token::_DIV)
+ eat(Token::_DIV);
+
+ ast = new BinOp(tk, ast, factor());
+ }
+
+ return ast;
+ }
+
+ public:
+
+ Parser(lsbasi::Lexer& lexer): lexer(lexer) {
+ current_token = this->lexer.get_next_token();
+ }
+
+ AST * expr(){
+
+ AST * ast = term();
+
+ while((current_token->type == Token::_PLUS) || (current_token->type == Token::_MINUS)){
+
+ Token * tk;
+ tk = current_token;
+
+ if (current_token->type == Token::_PLUS)
+ eat(Token::_PLUS);
+
+ if (current_token->type == Token::_MINUS)
+ eat(Token::_MINUS);
+
+ ast = new BinOp(tk, ast, term());
+
+ }
+
+ return ast;
+ }
+
+ };
+};
\ No newline at end of file
diff --git a/chapter07/printer.hpp b/chapter07/printer.hpp
new file mode 100644
index 0000000..04b0bf8
--- /dev/null
+++ b/chapter07/printer.hpp
@@ -0,0 +1,67 @@
+#include
+#include
+#include
+#include
+#include
+
+namespace lsbasi {
+
+ class Printer: public VisitorPrint {
+
+ public:
+
+ enum PRINT_TYPE {
+ _RPN_STYLE,
+ _LISP_STYLE,
+ _TREE
+ };
+
+ private:
+
+ AST *ast;
+ PRINT_TYPE type;
+ std::stringstream dispatcher(AST *node, int deep){
+ return node->handler(this, deep);
+ }
+
+ std::stringstream print_op(BinOp *node, std::string op, int deep){
+ std::stringstream ss;
+ if (type == _LISP_STYLE)
+ ss << "(" << op << dispatcher(node->left, deep).str() << " " << dispatcher(node->right, deep).str() << ")";
+ if (type == _RPN_STYLE)
+ ss << dispatcher(node->left, deep).str() << " " << dispatcher(node->right, deep).str() << op;
+ if (type == _TREE){
+ ss << std::string(deep, ' ');
+ ss << "BinOp(" << op << ")" << std::endl;
+ deep += 2;
+ ss << dispatcher(node->left, deep).str();
+ ss << dispatcher(node->right, deep).str();
+ }
+ return ss;
+
+ }
+
+ std::stringstream visit(Num *node, int deep){
+ std::stringstream ss;
+ if (type == _TREE){
+ ss << std::string(deep, ' ');
+ ss << "Num(" << node->value << ")" << std::endl;
+ }else
+ ss << node->value;
+ return ss;
+ }
+
+ std::stringstream visit(BinOp *node, int deep){
+ std::stringstream ss;
+ ss << print_op(node, node->op, deep).str();
+ return ss;
+ }
+
+ public:
+ Printer(AST * ast): ast(ast){}
+ std::string print (PRINT_TYPE type){
+ this->type = type;
+ return dispatcher(ast, 0).str();
+ }
+ };
+};
\ No newline at end of file