Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <sstream>
- #include <vector>
- #include <cstdlib>
- #include <stdexcept>
- #include <cmath>
- using namespace std;
- //description of errors:
- inline void error(const string& s)
- {
- throw runtime_error(s);
- }
- inline void error(const string& s, const string& s2)
- {
- error(s + s2);
- }
- inline void error(const string& s, int i)
- {
- ostringstream os;
- os << s << ": " << i;
- error(os.str());
- }
- //declaration of Token and it's namespace:
- 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 n) : kind{ ch }, name{ n }
- { }
- };
- 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;
- }
- //declaration of program consants:
- const char quit = 'q';
- const char print = ';';
- const char number = '8';
- const char name = 'a';
- const char let = 'L';
- const string prompt = "> ";
- const string result = "= ";
- const string declkey = "let";
- //working with input:
- Token Token_stream::get()
- {
- if (full)
- {
- full = false;
- return buffer;
- }
- char ch;
- cin >> ch;
- switch (ch)
- {
- case quit:
- case print:
- case '{':
- case '}':
- case '(':
- case ')':
- case '+':
- case '-':
- case '*':
- case '/':
- case '%':
- case '!':
- case '^':
- 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 };
- return Token{ name, s };
- }
- error("Bad token");
- }
- }
- void Token_stream::ignore(char c)
- {
- if (full && c == buffer.kind)
- {
- full = false;
- return;
- }
- full = false;
- char ch;
- while (cin >> ch)
- if (ch == c) return;
- }
- //GLOBAL BLOCK: VARIABLES
- //description of variables:
- struct Variable
- {
- string name;
- double value;
- Variable(string n, double v) : name{ n }, value{ v }
- {}
- };
- //saving variables into Vector:
- vector<Variable> var_table;
- //deal with mistakes and get/set values
- double get_value(string s)
- {
- for (int i = 0; i < var_table.size(); ++i)
- if (var_table[i].name == s)
- return var_table[i].value;
- error("get: undefined name ", s);
- }
- void set_value(string s, double d)
- {
- for (int i = 0; i < var_table.size(); ++i)
- {
- if (var_table[i].name == s)
- {
- var_table[i].value = d;
- return;
- }
- }
- error("set: undefined name ", s);
- }
- bool is_declared(string s)
- {
- for (int i = 0; i < var_table.size(); ++i)
- if (var_table[i].name == s) return true;
- return false;
- }
- //identify variables:
- double define_name(string var, double val)
- {
- if (is_declared(var))
- error(var, " declared twice");
- var_table.push_back(Variable{ var, val });
- return val;
- }
- //GLOBAL BLOCK: CALCULATING
- //to see the description of this algorythm open "calc.txt"
- Token_stream ts;
- double expression();
- double primary()
- {
- Token t = ts.get();
- switch (t.kind)
- {
- case '{':
- {
- double d = expression();
- t = ts.get();
- if (t.kind != '}')
- error("'{' expected");
- return d;
- }
- case '(':
- {
- double d = expression();
- t = ts.get();
- if (t.kind != ')')
- error("'(' expected");
- return d;
- }
- case '-':
- return -primary();
- case '+':
- return +primary();
- case number:
- return t.value;
- case name:
- return get_value(t.name);
- default:
- error("primary expected");
- }
- }
- long double fact()
- {
- double left = primary();
- Token t = ts.get();
- if (t.kind == '!') {
- double intpart;
- double fractpart = modf(left, &fractpart);
- if (left < 0)
- {
- left *= -1;
- for (int i = left - 1; i > 0; --i) left *= i;
- left *= -1;
- }
- else if (left == 0) left = 1;
- else
- for (int i = left - 1; i > 0; --i) left *= i;
- return left;
- }
- else {
- ts.putback(t);
- return left;
- }
- }
- double term()
- {
- double left = fact();
- while (true)
- {
- Token t = ts.get();
- switch (t.kind)
- {
- case '*':
- left *= fact();
- break;
- case '/':
- {
- double d = fact();
- if (d == 0) error("divide by zero");
- left /= d;
- break;
- }
- case '%':
- {
- double d = fact();
- if (d == 0) error("divide by zero");
- left = fmod(left, d);
- break;
- }
- case '^':
- {
- left = pow(left, fact());
- break;
- }
- default:
- ts.putback(t);
- return left;
- }
- }
- }
- double expression()
- {
- double left = term();
- while (true)
- {
- Token t = ts.get();
- switch (t.kind)
- {
- case '+':
- left += term();
- break;
- case '-':
- left -= term();
- break;
- default:
- ts.putback(t);
- return left;
- }
- }
- }
- //again work with variables: declarate and work with errors:
- double declaration()
- {
- Token t = ts.get();
- if (t.kind != name) error("name expected in declaration");
- string var = t.name;
- if (is_declared(var)) error(var, " declared twice");
- t = ts.get();
- if (t.kind != '=') error("'=' missing in declaration of ", var);
- return define_name(var, expression());
- }
- double statement()
- {
- Token t = ts.get();
- switch (t.kind)
- {
- case let:
- return declaration();
- default:
- ts.putback(t);
- return expression();
- }
- }
- void clean_up_mess()
- {
- ts.ignore(print);
- }
- //main function in this program (except main() lol)
- void calculate()
- {
- while (true)
- try
- {
- cout << prompt;
- Token t = ts.get();
- while (t.kind == print)
- t = ts.get();
- if (t.kind == quit) return;
- ts.putback(t);
- cout << result << statement() << endl;
- }
- catch (runtime_error& e)
- {
- cerr << e.what() << endl;
- clean_up_mess();
- }
- }
- int main()
- try
- {
- //define some calculating constants like e and pi and starts CALCULATING:
- define_name("pi", 3.141592653589793);
- define_name("e", 2.718281828459045);
- calculate();
- }
- //return the callback from errors
- catch (exception& e)
- {
- cerr << "exception: " << e.what() << endl;
- return 1;
- }
- catch (...)
- {
- cerr << "Oops, unknown exception" << endl;
- return 2;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement