Skip to content

Instantly share code, notes, and snippets.

@123Daoxyz
Last active December 21, 2015 02:09
Show Gist options
  • Save 123Daoxyz/6232863 to your computer and use it in GitHub Desktop.
Save 123Daoxyz/6232863 to your computer and use it in GitHub Desktop.
a calculator interpretor,referenced from <Programming:Principles and Practice Using C++ >.
/* Calculation:
* Statement
* Print
* 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