/*
* vertical [ very tiny calculator ]
*
* a basic calculator, GPL (General Public License)
*
* compile with -lreadline (or cf l274)
*
* http://submoon.freeshell.org/en/vertical/
*
* Little Neo, 2004-2005
*
*/
#include <iostream>
#include <readline/readline.h>
#include <readline/history.h>
#include <cmath>
using namespace std;
#define LG_MAX 1024
class tree;
tree *plant_tree (char *s, int length);
bool rpn=false;
const double c_INF=HUGE_VAL; // infinite
const double c_PI=M_PI; // circumference/diameter ratio
const double c_C=3e8; // celerity of light
const double c_MZ=c_PI*4e-7; // magnetic permeability
const double c_EZ=8.854e-12; // electric permittivity
const double c_H=6.6262e-34; // Planck's constant
const double c_HB=c_H/(2*c_PI); // reduced Planck's constant
const double c_KB=1.380662e-23; // Boltzmann's constant
const double c_NA=6.02e23; // Avogadro's constant
const double c_F=96320; // Faraday's number
const double c_R=8.314; // ideal gases' constant
const double c_Q=1.60219e-19; // proton's charge
const double c_ME=9.10956e-31; // electron's mass
const double c_MP=1.67261e-27; // proton's mass
const double c_MN=1.67492e-27; // neutron's mass
const double c_AZ=.529177e-10; // Bohr's radius
const double c_RY=1.0973731e3; // Rydberg's constant
const double c_EV=c_Q; // electron-volt
const double c_MB=9.2741e-24; // Bohr's magneton
const double c_MNU=5.051e-27; // nuclear magneton
const double c_A=1/137.036; // structure contant
const double c_WC=2.9e-3; // Wien's constant
const double c_S=5.67e-8; // Stefan's constant
const double c_G=6.672e-11; // gravitation's constant
const double c_D=M_PI/180; // degree
double u_id(double x){return x;}
double u_uminus(double x){return -x;}
double u_cos(double x){return cos(x);}
double u_sin(double x){return sin(x);}
double u_tan(double x){return tan(x);}
double u_cotan(double x){return 1/tan(x);}
double u_atan(double x){return atan(x);}
double u_acos(double x){return acos(x);}
double u_asin(double x){return asin(x);}
double u_ch(double x){return cosh(x);}
double u_sh(double x){return sinh(x);}
double u_th(double x){return tanh(x);}
double u_coth(double x){return 1/tanh(x);}
double u_ach(double x){return acosh(x);}
double u_ash(double x){return asinh(x);}
double u_ath(double x){return atanh(x);}
double u_sinc(double x){return x?sin(x)/x:1;}
double u_ln(double x){return log(x);}
double u_exp(double x){return exp(x);}
double u_log(double x){return log10(x);}
double u_log2(double x){return log2(x);}
double u_sqrt(double x){return sqrt(x);}
double u_cbrt(double x){return cbrt(x);}
double u_abs(double x){return fabs(x);}
double u_sgn(double x){return x?(x>0?1:-1):0;}
double u_floor(double x){return floor(x);}
double u_ceil(double x){return ceil(x);}
double u_fact(double x){return x<1?x:x*u_fact(x-1);}
double u_gamma(double x){return tgamma(x);}
double u_erf(double x){return erf(x);}
double b_ulx(double x, double y){return fmax(x,y);}
double b_lln(double x, double y){return fmin(x,y);}
double b_err(double x, double y){return abs(x-y)/y*100;}
double b_plus(double x, double y){return x+y;}
double b_minus(double x, double y){return x-y;}
double b_times(double x, double y){return x*y;}
double b_on(double x, double y){return x/y;}
double b_mod(double x, double y){return fmod(x,y);}
double b_pow(double x, double y){return pow(x,y);}
double b_pow10(double x, double y){return x*pow10(y);}
char *Dct[]={"INF","PI","C","MZ","EZ","H","HB","KB","NA","F","R","Q","ME","MP","MN","AZ",
"RY","EV","MB","MNU","A","WC","S","G","D",NULL};
char *Dop1[]={"+","-","cos","sin","tan","cotan","atan","acos","asin","ch","sh","th","coth","ach",
"ash","ath","sinc","ln","exp","log","logb","sqrt","cbrt","abs","sgn","floor",
"ceil","fact","gamma","erf",NULL};
char Dop2[]={'>','<','~','+','-','|','*','/','%','^','#',0};
const double *Nct=&c_INF;
double (*Nop1[])(double)={u_id,u_uminus,u_cos,u_sin,u_tan,u_cotan,u_atan,u_acos,u_asin,u_ch,u_sh,
u_th,u_coth,u_ach,u_ash,u_ath,u_sinc,u_ln,u_exp,u_log,u_log2,u_sqrt,u_cbrt,
u_abs,u_sgn,u_floor,u_ceil,u_fact,u_gamma,u_erf};
double (*Nop2[])(double,double)={b_ulx,b_lln,b_err,b_plus,b_minus,b_on,b_times,b_on,b_mod,b_pow,b_pow10};
class tree{
public:
char *s;
double val; // value here
};
class a_u:public tree{
public:
int num;
tree *o;
a_u(int _num, tree *_o):num(_num),o(_o){
val=Nop1[num](o->val); if (num && rpn) cout << Dop1[num] << ' ';
};
};
class a_b:public tree{
public:
int num;
tree *g;
tree *d;
a_b(int _num, tree *_g, tree *_d):num(_num),g(_g),d(_d){
val=Nop2[num](g->val,d->val); if (rpn) cout << Dop2[num] << ' ';
};
};
class f_n:public tree{
public:
f_n(char *_s, int nbchar){
s=new char[nbchar+1];
for (int i=0; i<nbchar; i++) s[i]=_s[i]; // ~ strcpy
s[nbchar]=0;
};
};
class ent:public f_n{
public:
int e;
ent(char *_s, int nbchar):f_n(_s,nbchar){
e=atoi(s);
val=(double)e;
if (rpn) cout << e << ' ';
};
};
class deci:public f_n{
public:
float d;
deci(char *_s, int nbchar):f_n(_s,nbchar){
d=atof(s);
val=(double)d;
if (rpn) cout << d << ' ';
};
};
class f_cte:public tree{
public:
int num;
double c;
f_cte(int num){
c=Nct[num];
val=c;
if (rpn) cout << Dct[num] << ' ';
};
};
bool _dg (char c){return c>='0'&&c<='9'||c=='.';}
bool _ul (char c){return c>='A'&&c<='Z';}
bool _ll (char c){return c>='a'&&c<='z';}
bool _sy (char c){bool sy=false; for (int i=0; Dop2[i]; i++) if (c==Dop2[i]) sy=true; return sy;}
tree *plant_tree (char *s, int length){
int start=0,length2=length; // spaces killer
for (char *p=s; *p==' '; p++) {start++; length2--;}
for (char *p=s+length-1; *p==' '; p--) length2--;
if (length2<=0) return NULL;
if (length2!=length) return plant_tree(s+start,length2);
int par=0,prem0=-1,prem1=-1;
int *imb=new int[length]; // parenthesis manager
for (int c=0,par=0; c<length&&par!=-1; c++){
if (s[c]=='(') par++;
if (s[c]==')') par--;
imb[c]=par;
if (par==0&&prem0==-1) prem0=c;
if (par==1&&prem1==-1) prem1=c;
}
if (par) return NULL;
if (length>1&&prem0==length-1) return plant_tree(s+1,length-2); // (...)
for (int i=0; Dop2[i]; i++)
for (int c=length-2; c+1; c--){
int mi=0; // implicit mult. flag
if (i&&Dop2[i-1]=='*'){
int fns=1; // 1st forwards char != ' '
while (s[c+fns]==' ') fns++;
if (!imb[c]&&c<length-1&&(s[c]==')'&&!_sy(s[c+fns])
||_dg(s[c])&&(_ll(s[c+fns])||_ul(s[c+fns])||s[c+fns]=='(')
||_ul(s[c])&&(_dg(s[c+fns])||s[c+fns]=='('))){
mi++; i--;
}
}
if (!imb[c]&&s[c]==Dop2[i]||mi){ // binary op
if (s[c]=='+'||s[c]=='-'){
int fns=1; // 1st backwards char != ' '
while (s[c-fns]==' ') fns++;
if (!(s[c-fns]==')'||_dg(s[c-fns])||_ul(s[c-fns])))
continue; // unary + and - -> later
}
tree *a1=plant_tree(s, c+mi);
tree *a2=plant_tree(s+c+1, length-c-1);
return a1&&a2?new a_b(i, a1, a2):NULL;
}
}
if (_ll(*s)||*s=='+'||*s=='-'){ // lowercase letter, + or -
int lg=1;
while(lg<6&&_ll(s[lg])) lg++;
for (;lg;lg--)
for (int i=0; Dop1[i]; i++) // unary op
for (int letter=0; letter<lg&&Dop1[i][letter]; letter++){
if (s[letter]!=Dop1[i][letter]) break;
if (letter+1==lg) {
tree *a=plant_tree(s+lg,length-lg);
return a?new a_u(i,a):NULL;
}
}
return NULL;
}
if (_ul(*s)){ // upercase letter
int lg=1;
while(lg<4&&_ul(s[lg])) lg++;
for (int i=0; Dct[i]; i++) // constant
for (int letter=0; letter<lg&&Dct[i][letter]; letter++){
if (s[letter]!=Dct[i][letter]) break;
if (letter+1==length&&!Dct[i][letter+1])
return new f_cte(i);
}
return NULL;
}
if (_dg(*s)){ // digit
int lg=1;
bool dot = *s=='.';
while (_dg(s[lg])){
if (s[lg]=='.'){ // dot
if (dot) return NULL;
dot=true;
}
lg++;
}
if (lg!=length) return NULL; // nothing else ?
if (dot)
return new deci(s, lg);
else
return new ent(s, lg);
}
return NULL;
}
int main(int argc, char *argv[]){
if (argc>=2){
if (!strcmp(argv[1], "-v")){
cout << "vertical v0.1 by Little Neo, 2004-2005\n";
return 0;
}
else if (argc>=2 && !strcmp(argv[1], "-r")) {rpn=true; argc--; argv[1]=argv[2];}
}
using_history();
do{
static bool cr=true;
static int deb=0;
if (deb==50) {cout << "\n You are too stressed :) exiting...\n"; break;} // anti-crash
// to compile without libreadline
char *entry=(argc>=2?argv[1]:readline("\n? ")); // comment this
// cin.getline(entry,LG_MAX); // and uncomment that
if (!entry) {entry = 0; cout << "\033[A\033[A"; deb++; continue;} // man 5 terminfo (good luck)
if (!entry[0]) {cout << "\033[A\033[A"; strncpy (entry, "\0", 2); deb++; continue;}
deb=0;
if (entry[0]=='q' && !entry[1]) break;
add_history (entry);
if (entry[0]=='/'&&entry[1]=='/') {cout << "\033[1K"; continue;} // quiet comment
if (entry[0]=='/'&&entry[1]=='>'&&entry[2]) {cout << entry << '\n'; continue;} // displayed comment
if (entry[0]=='>'&&entry[1]=='>'&&entry[2]) {cout << entry << '\n'; entry+=2;} // displayed and computed
int le=0; // length
while (entry[le]) le++;
cr=true;
if (rpn) cout << "RPN : ";
tree *sequoia=plant_tree(entry, le); // tree
if (rpn) cout << endl;
if (!sequoia) {cout << "Hey, syntax error...\n"; continue;}
cout << (argc==1?" => ":"") << (float)sequoia->val << endl; // fruit
if (sequoia) delete(sequoia);
} while (argc==1);
if (argc==1)cout << "\nSee you !\n\n"; // the end...
}
Little Neo + code2html, 2005
vertical
Accueil