Created
November 28, 2021 19:09
-
-
Save rw-r-r-0644/481c91e412873d38b12992c66a6f488c to your computer and use it in GitHub Desktop.
Math expression parser thing from 2/8/2020, working state unknown
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <math.h> | |
typedef enum statement_type statement_type_t; | |
typedef enum operators_op0 operators_op0_t; | |
typedef enum operators_op1 operators_op1_t; | |
typedef enum operators_op2 operators_op2_t; | |
typedef struct statement statement_t; | |
void statementslistfree(statement_t *statements); | |
int parsenum(const char *str, statement_t *out, int *parsed); | |
int parseop(const char *str, statement_t *out, int *parsed); | |
int parsepri(const char *str, statement_t *out, int *parsed); | |
statement_t *statementparse(const char *str, int *parsed); | |
statement_t *statementslistparse(const char *str, int size); | |
int ismathop(statement_t *st); | |
void statementslistcreateimplied(statement_t *statements); | |
double handleop0(statement_t *lo, statement_t *op, statement_t *ro); | |
double handleop1(statement_t *lo, statement_t *op, statement_t *ro); | |
double handleop2(statement_t *lo, statement_t *op, statement_t *ro); | |
void solveops(statement_t *statements, statement_type_t type); | |
double solve(statement_t *statements); | |
double mathexpr(const char *str); | |
enum statement_type | |
{ | |
TYPE_PRI, | |
TYPE_NUM, | |
TYPE_OP0, | |
TYPE_OP1, | |
TYPE_OP2, | |
}; | |
enum operators_op0 | |
{ | |
OP0_ADD, | |
OP0_SUB, | |
}; | |
enum operators_op1 | |
{ | |
OP1_MUL, | |
OP1_DIV, | |
}; | |
enum operators_op2 | |
{ | |
OP2_EXP, | |
}; | |
struct statement | |
{ | |
statement_type_t type; | |
union | |
{ | |
statement_t *pri; | |
operators_op0_t op0; | |
operators_op1_t op1; | |
operators_op2_t op2; | |
double num; | |
} data; | |
statement_t *next; | |
}; | |
void printspc(int count) | |
{ | |
while(count-- > 0) | |
putchar(' '); | |
} | |
void statementslistprintrec(statement_t *statements, int rec) | |
{ | |
for (statement_t *st = statements; st; st = st->next) | |
{ | |
printspc(rec); | |
switch(st->type) | |
{ | |
case TYPE_PRI: | |
{ | |
printf("[TYPE_PRI]\n"); | |
statementslistprintrec(st->data.pri, rec + 3); | |
continue; | |
} | |
case TYPE_NUM: | |
{ | |
printf("[TYPE_NUM] %f\n", st->data.num); | |
continue; | |
} | |
case TYPE_OP0: | |
{ | |
printf("[TYPE_OP0] %s\n", (st->data.op0 == OP0_ADD) ? "+" : "-"); | |
continue; | |
} | |
case TYPE_OP1: | |
{ | |
printf("[TYPE_OP1] %s\n", (st->data.op1 == OP1_MUL) ? "*" : "/"); | |
continue; | |
} | |
case TYPE_OP2: | |
{ | |
printf("[TYPE_OP2] %s\n", "^"); | |
continue; | |
} | |
default: | |
{ | |
printf("[????????]\n"); | |
continue; | |
} | |
} | |
} | |
} | |
void statementslistprint(statement_t *statements) | |
{ | |
statementslistprintrec(statements, 0); | |
} | |
void statementslistfree(statement_t *statements) | |
{ | |
statement_t *st = statements, *pv; | |
while(st) | |
{ | |
pv = st; | |
st = st->next; | |
free(pv); | |
} | |
} | |
/* parse math operators */ | |
int parseop(const char *str, statement_t *out, int *parsed) | |
{ | |
*parsed = 1; | |
switch(*str) | |
{ | |
case '+': | |
{ | |
out->type = TYPE_OP0; | |
out->data.op0 = OP0_ADD; | |
return 1; | |
} | |
case '-': | |
{ | |
out->type = TYPE_OP0; | |
out->data.op0 = OP0_SUB; | |
return 1; | |
} | |
case '*': | |
{ | |
out->type = TYPE_OP1; | |
out->data.op1 = OP1_MUL; | |
return 1; | |
} | |
case '/': | |
{ | |
out->type = TYPE_OP1; | |
out->data.op1 = OP1_DIV; | |
return 1; | |
} | |
case '^': | |
{ | |
out->type = TYPE_OP2; | |
out->data.op2 = OP2_EXP; | |
return 1; | |
} | |
} | |
return 0; | |
} | |
/* parse numbers */ | |
int parsenum(const char *str, statement_t *out, int *parsed) | |
{ | |
double num; | |
if (sscanf(str, "%lf %n", &num, parsed) != 1) | |
return 0; | |
out->type = TYPE_NUM; | |
out->data.num = num; | |
return 1; | |
} | |
/* parse parenthesis */ | |
int parsepri(const char *str, statement_t *out, int *parsed) | |
{ | |
int size, count; | |
if (*str != '(') | |
return 0; | |
for (size = 1, count = 1; count && str[size]; size++) | |
{ | |
if (str[size] == '(') | |
count++; | |
if (str[size] == ')') | |
count--; | |
} | |
out->type = TYPE_PRI; | |
out->data.pri = statementslistparse(str + 1, size - 1 - !count); | |
*parsed = size; | |
return 1; | |
} | |
statement_t *statementparse(const char *str, int *parsed) | |
{ | |
statement_t *st; | |
/* skip whitespaces */ | |
if (*str == ' ') | |
{ | |
*parsed = 1; | |
return NULL; | |
} | |
/* parse statement */ | |
st = malloc(sizeof(statement_t)); | |
if (parseop(str, st, parsed)) | |
return st; | |
if (parsenum(str, st, parsed)) | |
return st; | |
if (parsepri(str, st, parsed)) | |
return st; | |
free(st); | |
*parsed = 1; | |
return NULL; | |
} | |
statement_t *statementslistparse(const char *str, int size) | |
{ | |
statement_t *beg = NULL, *pv = NULL, *st = NULL; | |
int i = 0, parsed = 0; | |
beg = malloc(sizeof(statement_t)); | |
beg->type = TYPE_NUM; | |
beg->data.num = 0.0; | |
pv = malloc(sizeof(statement_t)); | |
pv->type = TYPE_OP0; | |
pv->data.op0 = OP0_ADD; | |
beg->next = pv; | |
for (i = 0; (i < size) && str[i]; i += parsed) | |
{ | |
st = statementparse(&str[i], &parsed); | |
if (!st) | |
continue; | |
pv->next = st; | |
pv = st; | |
} | |
pv->next = NULL; | |
return beg; | |
} | |
int ismathop(statement_t *st) | |
{ | |
return ((st->type == TYPE_OP0) || | |
(st->type == TYPE_OP1) || | |
(st->type == TYPE_OP2)); | |
} | |
/* add implied multiplications for numbers immediatly before and after parenthesis */ | |
int handleimpliedmul(statement_t *st0, statement_t *st1) | |
{ | |
statement_t *new; | |
if (!st0 || !st1) | |
return 0; | |
if (ismathop(st0) || ismathop(st1)) | |
return 0; | |
if ((st0->type != TYPE_PRI) && (st1->type != TYPE_PRI)) | |
return 0; | |
new = malloc(sizeof(statement_t)); | |
new->type = TYPE_OP1; | |
new->data.op1 = OP1_MUL; | |
st0->next = new; | |
new->next = st1; | |
return 1; | |
} | |
/* handle minus used as number negate, rather than operator, without parenthesis */ | |
int handleimpliedneg(statement_t *st0, statement_t *st1, statement_t *st2) | |
{ | |
if (!st0 || !st1 || !st2) | |
return 0; | |
if (!ismathop(st0)) | |
return 0; | |
if ((st1->type != TYPE_OP0) || (st1->data.op0 != OP0_SUB)) | |
return 0; | |
if (st2->type != TYPE_NUM) | |
return 0; | |
st0->next = st2; | |
st2->data.num = -st2->data.num; | |
free(st1); | |
return 1; | |
} | |
void statementslistcreateimplied(statement_t *statements) | |
{ | |
statement_t *st, *pv, *new; | |
statement_t *st0, *st1, *st2, *next; | |
double num; | |
for (st = statements; st; st = st->next) | |
{ | |
st0 = st; | |
st1 = st0 ? st0->next : NULL; | |
st2 = st1 ? st1->next : NULL; | |
if (st->type == TYPE_PRI) | |
statementslistcreateimplied(st->data.pri); | |
if (handleimpliedmul(st0, st1)) | |
continue; | |
if (handleimpliedneg(st0, st1, st2)) | |
continue; | |
} | |
} | |
/* | |
* math operations handling | |
*/ | |
double handleop0(statement_t *lo, statement_t *op, statement_t *ro) | |
{ | |
double num = 0.0; | |
switch (op->data.op0) { | |
case OP0_ADD: | |
{ | |
num = lo->data.num + ro->data.num; | |
break; | |
} | |
case OP0_SUB: | |
{ | |
num = lo->data.num - ro->data.num; | |
break; | |
} | |
} | |
return num; | |
} | |
double handleop1(statement_t *lo, statement_t *op, statement_t *ro) | |
{ | |
double num = 0.0; | |
switch (op->data.op1) | |
{ | |
case OP1_MUL: | |
{ | |
num = lo->data.num * ro->data.num; | |
break; | |
} | |
case OP1_DIV: | |
{ | |
num = lo->data.num / ro->data.num; | |
break; | |
} | |
} | |
return num; | |
} | |
double handleop2(statement_t *lo, statement_t *op, statement_t *ro) | |
{ | |
double num = 0.0; | |
switch (op->data.op2) | |
{ | |
case OP2_EXP: | |
{ | |
num = pow(lo->data.num, ro->data.num); | |
break; | |
} | |
} | |
return num; | |
} | |
/* | |
* handle numeric operations by replacing the | |
* [left number] -> [operator] -> [right number] | |
* set with their [resulting number] | |
*/ | |
void solveops(statement_t *st, statement_type_t type) | |
{ | |
statement_t *st0, *st1, *st2; | |
double num; | |
while(st) | |
{ | |
st0 = st; | |
st1 = st0 ? st0->next : NULL; | |
st2 = st1 ? st1->next : NULL; | |
if ((!st0 || (st0->type != TYPE_NUM)) || | |
(!st1 || (st1->type != type)) || | |
(!st2 || (st2->type != TYPE_NUM))) | |
{ | |
st = st->next; | |
continue; | |
} | |
switch (type) | |
{ | |
case TYPE_OP2: | |
{ | |
num = handleop2(st0, st1, st2); | |
break; | |
} | |
case TYPE_OP1: | |
{ | |
num = handleop1(st0, st1, st2); | |
break; | |
} | |
case TYPE_OP0: | |
{ | |
num = handleop0(st0, st1, st2); | |
break; | |
} | |
}; | |
st0->type = TYPE_NUM; | |
st0->data.num = num; | |
st0->next = st2->next; | |
free(st1); | |
free(st2); | |
} | |
} | |
/* | |
* computes the solution to a list of statements | |
* and returns their result | |
* | |
* statements are handled in the following order: | |
* 1) parenthesis | |
* 2) exponentiation | |
* 3) multiplication, division | |
* 4) addition, subtration | |
* | |
* this function is recursively called to handle parenthesis | |
*/ | |
double solve(statement_t *statements) | |
{ | |
statement_t *st; | |
double num; | |
/* | |
* recursively solve prioritized operation lists and | |
* replace them with the numeric value of the result | |
*/ | |
for (st = statements; st; st = st->next) | |
{ | |
if (st->type == TYPE_PRI) | |
{ | |
num = solve(st->data.pri); | |
statementslistfree(st->data.pri); | |
st->type = TYPE_NUM; | |
st->data.num = num; | |
} | |
} | |
/* | |
* solve maths operations in the described order | |
*/ | |
solveops(statements, TYPE_OP2); | |
solveops(statements, TYPE_OP1); | |
solveops(statements, TYPE_OP0); | |
/* | |
* the list should now contain a single statement, | |
* the numeric value of the final result | |
*/ | |
if (statements->type != TYPE_NUM) | |
{ | |
printf("something went wrong\n"); | |
exit(0); | |
} | |
return statements->data.num; | |
} | |
double mathexpr(const char *str) | |
{ | |
statement_t *statements; | |
double result; | |
statements = statementslistparse(str, strlen(str) + 1); | |
statementslistcreateimplied(statements); | |
result = solve(statements); | |
statementslistfree(statements); | |
return result; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
double result = 0.0; | |
result = mathexpr(argv[1]); | |
printf("result: %g %f\n", result, result); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment