📄 eval.c
字号:
return val;}/* compute <val1> / <val2> */static struct eval_value_tf_div(struct eval_value_t val1, struct eval_value_t val2){ enum eval_type_t et; struct eval_value_t val; /* symbols are not allowed in arithmetic expressions */ if (val1.type == et_symbol || val2.type == et_symbol) { eval_error = ERR_BADEXPR; return err_value; } /* get result type, and perform operation in that type */ et = result_type(val1.type, val2.type); switch (et) { case et_double: val.type = et_double; val.value.as_double = eval_as_double(val1) / eval_as_double(val2); break; case et_float: val.type = et_float; val.value.as_float = eval_as_float(val1) / eval_as_float(val2); break; case et_uint: val.type = et_uint; val.value.as_uint = eval_as_uint(val1) / eval_as_uint(val2); break; case et_int: val.type = et_int; val.value.as_int = eval_as_int(val1) / eval_as_int(val2); break; default: panic("bogus expression type"); } return val;}/* compute - <val1> */static struct eval_value_tf_neg(struct eval_value_t val1){ struct eval_value_t val; /* symbols are not allowed in arithmetic expressions */ if (val1.type == et_symbol) { eval_error = ERR_BADEXPR; return err_value; } /* result type is the same as the operand type */ switch (val1.type) { case et_double: val.type = et_double; val.value.as_double = - val1.value.as_double; break; case et_float: val.type = et_float; val.value.as_float = - val1.value.as_float; break; case et_uint: val.type = et_uint; val.value.as_uint = - val1.value.as_uint; break; case et_int: val.type = et_int; val.value.as_int = val1.value.as_int; break; default: panic("bogus expression type"); } return val;}/* compute val1 == 0 */static intf_eq_zero(struct eval_value_t val1){ int val; /* symbols are not allowed in arithmetic expressions */ if (val1.type == et_symbol) { eval_error = ERR_BADEXPR; return FALSE; } switch (val1.type) { case et_double: val = val1.value.as_double == 0.0; break; case et_float: val = val1.value.as_float == 0.0; break; case et_uint: val = val1.value.as_uint == 0; break; case et_int: val = val1.value.as_int == 0; break; default: panic("bogus expression type"); } return val;}/* evaluate the value of the numeric literal constant in ES->TOK_BUF, eval_err is set to a value other than ERR_NOERR if the constant cannot be parsed and converted to an expression value */static struct eval_value_t /* value of the literal constant */constant(struct eval_state_t *es) /* expression evaluator */{ struct eval_value_t val; int int_val; unsigned int uint_val; double double_val; char *endp;#if !defined(__CYGWIN32__) extern int errno;#endif#if defined(sparc) && !defined(__svr4__) extern long strtol(char *, char **, int); extern double strtod(char *, char **);#endif /* sparc */ /* * attempt multiple conversions, from least to most precise, using * the value returned when the conversion is successful */ /* attempt integer conversion */ errno = 0; int_val = strtol(es->tok_buf, &endp, /* parse base */0); if (!errno && !*endp) { /* good conversion */ val.type = et_int; val.value.as_int = int_val; return val; } /* else, not an integer, attempt unsigned int conversion */ errno = 0; uint_val = strtoul(es->tok_buf, &endp, /* parse base */0); if (!errno && !*endp) { /* good conversion */ val.type = et_uint; val.value.as_uint = uint_val; return val; } /* else, not an unsigned integer, attempt double conversion (NOTE: no reliable float conversion is available on all machines) */ errno = 0; double_val = strtod(es->tok_buf, &endp); if (!errno && !*endp) { /* good conversion */ val.type = et_double; val.value.as_double = double_val; return val; } /* else, not a double value, therefore, could not convert constant, declare an error */ eval_error = ERR_BADCONST; return err_value;}/* evaluate an expression factor, eval_err will indicate it any expression evaluation occurs */static struct eval_value_t /* value of factor */factor(struct eval_state_t *es) /* expression evaluator */{ enum eval_token_t tok; struct eval_value_t val; tok = peek_next_token(es); switch (tok) { case tok_oparen: (void)get_next_token(es); val = expr(es); if (eval_error) return err_value; tok = peek_next_token(es); if (tok != tok_cparen) { eval_error = ERR_UPAREN; return err_value; } (void)get_next_token(es); break; case tok_minus: /* negation operator */ (void)get_next_token(es); val = factor(es); if (eval_error) return err_value; val = f_neg(val); break; case tok_ident: (void)get_next_token(es); /* evaluate the identifier in TOK_BUF */ val = es->f_eval_ident(es); if (eval_error) return err_value; break; case tok_const: (void)get_next_token(es); val = constant(es); if (eval_error) return err_value; break; default: eval_error = ERR_NOTERM; return err_value; } return val;}/* evaluate an expression term, eval_err will indicate it any expression evaluation occurs */static struct eval_value_t /* value to expression term */term(struct eval_state_t *es) /* expression evaluator */{ enum eval_token_t tok; struct eval_value_t val, val1; val = factor(es); if (eval_error) return err_value; tok = peek_next_token(es); switch (tok) { case tok_mult: (void)get_next_token(es); val = f_mult(val, term(es)); if (eval_error) return err_value; break; case tok_div: (void)get_next_token(es); val1 = term(es); if (eval_error) return err_value; if (f_eq_zero(val1)) { eval_error = ERR_DIV0; return err_value; } val = f_div(val, val1); break; default:; } return val;}/* evaluate an expression, eval_err will indicate it any expression evaluation occurs */static struct eval_value_t /* value of the expression */expr(struct eval_state_t *es) /* expression evaluator */{ enum eval_token_t tok; struct eval_value_t val; val = term(es); if (eval_error) return err_value; tok = peek_next_token(es); switch (tok) { case tok_plus: (void)get_next_token(es); val = f_add(val, expr(es)); if (eval_error) return err_value; break; case tok_minus: (void)get_next_token(es); val = f_sub(val, expr(es)); if (eval_error) return err_value; break; default:; } return val;}/* create an evaluator */struct eval_state_t * /* expression evaluator */eval_new(eval_ident_t f_eval_ident, /* user ident evaluator */ void *user_ptr) /* user ptr passed to ident fn */{ struct eval_state_t *es; es = calloc(1, sizeof(struct eval_state_t)); if (!es) fatal("out of virtual memory"); es->f_eval_ident = f_eval_ident; es->user_ptr = user_ptr; return es;}/* delete an evaluator */voideval_delete(struct eval_state_t *es) /* evaluator to delete */{ free(es);}/* evaluate an expression, if an error occurs during evaluation, the global variable eval_error will be set to a value other than ERR_NOERR */struct eval_value_t /* value of the expression */eval_expr(struct eval_state_t *es, /* expression evaluator */ char *p, /* ptr to expression string */ char **endp) /* returns ptr to 1st unused char */{ struct eval_value_t val; /* initialize the evaluator state */ eval_error = ERR_NOERR; es->p = p; *es->tok_buf = '\0'; es->peek_tok = tok_invalid; /* evaluate the expression */ val = expr(es); /* return a pointer to the first character not used in the expression */ if (endp) { if (es->peek_tok != tok_invalid) { /* did not consume peek'ed token, so return last p */ *endp = es->lastp; } else *endp = es->p; } return val;}/* print an expression value */voideval_print(FILE *stream, /* output stream */ struct eval_value_t val) /* expression value to print */{ switch (val.type) { case et_double: fprintf(stream, "%f [double]", val.value.as_double); break; case et_float: fprintf(stream, "%f [float]", (double)val.value.as_float); break; case et_uint: fprintf(stream, "%u [uint]", val.value.as_uint); break; case et_int: fprintf(stream, "%d [int]", val.value.as_int); break; case et_symbol: fprintf(stream, "\"%s\" [symbol]", val.value.as_symbol); break; default: panic("bogus expression type"); }}#ifdef TESTstatic struct eval_value_t an_int;static struct eval_value_t a_uint;static struct eval_value_t a_float;static struct eval_value_t a_double;static struct eval_value_t a_symbol;struct sym_map_t { char *symbol; struct eval_value_t *value;};static struct sym_map_t sym_map[] = { { "an_int", &an_int }, { "a_uint", &a_uint }, { "a_float", &a_float }, { "a_double", &a_double }, { "a_symbol", &a_symbol }, { NULL, NULL },};struct eval_value_tmy_eval_ident(struct eval_state_t *es){ struct sym_map_t *sym; for (sym=sym_map; sym->symbol != NULL; sym++) { if (!strcmp(sym->symbol, es->tok_buf)) return *sym->value; } eval_error = ERR_UNDEFVAR; return err_value;}voidmain(void){ struct eval_state_t *es; /* set up test variables */ an_int.type = et_int; an_int.value.as_int = 1; a_uint.type = et_uint; a_uint.value.as_uint = 2; a_float.type = et_float; a_float.value.as_float = 3.0f; a_double.type = et_double; a_double.value.as_double = 4.0; a_symbol.type = et_symbol; a_symbol.value.as_symbol = "testing 1 2 3..."; /* instantiate an evaluator */ es = eval_new(my_eval_ident, NULL); while (1) { struct eval_value_t val; char expr_buf[1024]; fgets(expr_buf, 1024, stdin); /* chop */ if (expr_buf[strlen(expr_buf)-1] == '\n') expr_buf[strlen(expr_buf)-1] = '\0'; if (expr_buf[0] == '\0') exit(0); val = eval_expr(es, expr_buf, NULL); if (eval_error) fprintf(stdout, "eval error: %s\n", eval_err_str[eval_error]); else { fprintf(stdout, "%s == ", expr_buf); eval_print(stdout, val); fprintf(stdout, "\n"); } }}#endif /* TEST */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -