├── README.md ├── expression.cpp ├── expression.h ├── main.cpp ├── name.cpp ├── name.h ├── parser.cpp └── parser.h /README.md: -------------------------------------------------------------------------------- 1 | # Tiny_interpretor 2 | Calculater 3 | -------------------------------------------------------------------------------- /expression.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MeditatorE/Tiny_interpretor/f01fe57969c6ce477f21f12755a9d74e52ac4aa0/expression.cpp -------------------------------------------------------------------------------- /expression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #ifndef OOC_ARITHMETIC_EXPRESSION_H_ 5 | #define OOC_ARITHMETIC_EXPRESSION_H_ 6 | 7 | #include "parser.h" 8 | 9 | #include 10 | #include 11 | 12 | 13 | namespace compiler { 14 | 15 | class Expression; 16 | 17 | typedef std::shared_ptr expression_ptr_t; 18 | 19 | class Expression{ 20 | 21 | public: 22 | 23 | const expression_ptr_t left_; 24 | const expression_ptr_t right_; 25 | 26 | virtual double exec() const { return 0; } 27 | virtual ~Expression() {} 28 | Expression() {} 29 | Expression(const expression_ptr_t l, const expression_ptr_t r) : left_(l), right_(r) {} 30 | virtual expression_ptr_t left() { return left_; } 31 | virtual expression_ptr_t right() { return right_; } 32 | virtual std::string op() { return "null"; } 33 | }; 34 | 35 | class AddExpression : public Expression { 36 | public: 37 | AddExpression(const expression_ptr_t l, const expression_ptr_t r) 38 | :Expression(l, r) {} 39 | double exec() const override { return left_->exec() + right_->exec(); } 40 | virtual std::string op() { return "+"; } 41 | private: 42 | }; 43 | 44 | class SubExpression : public Expression { 45 | public: 46 | SubExpression(const expression_ptr_t l, const expression_ptr_t r) : Expression(l, r) {} 47 | double exec()const override { return left_->exec() - right_->exec(); } 48 | virtual std::string op() { return "-"; } 49 | }; 50 | 51 | class MulExpression : public Expression { 52 | public: 53 | MulExpression(const expression_ptr_t &l, const expression_ptr_t &r) :Expression(l, r) {} 54 | double exec() const override { return left_->exec() * right_->exec(); } 55 | virtual std::string op() { return "*"; } 56 | }; 57 | 58 | class DivExpression : public Expression { 59 | public: 60 | DivExpression(const expression_ptr_t & l, const expression_ptr_t & r) :Expression(l, r) {} 61 | double exec() const override { return left_->exec() / right_->exec(); } 62 | virtual std::string op() { return "/"; } 63 | }; 64 | 65 | class ValueExpression : public Expression { 66 | public: 67 | ValueExpression(double value) : value_(value){} 68 | double exec() const override { return value_; } 69 | virtual std::string op() { return std::to_string(value_); } 70 | private: 71 | double value_; 72 | }; 73 | 74 | class MinusExpression : public Expression { 75 | public: 76 | MinusExpression(expression_ptr_t value) : value_(value) {} 77 | double exec() const override { return -1 * value_->exec(); } 78 | virtual std::string op() { return std::to_string(-1*value_->exec()); } 79 | private: 80 | const expression_ptr_t value_; 81 | }; 82 | 83 | 84 | class CompareExpression : public Expression { 85 | using operator_specifier_t = std::string; 86 | 87 | public: 88 | CompareExpression(const expression_ptr_t& l, const expression_ptr_t& r, 89 | const operator_specifier_t operator_str) 90 | :Expression(l, r) { 91 | this->operator_str = operator_str; 92 | } 93 | double exec() const override { 94 | if (operator_str == ">") 95 | return left_->exec() > right_->exec(); 96 | else if (operator_str == "<") 97 | return left_->exec() < right_->exec(); 98 | else if (operator_str == "<=") 99 | return left_->exec() <= right_->exec(); 100 | else if (operator_str == ">=") 101 | return left_->exec() >= right_->exec(); 102 | else 103 | return 0; 104 | } 105 | 106 | virtual std::string op() { return operator_str; } 107 | private: 108 | operator_specifier_t operator_str; 109 | }; 110 | 111 | 112 | class TernaryExpression : public Expression { 113 | 114 | public: 115 | TernaryExpression(const expression_ptr_t judge, const expression_ptr_t l, 116 | const expression_ptr_t r) 117 | :Expression(l, r), judge_(judge) { 118 | } 119 | double exec() const override { 120 | if (judge_->exec() > 0) { 121 | return left_->exec(); 122 | } 123 | else { 124 | return right_->exec(); 125 | } 126 | } 127 | virtual std::string op() { return "?:"; } 128 | private: 129 | const expression_ptr_t judge_; 130 | }; 131 | 132 | class Parser; 133 | 134 | expression_ptr_t factor(Parser &p); 135 | expression_ptr_t sum(Parser &p); 136 | expression_ptr_t product(Parser &p); 137 | expression_ptr_t compare(Parser& p); 138 | expression_ptr_t ternary(Parser& p); 139 | 140 | expression_ptr_t assign(Parser& p); 141 | expression_ptr_t statement(Parser& p); 142 | 143 | void printExpression(expression_ptr_t treenode, int depth = 0); 144 | 145 | } // namespace compiler 146 | 147 | #endif // !OOC_ARITHMETIC_EXPRESSION_H_ -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | // ooc_arithmatic_eval.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 2 | // 3 | 4 | #include "parser.h" 5 | #include "expression.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | int main() 19 | { 20 | using std::string; 21 | 22 | auto source = std::vector{ 23 | string("let complex = 1.48 + + (1>2?1:2) - ( (0.4 * (3+5) < 5) + 5 + 100 ) < 3 ? 1: 2; "), 24 | string("let ba = complex + 3; "), 25 | string("ba * 2.5 + 200 * 4; "), 26 | string("let ba = 300; "), 27 | string("ba - 300 < 0.001; "), 28 | }; 29 | 30 | //for(;;) { 31 | compiler::Parser parser{ source }; 32 | compiler::expression_ptr_t expr; 33 | 34 | try { 35 | for (;;) { 36 | if (parser.MovetoNextToken() != compiler::Parser::END) { 37 | expr = compiler::statement(parser); 38 | std::printf("%.2lf\n", expr->exec()); 39 | //printExpression(expr); 40 | } 41 | else 42 | break; 43 | } 44 | } 45 | catch (std::runtime_error& e) { 46 | std::cerr << "runtime error: " << e.what() << std::endl; 47 | } 48 | catch (...) { 49 | std::cerr << "unexpected error " << std::endl; 50 | } 51 | //Sleep(50); 52 | //} 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /name.cpp: -------------------------------------------------------------------------------- 1 | #include "name.h" 2 | -------------------------------------------------------------------------------- /name.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NAME_H_ 4 | #define NAME_H_ 5 | 6 | #include "parser.h" 7 | #include "expression.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace compiler { 14 | 15 | class Name : public Expression { 16 | 17 | typedef std::string name_str_t; 18 | typedef Parser::TokenType token_t; 19 | 20 | public: 21 | name_str_t name; 22 | token_t token; 23 | Name(name_str_t namestr, token_t tk, const expression_ptr_t r = nullptr) 24 | : Expression(nullptr, r), name(namestr), token(tk) { 25 | 26 | } 27 | virtual double exec() const override { 28 | throw std::runtime_error("this function should not be called."); 29 | } 30 | }; 31 | 32 | class Assign : public Name { 33 | 34 | typedef std::string name_str_t; 35 | typedef Parser::TokenType token_t; 36 | public: 37 | Assign(name_str_t namestr, token_t tk, const expression_ptr_t r) 38 | :Name(namestr, tk, r) { 39 | } 40 | virtual double exec() const override { return this->right_->exec(); } 41 | virtual std::string op() { return "="; } 42 | }; 43 | 44 | } 45 | 46 | 47 | 48 | 49 | #endif // !NAME_H_ 50 | -------------------------------------------------------------------------------- /parser.cpp: -------------------------------------------------------------------------------- 1 | #include "parser.h" 2 | #include "name.h" 3 | 4 | #include 5 | namespace compiler { 6 | Parser::TokenType Parser::MovetoNextToken() noexcept(false) 7 | { 8 | using namespace std; 9 | const char*& bp{ cp_ }; 10 | 11 | while (isspace(*bp)) 12 | bp++; 13 | 14 | if (isdigit(*bp) || *bp == '.') { 15 | number_ = strtod(bp, (char**)&cp_); 16 | token_ = Parser::NUM; 17 | } 18 | // The judgment of the name should be after the judgment of the number, 19 | // because the number is a subset of the name 20 | else if (isalnum(*bp) || *bp == '_') { 21 | int len = strspn(bp, kAlphaNumber); 22 | string name(bp, len); 23 | bp += len; 24 | 25 | token_ = Screen(name); 26 | } 27 | else if (*bp == '<') { 28 | if (*(bp + 1) != 0 && *(bp + 1) == '=') { 29 | token_ = Parser::LE; 30 | bp += 2; 31 | } 32 | else { 33 | token_ = Parser::LT; 34 | bp++; 35 | } 36 | } 37 | else if (*bp == '>') { 38 | if (*(bp + 1) != 0 && *(bp + 1) == '=') { 39 | token_ = Parser::GE; 40 | bp += 2; // >= be sure there is no space between > and = 41 | } 42 | else { 43 | token_ = Parser::GT; 44 | bp++; 45 | } 46 | } 47 | else if (*bp == '=') { 48 | if (*(bp + 1) != 0 && *(bp + 1) == '=') { 49 | token_ = Parser::EQ; 50 | bp += 2; // >= be sure there is no space between > and = 51 | } 52 | else { 53 | token_ = Parser::ASIGN; 54 | bp++; 55 | } 56 | } 57 | 58 | else if (*bp != 0) { 59 | token_ = static_cast(*cp_); 60 | bp++; 61 | } 62 | else { 63 | if (MovetoNextLineIfExist()) 64 | token_ = MovetoNextToken(); 65 | else 66 | { 67 | return Parser::END; 68 | } 69 | } 70 | return token(); 71 | } 72 | 73 | bool Parser::MovetoNextLineIfExist(std::string line) noexcept(false) { 74 | if (++line_num <= source.size() - 1) { 75 | line_ = source.at(line_num); 76 | cp_ = line_.c_str(); 77 | return true; 78 | } 79 | return false; 80 | } 81 | 82 | void Parser::InsertORAssign(compiler_name_ptr_t name) { 83 | symbol_table_.insert_or_assign(name->name, name); 84 | } 85 | 86 | Parser::compiler_name_ptr_t Parser::SearchName(std::string name) { 87 | if (auto f = symbol_table_.find(name); f != symbol_table_.end() && f->second) 88 | return f->second; 89 | else 90 | return nullptr; 91 | } 92 | 93 | Parser::TokenType Parser::Screen(std::string name) noexcept(false) { 94 | name_ = name; 95 | if (auto search = symbol_table_.find(name); search != symbol_table_.end()) { 96 | auto [n, p] = *search; 97 | return static_cast(p->token); 98 | } 99 | // default behaviour, if we haven't meet the name, it should be a name 100 | else { 101 | return Parser::NAME; 102 | } 103 | } 104 | 105 | void Parser::initSymbolTable() { 106 | std::vector names; 107 | names.push_back(std::make_shared( 108 | std::string("let"), Parser::LET)); 109 | 110 | for (auto name : names) { 111 | InsertORAssign(name); 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef OOC_ARITHMETIC_PARSER_H_ 4 | #define OOC_ARITHMETIC_PARSER_H_ 5 | 6 | #include "expression.h" 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace compiler { 16 | 17 | class Name; 18 | 19 | class Parser 20 | { 21 | using token_number_value_t = double; 22 | using compiler_name_ptr_t = std::shared_ptr; 23 | public: 24 | const char* kAlphaNumber = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 25 | "abcdefghijklmnopqrstuvwxyz" 26 | "_" "0123456789"; 27 | 28 | enum TokenType { 29 | MUL = '*', ADD = '+', SUB = '-', Div = '/', STATEMENT_END =';', 30 | END = 0 , LParent = '(', RParent = ')', 31 | GT = '>', LT = '<', EQ = 'e', 32 | QUESTION = '?', COLON=':', 33 | VAR = 'v', GE = 'g', LE = 'c', NUM = 'n', ASIGN = 'a', 34 | LET = 'l', NAME = 'b' 35 | }; 36 | 37 | //Parser(const std::ifstream& _file); 38 | Parser(std::vector s) 39 | :token_(TokenType::END), number_(0), cp_(0), line_(""), source(s) { 40 | 41 | if (source.size() > 0) { 42 | line_ = source.at(line_num); 43 | this->cp_ = this->line_.c_str(); 44 | } 45 | initSymbolTable(); 46 | } 47 | 48 | // when never your call this function, you would get a new token 49 | TokenType token() const { return token_; } 50 | 51 | TokenType PeekToken(int num = 1) { 52 | 53 | auto copy{ *this }; 54 | return copy.MovetoNextToken(); 55 | 56 | } 57 | TokenType& token() { return token_; } 58 | std::string line() { return line_; } 59 | int Index() { return cp_-line_.c_str(); } 60 | std::string name() const { return name_; } 61 | // return a number if the token type is a number type 62 | token_number_value_t number() const { return number_; } 63 | //expression_ptr_t symbol(); 64 | 65 | 66 | 67 | void InsertORAssign(compiler_name_ptr_t name); 68 | compiler_name_ptr_t SearchName(std::string name); 69 | TokenType Screen(std::string name) noexcept(false); 70 | TokenType MovetoNextToken() noexcept(false); 71 | bool MovetoNextLineIfExist(std::string line="") noexcept(false) ; 72 | 73 | private: 74 | 75 | void initSymbolTable(); 76 | 77 | std::vector source; 78 | std::map symbol_table_; 79 | std::string name_; 80 | 81 | const char* cp_; // index of next char 82 | int line_num; // index of current line 83 | std::string line_; // current line 84 | TokenType token_; 85 | token_number_value_t number_;// Valid when token_ is num 86 | }; 87 | 88 | 89 | 90 | #define ErrorMsg(p, fmt) { \ 91 | const int buf_size{ 1024 }; \ 92 | char buffer[buf_size] = { 0 }; \ 93 | std::string invalid_loc(p.Index(), ' '); invalid_loc += '^'; \ 94 | std::snprintf(buffer, buf_size, fmt \ 95 | R"( "%s" )" "\n" \ 96 | R"( %s)" "\n", p.line().c_str(), invalid_loc.c_str()); \ 97 | throw std::runtime_error(buffer); } \ 98 | 99 | //void Parser::MovetoNextLine() { 100 | // 101 | //} 102 | 103 | 104 | #endif // OOC_ARITHMETIC_PARSER_H_ 105 | 106 | } --------------------------------------------------------------------------------