diff --git a/projects/07/calculator/CMakeLists.txt b/projects/07/calculator/CMakeLists.txt index c3bbaf8..14b4d29 100644 --- a/projects/07/calculator/CMakeLists.txt +++ b/projects/07/calculator/CMakeLists.txt @@ -7,6 +7,8 @@ project(${TARGET} LANGUAGES CXX) add_executable( ${TARGET} calculator.cpp + token.cpp + variable.cpp ) install(TARGETS ${TARGET}) diff --git a/projects/07/calculator/calculator.cpp b/projects/07/calculator/calculator.cpp index d1bf53e..f70c992 100644 --- a/projects/07/calculator/calculator.cpp +++ b/projects/07/calculator/calculator.cpp @@ -5,189 +5,8 @@ #include -struct Token -{ - char kind; - double value; - string name; - - Token(char ch) : kind{ch}, value{0} {} - - Token(char ch, double val) : kind{ch}, value{val} {} - - Token(char ch, string id) : kind{ch}, name{id} {} -}; - -class Token_stream -{ - bool full{false}; - Token buffer{'\0'}; - -public: - Token_stream() {} - - Token get (); - void putback (Token t); - - void ignore (char); -}; - -void Token_stream::putback(Token t) -{ - if (full) - error("putback() into a full buffer"); - - buffer = t; - full = true; -} - -constexpr char quit = 'q'; -constexpr char print = ';'; -constexpr char number = '8'; -constexpr char name = 'a'; -constexpr char let = 'L'; - -const string prompt = "> "; -const string result = "= "; -const string declkey = "let"; -const string quitkey = "quit"; - -Token Token_stream::get() -{ - if (full) - { - full = false; - return buffer; - } - - char ch; - cin >> ch; - - switch (ch) - { - case '(': - case ')': - case '+': - case '-': - case '*': - case '/': - case '%': - case print: - case '=': - return Token{ch}; - - case '.': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - cin.putback(ch); - double val; - cin >> val; - return Token{number, val}; - } - - default: - if (isalpha(ch)) - { - string s; - s += ch; - while (cin.get(ch) && (isalpha(ch) || isdigit(ch))) - s += ch; - cin.putback(ch); - - if (s == declkey) - return Token{let}; - - if (s == quitkey) - return Token{quit}; - - return Token{name, s}; - } - error("bad token"); - } -} - -void Token_stream::ignore(char c) -{ - if (full && c == buffer.kind) - { - full = false; - return; - } - full = false; - - for (char ch; cin >> ch;) - { - if (ch == c) - return; - } -} - -struct Variable -{ - string name; - double value; - - Variable(string n, double v) : name{n}, value{v} {} -}; - -vector var_table; - -double get_value (const string& s) -{ - for (const auto& var : var_table) - { - if (var.name == s) - return var.value; - } - - error("get: undefined name ", s); -} - -void set_value (const string& s, double d) -{ - for (auto& var : var_table) - { - if (var.name == s) - { - var.value = d; - return; - } - } - - error("set: undefined name ", s); -} - -bool is_declared (const string& s) -{ - for (const auto& var : var_table) - { - if (var.name == s) - return true; - } - - return false; -} - -double define_name (const string& var, double val) -{ - if (is_declared(var)) - error(var, " declared twice"); - - var_table.push_back(Variable{var, val}); - - return val; -} - -Token_stream ts; +#include "token.h" +#include "variable.h" double expression (); @@ -315,8 +134,6 @@ double statement () } } -void clean_up_mess () { ts.ignore(print); } - void calculate () { while (true) diff --git a/projects/07/calculator/test_ans.txt b/projects/07/calculator/test_ans.txt new file mode 100644 index 0000000..f002515 --- /dev/null +++ b/projects/07/calculator/test_ans.txt @@ -0,0 +1,54 @@ +> = 0 +> = 1 +> = 2 +> = 3 +> = 4 +> = 5 +> = 6 +> = 7 +> = 8 +> = 9 +> = 3 +> = 3 +> = 6 +> = -1 +> = -1 +> = -4 +> = 2 +> = 2 +> = 6 +> = 0.5 +> = 0.5 +> = 0.166667 +> = 7 +> = -5 +> = 1.66667 +> = 0.333333 +> = divide by zero +> = primary expected +> = 3 +> = -3 +> = 3 +> = -3 +> = 3 +> = 10 +> = 21 +> = divide by zero +> = bad token +> = bad token +> = 1 +> = 21 +> = -4.5 +> = 0 +> = 0 +> = 2 +> = 0 +> = 4.2 +> = 3.3 +> = 0.2 +> = 2 +> = 3 +> = 0 +> = 5 +> = 1 +> \ No newline at end of file diff --git a/projects/07/calculator/test_in.txt b/projects/07/calculator/test_in.txt new file mode 100644 index 0000000..037dc66 --- /dev/null +++ b/projects/07/calculator/test_in.txt @@ -0,0 +1,50 @@ +0; 1; 2; 3; 4; 5; 6; 7; 8; 9; + +1 + 2; 1+2; 1 + 2 + 3; +1 - 2; 1-2; 1 - 2 - 3; + +1 * 2; 1*2; 1 * 2 * 3; +1 / 2; 1/2; 1 / 2 / 3; + +1 + 2*3; 1 - 2*3; +1 + 2/3; 1 - 2/3; + +3/0; + +(); +(3); +-(3); ++(3); +(-3); +(+3); +(3+7); +(3*7); + +3 / (3 - 3); + +3 * 4&5; + +93"43-189'3dfrer4734***&340#$%%%8340909909()()*(&)))((( ; + +4 / (2 + 2*1); +1 + 4 * (2 + 3/2*2); + +72 / (10*(9-5) - 7*8); + ++2 - 2; -2 + 2; + +2 % 4; +4 % 2; +4.2 % 8; +3.3 % 6.6; +6.8 % 3.3; + +let x = 2; let q=3; + +x*q - (x * q); + +q + x; + +x/(x + 2*q - q*2); + +quit diff --git a/projects/07/calculator/token.cpp b/projects/07/calculator/token.cpp new file mode 100644 index 0000000..ae6e1c1 --- /dev/null +++ b/projects/07/calculator/token.cpp @@ -0,0 +1,93 @@ +#include "token.h" + +Token_stream ts; + +void Token_stream::putback(Token t) +{ + if (full) + error("putback() into a full buffer"); + + buffer = t; + full = true; +} + +Token Token_stream::get() +{ + if (full) + { + full = false; + return buffer; + } + + char ch; + cin >> ch; + + switch (ch) + { + case '(': + case ')': + case '+': + case '-': + case '*': + case '/': + case '%': + case print: + case '=': + return Token{ch}; + + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + cin.putback(ch); + double val; + cin >> val; + return Token{number, val}; + } + + default: + if (isalpha(ch)) + { + string s; + s += ch; + while (cin.get(ch) && (isalpha(ch) || isdigit(ch))) + s += ch; + cin.putback(ch); + + if (s == declkey) + return Token{let}; + + if (s == quitkey) + return Token{quit}; + + return Token{name, s}; + } + error("bad token"); + } +} + +void Token_stream::ignore(char c) +{ + if (full && c == buffer.kind) + { + full = false; + return; + } + full = false; + + for (char ch; cin >> ch;) + { + if (ch == c) + return; + } +} + +void clean_up_mess () { ts.ignore(print); } \ No newline at end of file diff --git a/projects/07/calculator/token.h b/projects/07/calculator/token.h new file mode 100644 index 0000000..9ad3c8d --- /dev/null +++ b/projects/07/calculator/token.h @@ -0,0 +1,48 @@ +#ifndef TOKEN_H +#define TOKEN_H 1 + +#include + +struct Token +{ + char kind; + double value; + string name; + + Token(char ch) : kind{ch}, value{0} {} + + Token(char ch, double val) : kind{ch}, value{val} {} + + Token(char ch, string id) : kind{ch}, name{id} {} +}; + +class Token_stream +{ + bool full{false}; + Token buffer{'\0'}; + +public: + Token_stream() {} + + Token get (); + void putback (Token t); + + void ignore (char); +}; + +extern Token_stream ts; + +constexpr char quit = 'q'; +constexpr char print = ';'; +constexpr char number = '8'; +constexpr char name = 'a'; +constexpr char let = 'L'; + +const string prompt = "> "; +const string result = "= "; +const string declkey = "let"; +const string quitkey = "quit"; + +void clean_up_mess (); + +#endif // #ifndef TOKEN_H \ No newline at end of file diff --git a/projects/07/calculator/variable.cpp b/projects/07/calculator/variable.cpp new file mode 100644 index 0000000..09b1775 --- /dev/null +++ b/projects/07/calculator/variable.cpp @@ -0,0 +1,49 @@ +#include "variable.h" + +vector var_table; + +double get_value (const string& s) +{ + for (const auto& var : var_table) + { + if (var.name == s) + return var.value; + } + + error("get: undefined name ", s); +} + +void set_value (const string& s, double d) +{ + for (auto& var : var_table) + { + if (var.name == s) + { + var.value = d; + return; + } + } + + error("set: undefined name ", s); +} + +bool is_declared (const string& s) +{ + for (const auto& var : var_table) + { + if (var.name == s) + return true; + } + + return false; +} + +double define_name (const string& var, double val) +{ + if (is_declared(var)) + error(var, " declared twice"); + + var_table.push_back(Variable{var, val}); + + return val; +} \ No newline at end of file diff --git a/projects/07/calculator/variable.h b/projects/07/calculator/variable.h new file mode 100644 index 0000000..5a4afc8 --- /dev/null +++ b/projects/07/calculator/variable.h @@ -0,0 +1,21 @@ +#ifndef VARIABLE_H +#define VARIABLE_H 1 + +#include + +struct Variable +{ + string name; + double value; + + Variable(string n, double v) : name{n}, value{v} {} +}; + +extern vector var_table; + +double get_value (const string& s); +void set_value (const string& s, double d); +bool is_declared (const string& s); +double define_name (const string& var, double val); + +#endif // #ifndef VARIABLE_H \ No newline at end of file