Mathematica-like environment on the mbed using USB keyboard input, VGA output, and a thermal printer.
Dependencies: mbed Thermal 4DGL-uLCD-SE USBHost_Modified uVGAIII
tree.c
- Committer:
- zrussell3
- Date:
- 2018-12-13
- Revision:
- 6:646d22295054
File content as of revision 6:646d22295054:
#include "tree.h" #include <stdlib.h> #include <stdio.h> #include <math.h> #include <string.h> /* Returns a string for each type of operator */ float eval_node(struct node* node, int level); void set_number_node(struct node* node, float num); /* local variables */ struct node* expr_root_node; float Xvalue; float eval_expr(struct node* node, float x_value) { Xvalue = x_value; return eval_node(node, 0); } float p(float l) { // printf(" op val: %g\n", l); return l; } float eval_op (struct node* op, int level) { float right = eval_node(op->right, level+1); float left = eval_node(op->left, level+1); switch(op->data.op) { case OP_ADD: return p(left + right); case OP_SUB: return p(left - right); case OP_MUL: return p(left * right); case OP_DIV: return p(left / right); case OP_EXP: return p(pow(left,right)); default: fprintf(stderr, "%d not defined as an operator in decode_op_type\n", op->data.op); exit(1); } } void set_root_node(struct node* node) { expr_root_node = node; } float eval_node(struct node* node, int level) { switch(node->type) { case NODE_NUMBER: return node->data.fval; case NODE_VAR: // printf("eval var x: %s\n",node->data.name); // printf("eval var x: %d\n",node->type); // printf("eval var x: %g\n",node->data.fval); if (strcmp(node->data.name,"x")==0) { return Xvalue; } else { fprintf(stderr,"Cannot parse variables: %s\n", node->data.name); exit(1); } case NODE_BINOP: return eval_op(node, level+1); case NODE_FUNC: if (strcmp(node->data.name,"sin")==0) { printf("Calling function: sin(...)\n"); float y = eval_node(node->left, level+1); return sin(y); } if (strcmp(node->data.name,"cos")==0) { printf("Calling function: cos(...)\n"); float y = eval_node(node->left, level+1); return cos(y); } if (strcmp(node->data.name,"tan")==0) { printf("Calling function: tan(...)\n"); float y = eval_node(node->left, level+1); return tan(y); } } exit(1); } struct node* new_number_node(float num){ struct node* node = calloc(sizeof(*node),1); node->type = NODE_NUMBER; node->data.fval = num; node->left = NULL; node->right = NULL; node->parent = NULL; return node; } struct node* new_var_node(char* str){ struct node* node = calloc(sizeof(*node),1); node->type = NODE_VAR; node->data.name = str; node->left = NULL; node->right = NULL; node->parent = NULL; return node; } struct node* new_binop_node(enum op_type op, struct node* left, struct node *right){ struct node* node = calloc(sizeof(*node),1); node->type = NODE_BINOP; node->data.op = op; node->left = left; node->left->parent = node; node->right = right; node->right->parent = node; node->parent = NULL; return node; } struct node* new_binop_node_no_right(enum op_type op, struct node* left){ struct node* node = calloc(sizeof(*node),1); node->type = NODE_BINOP; node->data.op = op; node->left = left; node->left->parent = node; node->right = NULL; node->parent = NULL; return node; } struct node* new_func_node(char* name, struct node* left){ struct node* node = calloc(sizeof(*node),1); node->type = NODE_FUNC; node->data.name = name; node->left = left; node->left->parent = node; node->right = NULL; node->parent = NULL; return node; } struct node* new_func_node_no_left(char* name) { struct node* node = calloc(sizeof(*node),1); node->type = NODE_FUNC; node->data.name = name; node->left = NULL; node->right = NULL; node->parent = NULL; return node; } // Try to match a number token // >0 success // 0 no match // -1 syntax error int isNumber(const char* expr) { int len = strlen(expr); int num_of_dots = 0; int i =0; for (int i=0; i<len; i++) { switch(expr[i]) { // find digit, '.' case '0' ... '9': continue; case '.': num_of_dots++; if (num_of_dots>1) return -num_of_dots; // an error continue; // legal end of match case ' ' : case '\t': case '\n': case '(' : case ')' : case '+' : case '-' : case '*' : case '/' : case '^' : return i; // error end of match default: return -i; } } return i; } int isFunc(const char* expr) { for (int i=0; i<strlen(expr); i++) { switch(expr[i]) { case 'a' ... 'z': case 'A' ... 'Z': case '_': continue; case '(': return i; default: return i==0 ? -1 : -i; } } return -1; } int isVar(const char* expr) { if (strlen(expr)==0) return 0; for (int i=0; i<strlen(expr); i++) { // match var name switch(expr[i]) { case 'a' ... 'z': case 'A' ... 'Z': case '_': continue; // match terminating character case ' ' : case '\t': case '\n': case ')' : case '+' : case '-' : case '*' : case '/' : case '^' : return i; default: return i==0 ? -1 : -i; } } return -1; } // Add right side of OP struct node* add_right(struct node* node, struct node* right){ node->right = right; right->parent = node; return right; } // Add right side of OP struct node* add_left(struct node* node, struct node* left){ node->left = left; left->parent = node; return left; } // Add a Node struct node* add_op(struct node* left, enum op_type op) { struct node* binop = NULL; struct node* parent = NULL; // no precedence ordering required if (left->parent==NULL) { return new_binop_node_no_right(op, left); } // new operation is same or higher precedence, so append as child of branch if (op >= left->parent->data.op) { parent = left->parent; binop = new_binop_node_no_right(op, left); add_right(parent, binop); return binop; } // traverse up the tree until no more parents or parent operation is lower precedence return add_op(left->parent, op); } // scanner and parser struct node* scanner(const char* es) { char buff[200]; int len = strlen(es); struct node* left = NULL; int lookahead = -1; // 0: fails, >0: success for (int i=0; i<len; i++) { switch(es[i]) { // skip space case ' ' : continue; // printf("[space]"); case '\t': continue; // printf("[tab]"); case '\n': continue; // printf("[newline]"); // find number case '0' ... '9': case '.': lookahead = isNumber(&es[i+1]); if (lookahead>=0) { memcpy(buff, &es[i], lookahead+1); buff[lookahead+1] = (char) 0; i = i + lookahead; // printf("token-number: '%s' (atof:%f)\n", buff,atof(buff)); if (left==NULL) { left = new_number_node(atof(buff)); } else if (left->type==NODE_BINOP) { left = add_right(left, new_number_node(atof(buff))); } else if (left->type==NODE_FUNC) { left = add_left(left, new_number_node(atof(buff))); left = left->parent; } } continue; // operators case '+' : // printf("token-add: '%c'\n", es[i]); left = add_op(left, OP_ADD); continue; case '-' : // printf("token-sub: '%c'\n", es[i]); left = add_op(left, OP_SUB); continue; case '*' : // printf("token-mul: '%c'\n", es[i]); left = add_op(left, OP_MUL); continue; case '/' : // printf("token-div: '%c'\n", es[i]); left = add_op(left, OP_DIV); continue; case '^' : // printf("token-exp: '%c'\n", es[i]); left = add_op(left, OP_EXP); continue; case 'a' ... 'z': case 'A' ... 'Z': // find function lookahead = isFunc(&es[i+1]); if (lookahead>=0) { memcpy(buff, &es[i], lookahead+1); buff[lookahead+1] = (char) 0; printf("token-func: '%s'\n", buff); i = i + lookahead; /* if (left==NULL) { left = new_func_node(buff); } else if (left->type==NODE_BINOP) { left = add_right(left, new_func_node(buff)); } */ continue; } // find variable lookahead = isVar(&es[i+1]); if (lookahead>=0) { memcpy(buff, &es[i], lookahead+1); buff[lookahead+1] = (char) 0; // printf("token-var: '%s'\n", buff); i = i + lookahead; if (left==NULL) { left = new_var_node(buff); } else if (left->type==NODE_BINOP) { left = add_right(left, new_var_node(buff)); } continue; } // grouping case '(' : printf("token-l-paren: '%c'\n", es[i]); continue; case ')' : printf("token-r-paren: '%c'\n", es[i]); continue; default: ; } } // find root while (left->parent != NULL) { left = left->parent; } return left; } /* static const char expr_str[] = "5*4 * 3 / 2 - 1 + 37\n"; // compile expression struct node* expr = comp_expr(expr_str); // evaluate expression eval_expr(expr, 1); // some output printf("Expression: %s\n", expr_str); x = 3.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 3.5; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 4.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); // example 2 static const char str2[] = "5*4 * 3 / 2 - x + 37\n"; expr = comp_expr(str2); eval_expr(expr, 1); printf("Expression: %s\n", str2); x = 1.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 3.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 3.5; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 4.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); // example 3 static const char str3[] = "5*4 * 3 / 2 - 1 + 37 + sin(x)\n"; expr = comp_expr(str3); eval_expr(expr, 1); printf("Expression: %s\n", str3); x =-1.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 1.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 3.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 3.5; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 4.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); // example 4 static const char str4[] = "5*4 * 3 / 2 - 1 + 37 + sin(x) + 2^3\n"; expr = comp_expr(str4); eval_expr(expr, 1); printf("Expression: %s\n", str4); x = 1.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 5.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 7.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x = 9.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); x =11.0; printf("Value[x=%2.3g]: %2.3g\n", x, eval_expr(expr, x)); */