-
Jul 4th, 2020, 02:41 PM
#1
Thread Starter
Fanatic Member
Simple rpn calculator
Hi, this is a simple reverse polish notation calulator in C it takes the input as postfix and and shows the result. this is very basic code I not added any functions but I may do in time. One rule of the code is that all numbers and operators must be seperated by a space. Anyway hope you find it intresting if you like more information on RPN you can check out https://en.wikipedia.org/wiki/Reverse_Polish_notation
Code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAX_EXPR 1024
#define MAX_TOKEN 30
#define MAX_STACK 100
#define TRUE 1
#define FALSE 0
//Points to top of stack.
int st =-1;
//Stack holds the values.
float STACK[MAX_STACK] = {0.0};
int is_num(char *src){
//Function to test if we have a number works for decimal places
int x = 0;
int ok = TRUE;
while(x < strlen(src)){
//Test for digit or dot
if(!isdigit(src[x]) && src[x] != '.'){
ok = FALSE;
break;
}
x++;
}
return ok;
}
int is_op(char op){
if(op == '+' || op == '-' ||
op == '*' || op == '/'){
return TRUE;
}
return FALSE;
}
void Push(float v){
STACK[++st] = v;
}
float Pop(){
return STACK[st--];
}
float calc_rpn(char *expr){
char zToken[MAX_TOKEN];
char src[MAX_EXPR];
float a = {0.0};
float b = {0.0};
int x = 0;
int y = 0;
st = -1;
//Make a copy of expr
strcpy(src,expr);
//Append last space so the string will split properly and not miss the end of the string.
strcat(src," ");
while(x < strlen(src)){
//Check for space
if(src[x] == ' '){
//Zap end of string.
zToken[y] = '\0';
//Check for number.
if(is_num(zToken) == TRUE){
//Push the number onto the stack
Push(atof(zToken));
}else{
//Process operators
switch(zToken[0]){
case '+':
a = Pop();
b = Pop();
Push(b+a);
break;
case '-':
a = Pop();
b = Pop();
Push(b-a);
break;
case '*':
a = Pop();
b = Pop();
Push(b*a);
break;
case '/':
a = Pop();
b = Pop();
Push(b/a);
break;
}
}
//Reset y
y = 0;
}else{
//Build string buffer.
zToken[y] = src[x];
//INC string buffer index
y++;
}
x++;
}
//Clear up
memset(zToken,0,sizeof zToken);
memset(src,0,sizeof src);
//Pop off result.
return Pop();
}
int main()
{
//5 + 5 / (5 * 3) + 120 - (4+8)
float c = calc_rpn("5 5 5 3 * / + 120 + 4 8 + -");
//Print result
printf("%f\n",c);
//Clear stack
memset(STACK,0,sizeof STACK);
return 0;
}
-
Jul 13th, 2020, 03:38 PM
#2
Thread Starter
Fanatic Member
Re: Simple rpn calculator
Here is a new update of my RPN calulator a lot of chnages now supports Functions and Variables hope you like the update.
Code:
// RPN Calculator with mathematical functions and variables
// By Ben a.k.a DreamVB
// Feel free to use modify this code as you wish.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#define MAX_EXPR 2048
#define MAX_TOKEN 30
#define MAX_STACK 256
#define MAX_VARS 50
#define TRUE 1
#define FALSE 0
//Points to top of stack.
int st = -1;
//Stack holds the values.
double STACK[MAX_STACK] = {0.0};
enum tok_types{
DIGIT = 1,
OP = 2,
STR = 3,
EOP = 4
};
int pos = 0;
int tok_type = 0;
char Token[MAX_TOKEN] = {0.0};
char Expr[MAX_EXPR] = {'\0'};
struct t_variable {
char vName;
double value;
};
int var_count = 0;
struct t_variable variables[MAX_VARS];
int is_op(char op);
void GetToken();
void add_var(char vn, double value){
//Add a new variable name
variables[var_count].vName = vn;
//Add variable value
variables[var_count].value = value;
//INC variable counter
var_count++;
}
void UCase(char *s){
//Just upper-case a string.
while(*s){
*s = toupper(*s);
s++;
}
}
int var_index(char *v){
int x = 0;
int idx = -1;
//This checks of v is in variables[n]
while(x < var_count){
//Check for variable name
if(v[0] == variables[x].vName){
//Store the found index
idx = x;
break;
}
x++;
}
//Return index
return idx;
}
void GetToken(){
//RPN calulator lexer
int t = 0;
tok_type = 0;
//Check if at end of expression
if(pos >= strlen(Expr)){
//Set token type to EOP
tok_type = EOP;
}
//Skip over white spaces
while(isspace(Expr[pos])){
//INC counter
pos++;
}
//Check for digit or dots
if(isdigit(Expr[pos]) || Expr[pos] == '.'){
//Grab all the digits
while(isdigit(Expr[pos]) || Expr[pos] == '.'){
//Build token
Token[t] = Expr[pos];
t++;
pos++;
}
//Zap end of token
Token[t] = '\0';
//Set token type to digit
tok_type = DIGIT;
//Check for operators
}if(is_op(Expr[pos])){
while(is_op(Expr[pos])){
//Build token
Token[t] = Expr[pos];
pos++;
t++;
}
//Set token type to operator
tok_type = OP;
//Zap end of token
Token[t] = '\0';
//Check for alpha
}else if(isalpha(Expr[pos])){
while(isalpha(Expr[pos])){
//Build token
Token[t] = Expr[pos];
t++;
pos++;
}
//Zap end of token
Token[t] = '\0';
//Set token type to string
tok_type = STR;
}
}
int is_op(char op){
//Tests for an operator
if(op == '+' || op == '-' ||
op == '*' || op == '/' ||
op == '%'){
return TRUE;
}
return FALSE;
}
void Push(double v){
//Push value on stack
STACK[++st] = v;
}
double Pop(){
//Pop value from top of stack
return STACK[st--];
}
double q(double f){
//Return square root
return f*f;
}
int is_math_func(char *f){
//Upper-case token
UCase(Token);
//Check if we have a function name and return true if found.
if(strcmp(f,"SIN") == 0){
return TRUE;
}
if(strcmp(f,"COS") == 0){
return TRUE;
}
if(strcmp(f,"LOG") == 0){
return TRUE;
}
if(strcmp(f,"EXP") == 0){
return TRUE;
}
if(strcmp(f,"SQR") == 0){
return TRUE;
}
if(strcmp(f,"POW") == 0){
return TRUE;
}
//No function so retune false
return FALSE;
}
void mathfunc(char *f){
double a = 0.0;
//Pop of item from stack
a = Pop();
//Upper-case token
UCase(Token);
//Process inbuilt functions
if(strcmp(f,"SIN") == 0){
Push(sin(a));
}
if(strcmp(f,"COS") == 0){
Push(cos(a));
}
if(strcmp(f,"LOG") == 0){
Push(log(a));
}
if(strcmp(f,"EXP") == 0){
Push(exp(a));
}
if(strcmp(f,"SQR") == 0){
Push(q(a));
}
if(strcmp(f,"POW") == 0){
Push(pow(Pop(),a));
}
}
double calc_rpn(char *n){
//RPN parser
double a = 0;
double b = 0;
int vId = 0;
//Make a copy of the expression
strcpy(Expr,n);
//Get first token
GetToken();
//While not EOP get and process the tokens
while(tok_type != EOP){
//Check for digit tokens
if(tok_type == DIGIT){
//Push value on top of the stack
Push(atof(Token));
}
//Check for string token
if(tok_type == STR){
//Test if we have a inbuilt math function
if(is_math_func(Token) == TRUE){
//Process maths function
mathfunc(Token);
}
else{
//Must be a variable
//Get variable index
vId = var_index(Token);
//Check if variable was found
if(vId != -1){
//Push the value of the variable on the stack.
Push(variables[vId].value);
}
}
}
//Process operatos
if(tok_type == OP){
switch(Token[0]){
case '+':
//Pop of the top two items on the stack
a = Pop();
b = Pop();
//Push the result back onto the stack
Push(b+a);
break;
case '-':
//Pop of the top two items on the stack
a = Pop();
b = Pop();
//Push the result back onto the stack
Push(b-a);
break;
case '*':
//Pop of the top two items on the stack
a = Pop();
b = Pop();
//Push the result back onto the stack
Push(b*a);
break;
case '%':
//Pop of the top two items on the stack
a = Pop();
b = Pop();
if(a != 0.0){
//Push the result back onto the stack
Push(fmod(b,a));
}else{
printf("Division By Zero.\n");
}
break;
case '/':
//Pop of the top two items on the stack
a = Pop();
b = Pop();
if(a != 0.0){
//Push the result back onto the stack
Push(b/a);
}
else{
printf("Division By Zero.\n");
}
break;
}
}
//Get next token.
GetToken();
}
//Pop of the result from the stack.
return Pop();
}
int main()
{
//Add variables
add_var('A',120);
add_var('B',5);
//Expression to calulate
double c = calc_rpn("B 5 5 3 * / + A + 4 8 + -");
//Print result
printf("%lf\n",c);
//Clear stack
memset(STACK,0,sizeof STACK);
return 0;
}
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|