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