Aereshaa's Stack-based Calculator.
CHANGE LOG
Sun Aug 31 18:14:58 EDT 2008
First release. Lots of features missing, no error checking.
Issues:
No error checking, therefore misuse of Z or z commands can cause memory leaks or segfaults.
There's no way to put string inside string; will fix this next release.
While loops are shoddy.
LANGUAGE: C
TESTED SYSTEMS: Ubuntu Linux
LICESNSE: Giftware
PRICE: Free
This is a calculator program I've been working on for a bit (like 5 hours over two days). It is fast, and interprets the code on a character, rather than line or word, basis. It uses a simple stack. This code is gift-ware: that is, you are free to do whatever. You may use, modify, redistribute, and generally hack it about in any way you like, and you do not have to give me anything in return. However, questions and comments would be nice!
/* calcu.c */
#include "stack.h"
#include "stdio.h"
#include "time.h"
#include "vlstr.h"
#define MD_NORM 'i'
#define MD_CHAR 'c'
#define MD_NPCR 'C'
#define MD_NUMR 'n'
#define MD_XPER 'x'
#define MD_COMM '\\'
#define MD_STRN 's'
#define MD_ESCP 'E'
#define ERR_BADMODE 1
#define ERR_NOCMD 2
int * var;
int * xvar;
int * sta;
int ** s;
char * str;
void execute(int ** st,const char * s);
int interpret(int ** s,const int cmd){
int ret = 0;
if(cmd == EOF)ret = 'x';
if(var[1] == MD_NUMR){
if(cmd >= '0' && cmd <= '9'){
int x = cmd - '0';
int y = st_pop(s);
x += (y * 10);
st_push(s,x);
goto end;
}else{
var[1] = xvar[0];
}
}
if(var[1] == MD_NORM){
if(cmd == 'q')ret = 'x';
else if(cmd >= '0' && cmd <= '9'){
int x = cmd - '0';
st_push(s,x);
xvar[0] = var[1];
var[1] = MD_NUMR;
}
else if(cmd == '+'){
int a = st_pop(s);
int b = st_pop(s);
st_push(s, a + b);
}
else if(cmd == '-'){
int b = st_pop(s);
int a = st_pop(s);
st_push(s, a - b);
}
else if(cmd == '*'){
int a = st_pop(s);
int b = st_pop(s);
st_push(s, a * b);
}
else if(cmd == '/'){
int b = st_pop(s);
int a = st_pop(s);
st_push(s, a / b);
}
else if(cmd == '%'){
int a = st_pop(s);
int b = st_pop(s);
st_push(s, a % b);
}
else if(cmd == 'e'){
int a = st_pop(s);
int b = st_pop(s);
st_push(s, a == b);
}
else if(cmd == '='){
int a = st_pop(s);
int b = st_pop(s);
var[a] = b;
}
else if(cmd == '~'){
int x = st_pop(s);
st_push(s,var[x]);
}
else if(cmd == 'p'){
int x = st_top(s);
printf("%d\n",x);
}
else if(cmd == 'Z'){
str = (char *) st_top(s);
free(str);
st_drop(s);
}
else if(cmd == 'z'){
st_drop(s);
}
else if(cmd == 'd'){
int a = st_top(s);
st_push(s,a);
}
else if(cmd == 'f'){
int a = st_pop(s);
int b = st_pop(s);
st_push(s,a);
st_push(s,b);
}
else if(cmd == 'h'){
if(var[3] == 0)printf("No error occured.\n");
if(var[3] == ERR_BADMODE)printf("The context was invalid: '%c'\n", xvar[2]);
if(var[3] == ERR_NOCMD)printf("'%c' is not a valid command.\n", xvar[2]);
var[3] = 0;
}
else if(cmd == '\''){
xvar[0] = var[1];
var[1] = MD_CHAR;
}
else if(cmd == '{'){
vl_start(&str);
xvar[0] = var[1];
var[1] = MD_STRN;
}
else if(cmd == 'P'){
char * strng = (char *) st_top(s);
puts(strng);
}
else if(cmd == 'x'){
char * strng = (char *) st_pop(s);
execute(s,strng);
st_push(s,(int)strng);
}
else if(cmd == 'w'){
int c = st_pop(s);
switch(c){
case 'q':
puts("q: Quits the interpreter."); break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
puts("0 to 9: Puts that number onto the stack.\nA sequence of numbers like 234 is used to put\nlarger numbers onto the stack."); break;
case '+':
puts("+: Performs addition.\nPops two numbers, Pushes their sum."); break;
case '-':
puts("-: Performs subtraction.\nA way to show how this works is that\n{21-pz} will print 1."); break;
case '*':
puts("*: Performs multiplication.\nPops two numbers, pushes their product."); break;
case '/':
puts("/: Performs division.\nThis is inaccurate due to the integer\nnature of the values.\noperand order is the same as subtraction."); break;
case '%':
puts("/: Performs modulus.\noperand order is the same as subtraction."); break;
case '=':
puts("=: Sets a variable to a value.\n{13'd=} sets variable 'd to 13."); break;
case 'e':
puts("e: Equality test.\nPops two numbers, tests their equality,\nand puts 1 on the stack if they are, 0 if not."); break;
case '~':
puts("~: Gets the value of a variable.\n{'d~} pushes the value of variable 'd ."); break;
case 'p':
puts("p: Prints the number at the top of a stack.\nDoes not pop any numbers.\nUse P for strings."); break;
case 'd':
puts("d: Duplicates the number at the top of the stack.\nDo not use on strings, or weird stuff wil happen."); break;
case 'w':
puts("w: Prints documentation for a command.\nPops one number (the commmand.)"); break;
case 'f':
puts("f: Reverses the order of the two numbers\nat the top of the stack.\nOkay for use on strings."); break;
case 'h':
puts("h: Prints an explanation of the last error.\nNot as useful as w."); break;
case '\'':
puts("\': Pushes the ascii value of following character."); break;
case '{':
puts("{: Begins a string, which continues until the matching }."); break;
case 'P':
puts("P: Prints a string.\nDoes not pop anything."); break;
case 'z':
puts("z: Pops a number off the stack.\nDo not use on strings, unless\nyou want a memory leak."); break;
case 'Z':
puts("Z: Pops a string and frees it.\nDo not use on integers, unless\nyou want a segfault."); break;
case 'x':
puts("x: Pops a string, executes it, and pushes it back on."); break;
default:
puts(" Either I haven't written documentation for\nthat command, or it doesn't exist."); break;
}
}
else if(cmd == '?'){
char * strng = (char *) st_pop(s);
if(var[4])execute(s,strng);
st_push(s,(int)strng);
}
else if(cmd == '@'){
char * strng = (char *) st_pop(s);
int a = st_top(s);
while(var[4])execute(s,strng);
st_push(s,(int)strng);
}
else if(cmd == '\n')xvar[1] = 1;
else if(cmd == '\\'){
xvar[0] = var[1];
var[1] = MD_COMM;
}
else if(cmd == ' ');
else{
putchar('?');
xvar[2] = cmd;
var[3] = ERR_NOCMD;
}
goto end;
}
if(var[1] == MD_CHAR){
st_push(s,cmd);
var[1] = xvar[0];
goto end;
}
if(var[1] == MD_STRN){
if(cmd == '}'){
var[1] = xvar[0];
xvar[1] = 1;
st_push(s,(int)str);
}else{
vl_add(&str,cmd);
}
goto end;
}
if(var[1] == MD_COMM){
if(cmd == '\n'){
var[1] = xvar[0];
xvar[1] = 1;
}
goto end;
}
putchar('?');// Bad Mode? WTF.
var[3] = ERR_BADMODE;
xvar[2] = var[1];
var[1] = MD_NORM;
end:
return ret;
}
void execute(int ** st,const char * s){
int i = 0;
int len = strlen(s);
while(i < len){
interpret(st,s[i]);
i++;
}
}
int main(){
s = &sta;
st_make(s);
st_test(s);
var = malloc(256 * sizeof(int));
xvar = malloc(16 * sizeof(int));
var[0] = 256; // size of var array
var[1] = MD_NORM; // interpretation mode
var[2] = '\\'; // prompt
var[3] = 0; // error code
var[4] = 1; // conditionals
xvar[1] = 1; // for prompting
int cmd = 0, ret = 0;
while(ret != 'x'){
if(var[2] && xvar[1]){
putchar(var[2]);
xvar[1] = 0;
}
cmd = getchar();
ret = interpret(s,cmd);
}
st_test(s);
st_dest(s);
}
/* stack.h */
#include "stdio.h"
#include "stdlib.h"
#define slen **s
#define stop *(*s + slen * sizeof(int))
void st_make(int ** s){
*s = malloc(sizeof(int));
slen = 1;
}
int st_size(int ** s){
return slen;
}
void st_push(int ** s, int i){
*s = realloc(*s,sizeof(int) * (slen + 1));
slen = slen + 1;
stop = i;
}
int st_top (int ** s){
return stop;
}
void st_drop(int ** s){
*s = realloc(*s,sizeof(int) * (slen - 1));
slen = slen - 1;
}
int st_pop (int ** s){
int r = st_top(s);
st_drop(s);
return r;
}
void st_dest(int ** s){
free(*s);
}
#undef slen
#undef stop
int st_test(int ** stack){
st_push(stack, 1234);
int ret = 1234 == st_top(stack);
st_drop(stack);
return ret;
}
/* vlstr.h */
#include "string.h"
#include "stdlib.h"
void vl_start(char ** s){
*s = malloc(1);
(*s)[0] = 0;
}
void vl_add(char ** s, char c){
int len = strlen(*s);
*s = realloc(*s,len + 2);
(*s)[len] = c;
(*s)[len + 1] = 0;
}


Sign In
Create Account



Back to top









