diff options
Diffstat (limited to 'Source/Parser/wp_parser_y.c')
-rw-r--r-- | Source/Parser/wp_parser_y.c | 1082 |
1 files changed, 1082 insertions, 0 deletions
diff --git a/Source/Parser/wp_parser_y.c b/Source/Parser/wp_parser_y.c new file mode 100644 index 000000000..c4815a2a9 --- /dev/null +++ b/Source/Parser/wp_parser_y.c @@ -0,0 +1,1082 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <math.h> +#include "wp_parser_y.h" +#include "wp_parser.tab.h" + +static struct wp_node* wp_root = NULL; + +/* This is called by a bison rule to store the original AST in a + * static variable. Accessing this directly is not thread safe. So + * this will be duplicated later for each thread. + */ +void +wp_defexpr (struct wp_node* body) +{ + wp_root = body; +} + +struct wp_node* +wp_newnumber (double d) +{ + struct wp_number* r = malloc(sizeof(struct wp_number)); + r->type = WP_NUMBER; + r->value = d; + return (struct wp_node*) r; +} + +struct wp_symbol* +wp_makesymbol (char* name) +{ + struct wp_symbol* symbol = malloc(sizeof(struct wp_symbol)); + symbol->type = WP_SYMBOL; + symbol->name = strdup(name); + symbol->pointer = NULL; + return symbol; +} + +struct wp_node* +wp_newsymbol (struct wp_symbol* symbol) +{ + return (struct wp_node*) symbol; +} + +struct wp_node* +wp_newnode (enum wp_node_t type, struct wp_node* l, struct wp_node* r) +{ + struct wp_node* tmp = malloc(sizeof(struct wp_node)); + tmp->type = type; + tmp->l = l; + tmp->r = r; + return tmp; +} + +struct wp_node* +wp_newf1 (enum wp_f1_t ftype, struct wp_node* l) +{ + struct wp_f1* tmp = malloc(sizeof(struct wp_f1)); + tmp->type = WP_F1; + tmp->l = l; + tmp->ftype = ftype; + return (struct wp_node*) tmp; +} + +struct wp_node* +wp_newf2 (enum wp_f2_t ftype, struct wp_node* l, struct wp_node* r) +{ + struct wp_f2* tmp = malloc(sizeof(struct wp_f2)); + tmp->type = WP_F2; + tmp->l = l; + tmp->r = r; + tmp->ftype = ftype; + return (struct wp_node*) tmp; +} + +void +yyerror (char const *s, ...) +{ + va_list vl; + va_start(vl, s); + vfprintf(stderr, s, vl); + fprintf(stderr, "\n"); + va_end(vl); +} + +/*******************************************************************/ + +struct wp_parser* +wp_parser_new (void) +{ + struct wp_parser* my_parser = malloc(sizeof(struct wp_parser)); + + my_parser->sz_mempool = wp_ast_size(wp_root); + my_parser->p_root = malloc(my_parser->sz_mempool); + my_parser->p_free = my_parser->p_root; + + my_parser->ast = wp_parser_ast_dup(my_parser, wp_root,1); /* 1: free the source wp_root */ + + if (my_parser->p_root + my_parser->sz_mempool != my_parser->p_free) { + yyerror("wp_parser_new: error in memory size"); + exit(1); + } + + wp_ast_optimize(my_parser->ast); + + return my_parser; +} + +void +wp_parser_delete (struct wp_parser* parser) +{ + free(parser->p_root); + free(parser); +} + +static size_t +wp_aligned_size (size_t N) +{ + const unsigned int align_size = 16; + size_t x = N + (align_size-1); + x -= x & (align_size-1); + return x; +} + +static +void* +wp_parser_allocate (struct wp_parser* my_parser, size_t N) +{ + void* r = my_parser->p_free; + my_parser->p_free = (char*)r + wp_aligned_size(N); + return r; +} + +struct wp_parser* +wp_parser_dup (struct wp_parser* source) +{ + struct wp_parser* dest = malloc(sizeof(struct wp_parser)); + dest->sz_mempool = source->sz_mempool; + dest->p_root = malloc(dest->sz_mempool); + dest->p_free = dest->p_root; + + dest->ast = wp_parser_ast_dup(dest, source->ast, 0); /* 0: don't free the source */ + + return dest; +} + +static +double +wp_call_f1 (struct wp_f1* f1) +{ + double a = wp_ast_eval(f1->l); + switch (f1->ftype) { + case WP_SQRT: return sqrt(a); + case WP_EXP: return exp(a); + case WP_LOG: return log(a); + case WP_LOG10: return log10(a); + case WP_SIN: return sin(a); + case WP_COS: return cos(a); + case WP_TAN: return tan(a); + case WP_ASIN: return asin(a); + case WP_ACOS: return acos(a); + case WP_ATAN: return atan(a); + case WP_SINH: return sinh(a); + case WP_COSH: return cosh(a); + case WP_TANH: return tanh(a); + case WP_ABS: return fabs(a); + case WP_POW_M3: return 1.0/(a*a*a); + case WP_POW_M2: return 1.0/(a*a); + case WP_POW_M1: return 1.0/a; + case WP_POW_P1: return a; + case WP_POW_P2: return a*a; + case WP_POW_P3: return a*a*a; + default: + yyerror("wp_call_f1: Unknow function %d", f1->ftype); + return 0.0; + } +} + +static +double +wp_call_f2 (struct wp_f2* f2) +{ + double a = wp_ast_eval(f2->l); + double b = wp_ast_eval(f2->r); + switch (f2->ftype) { + case WP_POW: + return pow(a,b); + case WP_GT: + return (a > b) ? 1.0 : 0.0; + case WP_LT: + return (a < b) ? 1.0 : 0.0; + case WP_HEAVISIDE: + return (a < 0.0) ? 0.0 : ((a > 0.0) ? 1.0 : b); + case WP_MIN: + return (a < b) ? a : b; + case WP_MAX: + return (a > b) ? a : b; + default: + yyerror("wp_call_f2: Unknow function %d", f2->ftype); + return 0.0; + } +} + +double +wp_ast_eval (struct wp_node* node) +{ + double result; + + switch (node->type) + { + case WP_NUMBER: + result = ((struct wp_number*)node)->value; + break; + case WP_SYMBOL: + result = *(((struct wp_symbol*)node)->pointer); + break; + case WP_ADD: + result = wp_ast_eval(node->l) + wp_ast_eval(node->r); + break; + case WP_SUB: + result = wp_ast_eval(node->l) - wp_ast_eval(node->r); + break; + case WP_MUL: + result = wp_ast_eval(node->l) * wp_ast_eval(node->r); + break; + case WP_DIV: + result = wp_ast_eval(node->l) / wp_ast_eval(node->r); + break; + case WP_NEG: + result = -wp_ast_eval(node->l); + break; + case WP_F1: + result = wp_call_f1((struct wp_f1*)node); + break; + case WP_F2: + result = wp_call_f2((struct wp_f2*)node); + break; + case WP_ADD_VP: + result = node->lvp.v + *(node->rp); + break; + case WP_ADD_PP: + result = *(node->lvp.p) + *(node->rp); + break; + case WP_SUB_VP: + result = node->lvp.v - *(node->rp); + break; + case WP_SUB_PP: + result = *(node->lvp.p) - *(node->rp); + break; + case WP_MUL_VP: + result = node->lvp.v * *(node->rp); + break; + case WP_MUL_PP: + result = *(node->lvp.p) * *(node->rp); + break; + case WP_DIV_VP: + result = node->lvp.v / *(node->rp); + break; + case WP_DIV_PP: + result = *(node->lvp.p) / *(node->rp); + break; + case WP_NEG_P: + result = -*(node->lvp.p); + break; + default: + yyerror("wp_ast_eval: unknown node type %d\n", node->type); + } + + return result; +} + +size_t +wp_ast_size (struct wp_node* node) +{ + size_t result; + + switch (node->type) + { + case WP_NUMBER: + result = wp_aligned_size(sizeof(struct wp_number)); + break; + case WP_SYMBOL: + result = wp_aligned_size(sizeof(struct wp_symbol)) + + wp_aligned_size(strlen(((struct wp_symbol*)node)->name)+1); + break; + case WP_ADD: + case WP_SUB: + case WP_MUL: + case WP_DIV: + case WP_ADD_PP: + case WP_SUB_PP: + case WP_MUL_PP: + case WP_DIV_PP: + result = wp_aligned_size(sizeof(struct wp_node)) + + wp_ast_size(node->l) + wp_ast_size(node->r); + break; + case WP_NEG: + result = wp_aligned_size(sizeof(struct wp_node)) + + wp_ast_size(node->l); + break; + case WP_F1: + result = wp_aligned_size(sizeof(struct wp_f1)) + + wp_ast_size(node->l); + break; + case WP_F2: + result = wp_aligned_size(sizeof(struct wp_f2)) + + wp_ast_size(node->l) + wp_ast_size(node->r); + break; + case WP_ADD_VP: + case WP_SUB_VP: + case WP_MUL_VP: + case WP_DIV_VP: + result = wp_aligned_size(sizeof(struct wp_node)) + + wp_ast_size(node->r); + break; + case WP_NEG_P: + result = wp_aligned_size(sizeof(struct wp_node)) + + wp_ast_size(node->l); + break; + default: + yyerror("wp_ast_size: unknown node type %d\n", node->type); + exit(1); + } + + return result; +} + +struct wp_node* +wp_parser_ast_dup (struct wp_parser* my_parser, struct wp_node* node, int move) +{ + void* result; + + switch (node->type) + { + case WP_NUMBER: + result = wp_parser_allocate(my_parser, sizeof(struct wp_number)); + memcpy(result, node , sizeof(struct wp_number)); + break; + case WP_SYMBOL: + result = wp_parser_allocate(my_parser, sizeof(struct wp_symbol)); + memcpy(result, node , sizeof(struct wp_symbol)); + ((struct wp_symbol*)result)->name = wp_parser_allocate + (my_parser, strlen(((struct wp_symbol*)node)->name)+1); + strcpy(((struct wp_symbol*)result)->name, + ((struct wp_symbol*)node )->name); + break; + case WP_ADD: + case WP_SUB: + case WP_MUL: + case WP_DIV: + case WP_ADD_PP: + case WP_SUB_PP: + case WP_MUL_PP: + case WP_DIV_PP: + result = wp_parser_allocate(my_parser, sizeof(struct wp_node)); + memcpy(result, node , sizeof(struct wp_node)); + ((struct wp_node*)result)->l = wp_parser_ast_dup(my_parser, node->l, move); + ((struct wp_node*)result)->r = wp_parser_ast_dup(my_parser, node->r, move); + break; + case WP_NEG: + result = wp_parser_allocate(my_parser, sizeof(struct wp_node)); + memcpy(result, node , sizeof(struct wp_node)); + ((struct wp_node*)result)->l = wp_parser_ast_dup(my_parser, node->l, move); + ((struct wp_node*)result)->r = NULL; + break; + case WP_F1: + result = wp_parser_allocate(my_parser, sizeof(struct wp_f1)); + memcpy(result, node , sizeof(struct wp_f1)); + ((struct wp_f1*)result)->l = wp_parser_ast_dup(my_parser, ((struct wp_f1*)node)->l, move); + break; + case WP_F2: + result = wp_parser_allocate(my_parser, sizeof(struct wp_f2)); + memcpy(result, node , sizeof(struct wp_f2)); + ((struct wp_f2*)result)->l = wp_parser_ast_dup(my_parser, ((struct wp_f2*)node)->l, move); + ((struct wp_f2*)result)->r = wp_parser_ast_dup(my_parser, ((struct wp_f2*)node)->r, move); + break; + case WP_ADD_VP: + case WP_SUB_VP: + case WP_MUL_VP: + case WP_DIV_VP: + result = wp_parser_allocate(my_parser, sizeof(struct wp_node)); + memcpy(result, node , sizeof(struct wp_node)); + ((struct wp_node*)result)->r = wp_parser_ast_dup(my_parser, node->r, move); + break; + case WP_NEG_P: + result = wp_parser_allocate(my_parser, sizeof(struct wp_node)); + memcpy(result, node , sizeof(struct wp_node)); + ((struct wp_node*)result)->l = wp_parser_ast_dup(my_parser, node->l, move); + break; + default: + yyerror("wp_ast_dup: unknown node type %d\n", node->type); + exit(1); + } + if (move) { + /* Note that we only do this on the original AST. We do not + * need to call free for AST stored in wp_parser because the + * memory is not allocated with malloc directly. + */ + if (node->type == WP_SYMBOL) { + free(((struct wp_symbol*)node)->name); + } + free((void*)node); + } + return (struct wp_node*)result; +} + +#define WP_MOVEUP_R(node, v) \ + struct wp_node* n = node->r->r; \ + double* p = node->r->rp; \ + node->r = n; \ + node->lvp.v = v; \ + node->rp = p; +#define WP_MOVEUP_L(node, v) \ + struct wp_node* n = node->l->r; \ + double* p = node->l->rp; \ + node->r = n; \ + node->lvp.v = v; \ + node->rp = p; +#define WP_EVAL_R(node) node->r->lvp.v +#define WP_EVAL_L(node) node->l->lvp.v + +#define WP_NEG_MOVEUP(node) \ + node->r = node->l->r; \ + node->lvp.v = -node->l->lvp.v; \ + node->rp = node->l->rp; + +void +wp_ast_optimize (struct wp_node* node) +{ + /* No need to free memory because we only call this on ASTs in + * wp_parser that are allocated from the memory pool. + */ + switch (node->type) + { + case WP_NUMBER: + case WP_SYMBOL: + break; + case WP_ADD: + case WP_ADD_PP: + wp_ast_optimize(node->l); + wp_ast_optimize(node->r); + if (node->l->type == WP_NUMBER && + node->r->type == WP_NUMBER) + { + double v = wp_ast_eval(node); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_SYMBOL) + { + node->lvp.v = wp_ast_eval(node->l); + node->rp = ((struct wp_symbol*)(node->r))->pointer; + node->type = WP_ADD_VP; + } + else if (node->l->type == WP_SYMBOL && + node->r->type == WP_NUMBER) + { + node->lvp.v = wp_ast_eval(node->r); + node->rp = ((struct wp_symbol*)(node->l))->pointer; + node->r = node->l; + node->type = WP_ADD_VP; + } + else if (node->l->type == WP_SYMBOL && + node->r->type == WP_SYMBOL) + { + node->lvp.p = ((struct wp_symbol*)(node->l))->pointer; + node->rp = ((struct wp_symbol*)(node->r))->pointer; + node->type = WP_ADD_PP; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_ADD_VP) + { + double v = wp_ast_eval(node->l) + WP_EVAL_R(node); + WP_MOVEUP_R(node, v); + node->type = WP_ADD_VP; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_SUB_VP) + { + double v = wp_ast_eval(node->l) + WP_EVAL_R(node); + WP_MOVEUP_R(node, v); + node->type = WP_SUB_VP; + } + else if (node->l->type == WP_ADD_VP && + node->r->type == WP_NUMBER) + { + double v = WP_EVAL_L(node) + wp_ast_eval(node->r); + WP_MOVEUP_L(node, v); + node->type = WP_ADD_VP; + } + else if (node->l->type == WP_SUB_VP && + node->r->type == WP_NUMBER) + { + double v = WP_EVAL_L(node) + wp_ast_eval(node->r); + WP_MOVEUP_L(node, v); + node->type = WP_SUB_VP; + } + break; + case WP_SUB: + case WP_SUB_PP: + wp_ast_optimize(node->l); + wp_ast_optimize(node->r); + if (node->l->type == WP_NUMBER && + node->r->type == WP_NUMBER) + { + double v = wp_ast_eval(node); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_SYMBOL) + { + node->lvp.v = wp_ast_eval(node->l); + node->rp = ((struct wp_symbol*)(node->r))->pointer; + node->type = WP_SUB_VP; + } + else if (node->l->type == WP_SYMBOL && + node->r->type == WP_NUMBER) + { + node->lvp.v = -wp_ast_eval(node->r); + node->rp = ((struct wp_symbol*)(node->l))->pointer; + node->r = node->l; + node->type = WP_ADD_VP; + } + else if (node->l->type == WP_SYMBOL && + node->r->type == WP_SYMBOL) + { + node->lvp.p = ((struct wp_symbol*)(node->l))->pointer; + node->rp = ((struct wp_symbol*)(node->r))->pointer; + node->type = WP_SUB_PP; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_ADD_VP) + { + double v = wp_ast_eval(node->l) - WP_EVAL_R(node); + WP_MOVEUP_R(node, v); + node->type = WP_SUB_VP; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_SUB_VP) + { + double v = wp_ast_eval(node->l) - WP_EVAL_R(node); + WP_MOVEUP_R(node, v); + node->type = WP_ADD_VP; + } + else if (node->l->type == WP_ADD_VP && + node->r->type == WP_NUMBER) + { + double v = WP_EVAL_L(node) - wp_ast_eval(node->r); + WP_MOVEUP_L(node, v); + node->type = WP_ADD_VP; + } + else if (node->l->type == WP_SUB_VP && + node->r->type == WP_NUMBER) + { + double v = WP_EVAL_L(node) - wp_ast_eval(node->r); + WP_MOVEUP_L(node, v); + node->type = WP_SUB_VP; + } + break; + case WP_MUL: + case WP_MUL_PP: + wp_ast_optimize(node->l); + wp_ast_optimize(node->r); + if (node->l->type == WP_NUMBER && + node->r->type == WP_NUMBER) + { + double v = wp_ast_eval(node); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_SYMBOL) + { + node->lvp.v = wp_ast_eval(node->l); + node->rp = ((struct wp_symbol*)(node->r))->pointer; + node->type = WP_MUL_VP; + } + else if (node->l->type == WP_SYMBOL && + node->r->type == WP_NUMBER) + { + node->lvp.v = wp_ast_eval(node->r); + node->rp = ((struct wp_symbol*)(node->l))->pointer; + node->r = node->l; + node->type = WP_MUL_VP; + } + else if (node->l->type == WP_SYMBOL && + node->r->type == WP_SYMBOL) + { + node->lvp.p = ((struct wp_symbol*)(node->l))->pointer; + node->rp = ((struct wp_symbol*)(node->r))->pointer; + node->type = WP_MUL_PP; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_MUL_VP) + { + double v = wp_ast_eval(node->l) * WP_EVAL_R(node); + WP_MOVEUP_R(node, v); + node->type = WP_MUL_VP; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_DIV_VP) + { + double v = wp_ast_eval(node->l) * WP_EVAL_R(node); + WP_MOVEUP_R(node, v); + node->type = WP_DIV_VP; + } + else if (node->l->type == WP_MUL_VP && + node->r->type == WP_NUMBER) + { + double v = WP_EVAL_L(node) * wp_ast_eval(node->r); + WP_MOVEUP_L(node, v); + node->type = WP_MUL_VP; + } + else if (node->l->type == WP_DIV_VP && + node->r->type == WP_NUMBER) + { + double v = WP_EVAL_L(node) * wp_ast_eval(node->r); + WP_MOVEUP_L(node, v); + node->type = WP_DIV_VP; + } + break; + case WP_DIV: + case WP_DIV_PP: + wp_ast_optimize(node->l); + wp_ast_optimize(node->r); + if (node->l->type == WP_NUMBER && + node->r->type == WP_NUMBER) + { + double v = wp_ast_eval(node); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_SYMBOL) + { + node->lvp.v = wp_ast_eval(node->l); + node->rp = ((struct wp_symbol*)(node->r))->pointer; + node->type = WP_DIV_VP; + } + else if (node->l->type == WP_SYMBOL && + node->r->type == WP_NUMBER) + { + node->lvp.v = 1./wp_ast_eval(node->r); + node->rp = ((struct wp_symbol*)(node->l))->pointer; + node->r = node->l; + node->type = WP_MUL_VP; + } + else if (node->l->type == WP_SYMBOL && + node->r->type == WP_SYMBOL) + { + node->lvp.p = ((struct wp_symbol*)(node->l))->pointer; + node->rp = ((struct wp_symbol*)(node->r))->pointer; + node->type = WP_DIV_PP; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_MUL_VP) + { + double v = wp_ast_eval(node->l) / WP_EVAL_R(node); + WP_MOVEUP_R(node, v); + node->type = WP_DIV_VP; + } + else if (node->l->type == WP_NUMBER && + node->r->type == WP_DIV_VP) + { + double v = wp_ast_eval(node->l) / WP_EVAL_R(node); + WP_MOVEUP_R(node, v); + node->type = WP_MUL_VP; + } + else if (node->l->type == WP_MUL_VP && + node->r->type == WP_NUMBER) + { + double v = WP_EVAL_L(node) / wp_ast_eval(node->r); + WP_MOVEUP_L(node, v); + node->type = WP_MUL_VP; + } + else if (node->l->type == WP_DIV_VP && + node->r->type == WP_NUMBER) + { + double v = WP_EVAL_L(node) / wp_ast_eval(node->r); + WP_MOVEUP_L(node, v); + node->type = WP_DIV_VP; + } + break; + case WP_NEG: + wp_ast_optimize(node->l); + if (node->l->type == WP_NUMBER) + { + double v = wp_ast_eval(node); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + else if (node->l->type == WP_SYMBOL) + { + node->lvp.p = ((struct wp_symbol*)(node->l))->pointer; + node->type = WP_NEG_P; + } + else if (node->l->type == WP_ADD_VP) + { + WP_NEG_MOVEUP(node); + node->type = WP_SUB_VP; + } + else if (node->l->type == WP_SUB_VP) + { + WP_NEG_MOVEUP(node); + node->type = WP_ADD_VP; + } + else if (node->l->type == WP_MUL_VP) + { + WP_NEG_MOVEUP(node); + node->type = WP_MUL_VP; + } + else if (node->l->type == WP_DIV_VP) + { + WP_NEG_MOVEUP(node); + node->type = WP_DIV_VP; + } + break; + case WP_F1: + wp_ast_optimize(node->l); + if (node->l->type == WP_NUMBER) + { + double v = wp_ast_eval(node); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + break; + case WP_F2: + wp_ast_optimize(node->l); + wp_ast_optimize(node->r); + if (node->l->type == WP_NUMBER && + node->r->type == WP_NUMBER) + { + double v = wp_ast_eval(node); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + else if (node->r->type == WP_NUMBER && ((struct wp_f2*)node)->ftype == WP_POW) + { + struct wp_node* n = node->l; + double v = wp_ast_eval(node->r); + if (-3.0 == v) { + ((struct wp_f1*)node)->type = WP_F1; + ((struct wp_f1*)node)->l = n; + ((struct wp_f1*)node)->ftype = WP_POW_M3; + } else if (-2.0 == v) { + ((struct wp_f1*)node)->type = WP_F1; + ((struct wp_f1*)node)->l = n; + ((struct wp_f1*)node)->ftype = WP_POW_M2; + } else if (-1.0 == v) { + ((struct wp_f1*)node)->type = WP_F1; + ((struct wp_f1*)node)->l = n; + ((struct wp_f1*)node)->ftype = WP_POW_M1; + } else if (0.0 == v) { + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = 1.0; + } else if (1.0 == v) { + ((struct wp_f1*)node)->type = WP_F1; + ((struct wp_f1*)node)->l = n; + ((struct wp_f1*)node)->ftype = WP_POW_P1; + } else if (2.0 == v) { + ((struct wp_f1*)node)->type = WP_F1; + ((struct wp_f1*)node)->l = n; + ((struct wp_f1*)node)->ftype = WP_POW_P2; + } else if (3.0 == v) { + ((struct wp_f1*)node)->type = WP_F1; + ((struct wp_f1*)node)->l = n; + ((struct wp_f1*)node)->ftype = WP_POW_P3; + } + } + break; + case WP_ADD_VP: + wp_ast_optimize(node->r); + if (node->r->type == WP_NUMBER) + { + double v = node->lvp.v + wp_ast_eval(node->r); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + break; + case WP_SUB_VP: + wp_ast_optimize(node->r); + if (node->r->type == WP_NUMBER) + { + double v = node->lvp.v - wp_ast_eval(node->r); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + break; + case WP_MUL_VP: + wp_ast_optimize(node->r); + if (node->r->type == WP_NUMBER) + { + double v = node->lvp.v * wp_ast_eval(node->r); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + break; + case WP_DIV_VP: + wp_ast_optimize(node->r); + if (node->r->type == WP_NUMBER) + { + double v = node->lvp.v / wp_ast_eval(node->r); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + break; + case WP_NEG_P: + wp_ast_optimize(node->l); + if (node->l->type == WP_NUMBER) + { + double v = -wp_ast_eval(node->l); + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = v; + } + break; + default: + yyerror("wp_ast_optimize: unknown node type %d\n", node->type); + exit(1); + } +} + +static +void +wp_ast_print_f1 (struct wp_f1* f1) +{ + wp_ast_print(f1->l); + switch (f1->ftype) { + case WP_SQRT: printf("SQRT\n"); break; + case WP_EXP: printf("EXP\n"); break; + case WP_LOG: printf("LOG\n"); break; + case WP_LOG10: printf("LOG10\n"); break; + case WP_SIN: printf("SIN\n"); break; + case WP_COS: printf("COS\n"); break; + case WP_TAN: printf("TAN\n"); break; + case WP_ASIN: printf("ASIN\n"); break; + case WP_ACOS: printf("ACOS\n"); break; + case WP_ATAN: printf("ATAN\n"); break; + case WP_SINH: printf("SINH\n"); break; + case WP_COSH: printf("COSH\n"); break; + case WP_TANH: printf("TANH\n"); break; + case WP_ABS: printf("ABS\n"); break; + case WP_POW_M3: printf("POW(,-3)\n"); break; + case WP_POW_M2: printf("POW(,-2)\n"); break; + case WP_POW_M1: printf("POW(,-1)\n"); break; + case WP_POW_P1: printf("POW(,1)\n"); break; + case WP_POW_P2: printf("POW(,2)\n"); break; + case WP_POW_P3: printf("POW(,3)\n"); break; + default: + yyerror("wp_ast+print_f1: Unknow function %d", f1->ftype); + } +} + +static +void +wp_ast_print_f2 (struct wp_f2* f2) +{ + wp_ast_print(f2->l); + wp_ast_print(f2->r); + switch (f2->ftype) { + case WP_POW: + printf("POW\n"); + break; + case WP_GT: + printf("GT\n"); + break; + case WP_LT: + printf("LT\n"); + break; + case WP_HEAVISIDE: + printf("HEAVISIDE\n"); + break; + case WP_MIN: + printf("MIN\n"); + break; + case WP_MAX: + printf("MAX\n"); + break; + default: + yyerror("wp_ast_print_f2: Unknow function %d", f2->ftype); + } +} + +void +wp_ast_print (struct wp_node* node) +{ + switch (node->type) + { + case WP_NUMBER: + printf("NUMBER: %.17g\n", wp_ast_eval(node)); + break; + case WP_SYMBOL: + printf("VARIABLE: %s\n", ((struct wp_symbol*)node)->name); + break; + case WP_ADD: + wp_ast_print(node->l); + wp_ast_print(node->r); + printf("ADD\n"); + break; + case WP_SUB: + wp_ast_print(node->l); + wp_ast_print(node->r); + printf("SUB\n"); + break; + case WP_MUL: + wp_ast_print(node->l); + wp_ast_print(node->r); + printf("MUL\n"); + break; + case WP_DIV: + wp_ast_print(node->l); + wp_ast_print(node->r); + printf("DIV\n"); + break; + case WP_NEG: + wp_ast_print(node->l); + printf("NEG\n"); + break; + case WP_F1: + wp_ast_print_f1((struct wp_f1*)node); + break; + case WP_F2: + wp_ast_print_f2((struct wp_f2*)node); + break; + case WP_ADD_VP: + printf("ADD: %.17g %s\n", node->lvp.v, ((struct wp_symbol*)(node->r))->name); + break; + case WP_SUB_VP: + printf("SUM: %.17g %s\n", node->lvp.v, ((struct wp_symbol*)(node->r))->name); + break; + case WP_MUL_VP: + printf("MUL: %.17g %s\n", node->lvp.v, ((struct wp_symbol*)(node->r))->name); + break; + case WP_DIV_VP: + printf("DIV: %.17g %s\n", node->lvp.v, ((struct wp_symbol*)(node->r))->name); + break; + case WP_NEG_P: + printf("NEG: %s\n", ((struct wp_symbol*)(node->l))->name); + break; + case WP_ADD_PP: + printf("ADD: %s %s\n", ((struct wp_symbol*)(node->l))->name, + ((struct wp_symbol*)(node->r))->name); + break; + case WP_SUB_PP: + printf("SUB: %s %s\n", ((struct wp_symbol*)(node->l))->name, + ((struct wp_symbol*)(node->r))->name); + break; + case WP_MUL_PP: + printf("MUL: %s %s\n", ((struct wp_symbol*)(node->l))->name, + ((struct wp_symbol*)(node->r))->name); + break; + case WP_DIV_PP: + printf("DIV: %s %s\n", ((struct wp_symbol*)(node->l))->name, + ((struct wp_symbol*)(node->r))->name); + break; + default: + yyerror("wp_ast_print: unknown node type %d\n", node->type); + exit(1); + } +} + +void +wp_ast_regvar (struct wp_node* node, char const* name, double* p) +{ + switch (node->type) + { + case WP_NUMBER: + break; + case WP_SYMBOL: + if (strcmp(name, ((struct wp_symbol*)node)->name) == 0) { + ((struct wp_symbol*)node)->pointer = p; + } + break; + case WP_ADD: + case WP_SUB: + case WP_MUL: + case WP_DIV: + wp_ast_regvar(node->l, name, p); + wp_ast_regvar(node->r, name, p); + break; + case WP_NEG: + wp_ast_regvar(node->l, name, p); + break; + case WP_F1: + wp_ast_regvar(node->l, name, p); + break; + case WP_F2: + wp_ast_regvar(node->l, name, p); + wp_ast_regvar(node->r, name, p); + break; + case WP_ADD_VP: + case WP_SUB_VP: + case WP_MUL_VP: + case WP_DIV_VP: + wp_ast_regvar(node->r, name, p); + node->rp = ((struct wp_symbol*)(node->r))->pointer; + break; + case WP_NEG_P: + wp_ast_regvar(node->l, name, p); + node->lvp.p = ((struct wp_symbol*)(node->l))->pointer; + break; + case WP_ADD_PP: + case WP_SUB_PP: + case WP_MUL_PP: + case WP_DIV_PP: + wp_ast_regvar(node->l, name, p); + wp_ast_regvar(node->r, name, p); + node->lvp.p = ((struct wp_symbol*)(node->l))->pointer; + node->rp = ((struct wp_symbol*)(node->r))->pointer; + break; + default: + yyerror("wp_ast_regvar: unknown node type %d\n", node->type); + exit(1); + } +} + +void wp_ast_setconst (struct wp_node* node, char const* name, double c) +{ + switch (node->type) + { + case WP_NUMBER: + break; + case WP_SYMBOL: + if (strcmp(name, ((struct wp_symbol*)node)->name) == 0) { + ((struct wp_number*)node)->type = WP_NUMBER; + ((struct wp_number*)node)->value = c; + } + break; + case WP_ADD: + case WP_SUB: + case WP_MUL: + case WP_DIV: + wp_ast_setconst(node->l, name, c); + wp_ast_setconst(node->r, name, c); + break; + case WP_NEG: + wp_ast_setconst(node->l, name, c); + break; + case WP_F1: + wp_ast_setconst(node->l, name, c); + break; + case WP_F2: + wp_ast_setconst(node->l, name, c); + wp_ast_setconst(node->r, name, c); + break; + case WP_ADD_VP: + case WP_SUB_VP: + case WP_MUL_VP: + case WP_DIV_VP: + wp_ast_setconst(node->r, name, c); + break; + case WP_NEG_P: + wp_ast_setconst(node->l, name, c); + break; + case WP_ADD_PP: + case WP_SUB_PP: + case WP_MUL_PP: + case WP_DIV_PP: + wp_ast_setconst(node->l, name, c); + wp_ast_setconst(node->r, name, c); + break; + default: + yyerror("wp_ast_setconst: unknown node type %d\n", node->type); + exit(1); + } +} + +void +wp_parser_regvar (struct wp_parser* parser, char const* name, double* p) +{ + wp_ast_regvar(parser->ast, name, p); +} + +void +wp_parser_setconst (struct wp_parser* parser, char const* name, double c) +{ + wp_ast_setconst(parser->ast, name, c); + wp_ast_optimize(parser->ast); +} + |