#include <stdio.h> #include <ctype.h> #include <string.h> #include "externs.h" #include "softcode.h" int is_sign(char ch) { if(ch != '+' && ch != '-' && ch != '^' && ch != '*' && ch != '/' && ch != '%') { return(0); } return(1); } char *is_math(char *str) { char *p; int num_parentheses = 0; int floating = 0; if(!*str) return(NULL); for(p = str;*p;p++) { if(!isdigit(*p) && *p != '(' && *p != ')' && !is_sign(*p) && *p != '.') { break; } if(is_sign(*p)) /* Reset floating for next number */ floating = 0; /* Check for multiple '.' thingies */ if(*p == '.') { if(floating) return(NULL); floating = 1; } if(*p == '(') num_parentheses++; else if(*p == ')') num_parentheses--; if(num_parentheses < 0) return(NULL); } if(!*p || (p != str && *p == '"')) return((num_parentheses)?NULL:p); return(NULL); } static char *find_innermost_paren(char *str) { char *p, *q; for(p = str, q = p;*p;p++) { if(*p == '(') q = p; else if(*p == ')') break; } return(q); } static float do_power(int num, int exp) { int rv = 1; while(exp-- > 0) rv *= num; return(rv); } static int parse_one(char *str, char *retbuf) { char *p, *b; float op1 = 0, op2 = 0; char buf[4096]; char sign = 0; float answer = 0; for(p = str;*p;p++) { b = buf; if(*p == '-') *b++ = *p++; while(isdigit(*p) || *p == '.') *b++ = *p++; *b = '\0'; op1 = atof(buf); sign = *p++; b = buf; if(*p == '-') *b++ = *p++; while(isdigit(*p) || *p == '.') *b++ = *p++; *b = '\0'; op2 = atof(buf); break; } switch(sign) { case '+': answer = op1+op2; break; case '-': answer = op1-op2; break; case '^': answer = do_power((int)op1, (int)op2); break; case '*': answer = op1*op2; break; case '/': if(op2 == 0) { if(code_ptr) { notify(code_ptr->executor, "ERROR - Division by zero."); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); notify(code_ptr->executor, str); end_program(code_ptr->program, 0); } return(1); } answer = op1/op2; break; case '%': if((int)op2 == 0) { if(code_ptr) { notify(code_ptr->executor, "ERROR - Division by zero."); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); notify(code_ptr->executor, str); end_program(code_ptr->program, 0); } return(1); } answer = (int)op1%(int)op2; } sprintf(retbuf, "%f", answer); return(0); } static char *find_highest_order(char *str) { char *p, *q; int exp = 0; if(strchr(str, '^')) exp = 1; for(p = str, q = str;*p;p++) { if(*p == '-') q = p; else if(isdigit(*p) || *p == '.') q = p; while(isdigit(*p) || *p == '.') p++; if(!is_sign(*p)) return(str); if(*p == '^') return(q); if(*p == '*' || *p == '/' || *p == '%') if(!exp) return(q); } return(str); } static int parse_no_paren(char *str, char *retbuf) { char *p, *q; char buf[4096], buf2[4096], buf3[4096], buf4[4096]; char newstr[4096]; int rv = 0; strcpy(newstr, str); q = p = find_highest_order(newstr); while(*p) { if(!isdigit(*p) && *p != '.' && *p != '-') { syntax_error(); return(1); } if(*p == '-') p++; while(isdigit(*p) || *p == '.') p++; if(!*p) break; if(!is_sign(*p)) { syntax_error(); return(1); } p++; if(!isdigit(*p) && *p != '-' && *p != '.') { syntax_error(); return(1); } if(*p == '-') p++; while(isdigit(*p) || *p == '.') p++; strncpy(buf, q, p-q); *(buf+(p-q)) = '\0'; if(parse_one(buf, buf2)) return(1); strncpy(buf3, newstr, q-newstr); *(buf3+(q-newstr)) = '\0'; strcpy(buf4, p); sprintf(newstr, "%s%s%s", buf3, buf2, buf4); q = p = find_highest_order(newstr); } strcpy(retbuf, newstr); return(rv); } static int has_sign(char *str) { char *p; for(p = str;*p;p++) { if((is_sign(*p) && *p != '-') || *p == '(' || *p == ')') return(1); /* Check for negativity */ if(*p == '-' && p != str && !is_sign(*(p-1))) return(1); } return(0); } static void strip_float(char *str, char *retbuf) { char *p; if(!(p = strchr(str, '.'))) { strcpy(retbuf, str); return; } p++; while(*p && *p != '0') p++; if((!*p || *p == '0') && *(p-1) == '.') p--; strncpy(retbuf, str, p-str); *(retbuf+(p-str)) = '\0'; } int parse_statement(char *statement, char *final) { char buf[4096], buf2[4096]; char buf3[4096]; char *p, *q; strcpy(buf, statement); while(*(p = find_innermost_paren(buf))) { if(*p == '(') extract_char(p); q = p; while(*q && *q != ')') q++; if(!*q && q == p) { syntax_error(); return(1); } if(*q == ')') extract_char(q); strncpy(buf2, p, q-p); *(buf2+(q-p)) = '\0'; if(parse_no_paren(buf2, buf3)) return(1); if(!has_sign(buf)) break; strncpy(buf2, buf, p-buf); *(buf2+(p-buf)) = '\0'; sprintf(buf2+strlen(buf2), "%s%s", buf3, q); strcpy(buf, buf2); } strcpy(final, buf); strip_float(final, buf); strcpy(final, buf); return(0); }