/*
 * 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