Last active
December 21, 2015 02:09
-
-
Save 123Daoxyz/6232863 to your computer and use it in GitHub Desktop.
a calculator interpretor,referenced from <Programming:Principles and Practice Using C++ >.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Calculation: | |
* Statement | |
* Quit | |
* Calculation Statement | |
* | |
* Statement: | |
* Declaration | |
* Expression | |
* | |
* Declaration: | |
* "let" Name "=" Expression | |
* | |
* Print: | |
* ; | |
* | |
* Quit: | |
* q | |
* | |
* Expression: | |
* Term | |
* Expression + Term | |
* Expression - Term | |
* | |
* Term: | |
* Primary | |
* Term * Primary | |
* Term / Primary | |
* Term % Primary | |
* | |
* Primary: | |
* Number | |
* Name | |
* ( Expression ) | |
* - Primary | |
* + Primary | |
* | |
* Number: | |
* floating-point-literal | |
* | |
* Name: | |
* [a-zA-z]+[a-zA-z0-9~!@!#$%^&*()]* | |
* Input comes from cin through the Token_stream called ts. | |
*/ | |
#include "std_lib_facilities.h" | |
const char number = '8'; | |
const char quit = 'q'; | |
const char print = ';'; | |
const char prompt = '>'; | |
const char result = '='; | |
const char name = 'a'; | |
const char let = 'L'; | |
const string declkey = "let"; | |
class Token; | |
class Token_stream; | |
class Variable; | |
Token get_token(); | |
double expression(); | |
double term(); | |
double primary(); | |
void calculate(); | |
void clean_up_mess(); | |
double get_value(string s); | |
double statement(); | |
double declaration(); | |
double define_name(string,double); | |
class Variable{ | |
public: | |
string name; | |
double value; | |
Variable(string n,double v):name(n),value(v){} | |
}; | |
class | |
Token{ | |
public: | |
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 | |
{ | |
public: | |
Token_stream(); | |
Token get(); | |
void putback(Token t); | |
void ignore(char); | |
private: | |
bool full; | |
Token buffer; | |
}; | |
Token_stream::Token_stream() | |
:full(false),buffer(0) | |
{ | |
} | |
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 print: | |
case quit: | |
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('8',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) | |
//c represent the kind of Token | |
{ | |
//first look in buffer | |
if ( full && c==buffer.kind) { | |
full = false; | |
return; | |
} | |
full = false; | |
//now search input; | |
char ch=0; | |
while(cin>>ch) | |
if ( ch == c) { | |
return; | |
} | |
} | |
Token_stream ts; | |
vector<Variable>var_table; | |
int | |
main() | |
{ | |
try{ | |
//predefine names; | |
define_name("pi",3.141592); | |
define_name("e",2.7182); | |
calculate(); | |
keep_window_open(); | |
return 0; | |
} | |
catch(exception&e){ | |
cerr<<e.what()<<endl; | |
keep_window_open("~~"); | |
return 1; | |
} | |
catch(...){ | |
cerr<<"exception\n"; | |
keep_window_open(); | |
return 2; | |
} | |
} | |
void | |
calculate() | |
{ | |
while(cin) | |
try{ | |
{ | |
cout<<prompt; | |
Token t = ts.get(); | |
while(t.kind == ';') t = ts.get(); | |
if ( t.kind == 'q' ) | |
return; | |
ts.putback(t); | |
cout << result << statement() << endl; | |
} | |
} | |
catch(exception&e){ | |
cerr<< e.what() << endl; | |
clean_up_mess(); | |
} | |
} | |
double | |
statement() | |
{ | |
Token t = ts.get(); | |
switch(t.kind){ | |
case let: | |
return declaration(); | |
default: | |
ts.putback(t); | |
return expression(); | |
} | |
} | |
bool is_declared(string var) | |
{ | |
for (int i = 0; i < var_table.size(); i++) { | |
if (var_table[i].name==var) return true; | |
} | |
return false; | |
} | |
double define_name(string var, double val) | |
{ | |
if ( is_declared(var) ) error(var,"declared twice"); | |
var_table.push_back(Variable(var,val)); | |
return val; | |
} | |
double declaration() | |
{ | |
Token t = ts.get(); | |
if ( t.kind != name) error("name expected in declaration"); | |
string var_name = t.name; | |
Token t2 = ts.get(); | |
if ( t2.kind != '=') error("=missing in declaration of ",var_name); | |
double d = expression(); | |
define_name(var_name,d); | |
return d; | |
} | |
double | |
expression() | |
{ | |
double left = term(); | |
Token t = ts.get(); | |
while ( true ) { | |
switch( t.kind ){ | |
case '+': | |
left += term(); | |
t = ts.get(); | |
break; | |
case '-': | |
left -= term(); | |
t = ts.get(); | |
break; | |
default: | |
ts.putback(t); | |
return left; | |
} | |
} | |
return left; | |
} | |
double | |
term() | |
{ | |
double left = primary(); | |
Token t = ts.get(); | |
while(true){ | |
switch(t.kind){ | |
case '*': | |
left *= primary(); | |
t = ts.get(); | |
break; | |
case '/': | |
{ | |
double d = primary(); | |
if ( d == 0) error("divide by zero"); | |
left /= d; | |
t = ts.get(); | |
break; | |
} | |
case '%': | |
{ | |
//double d =primary(); | |
//int i1 = int(left); | |
//if ( i1 != left) error("left-hand operand of % not int"); | |
//int i2 = int(d); | |
//if (i2 != d) error("right-hand operand of % not int"); | |
//use st lib | |
int i1 = narrow_cast<int>(left); | |
int i2 = narrow_cast<int>(term()); | |
if (i2 == 0) error("%:divide by zero"); | |
left = i1%i2; | |
t = ts.get(); | |
break; | |
} | |
default: | |
ts.putback(t); | |
return left; | |
} | |
} | |
} | |
double | |
primary() | |
{ | |
Token t = ts.get(); | |
switch(t.kind) { | |
case '(': | |
{ | |
double d = expression(); | |
t = ts.get(); | |
if ( t.kind != ')') error("')' expected"); | |
return d; | |
} | |
case number: | |
return t.value; | |
case name: | |
return get_value(t.name); | |
case '-': | |
return -primary(); | |
case '+': | |
return primary(); | |
default: | |
error("primary expected"); | |
} | |
} | |
void clean_up_mess() | |
{ | |
ts.ignore(print); | |
} | |
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 variable",s); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment