📄 expr2.c
字号:
/* * This is where we store our rvalues, kind of. What we really store here * are all of the string operands from the original expression. Whenever * one of the original operands is parsed, it is converted to a string and * put in here and the index into the 'token' table is returned. Only the * operands of the original expression go here. All derived operands (the * result of operators) directly create "expanded" tokens. *//* THIS FUNCTION MAKES A NEW COPY OF 'T'. YOU MUST DISPOSE OF 'T' YOURSELF */__inline static TOKEN tokenize_raw (expr_info *c, char *t){ if (c->token >= TOKENCOUNT) { error("Too many tokens for this expression"); return -1; } TOK(c, c->token).used = USED_RAW; malloc_strcpy(&TOK(c, c->token).raw_value, t); return c->token++;}/* * This is where any rvalues are stored. The result of any operation that * yeilds a string creates an 'expanded' token. Tokens that begin life as * 'expanded' tokens never can be passed through expand_alias() again. This * protects against possible security holes in the client. */__inline static TOKEN tokenize_expanded (expr_info *c, char *t){ if (c->token >= TOKENCOUNT) { error("Too many tokens for this expression"); return -1; } TOK(c, c->token).used = USED_EXPANDED; malloc_strcpy(&TOK(c, c->token).expanded_value, t); return c->token++;}/* * This creates an integer token. This is useful for quick operation on * complex mathematical expressions, where conversions to and from strings * is both expensive, and unnecesary. This type of token is created by * integer-only operations like &, |, ^, <<, >>. */__inline static TOKEN tokenize_integer (expr_info *c, INTTYPE t){ if (c->token >= TOKENCOUNT) { error("Too many tokens for this expression"); return -1; } TOK(c, c->token).used = USED_INTEGER; TOK(c, c->token).integer_value = t; return c->token++;}/* * This creates a floating point token. This is useful for the same things * that integer tokens are, and this is the token generated by floating * point operations, such as +, -, *, /, %, **. */__inline static TOKEN tokenize_float (expr_info *c, double t){ if (c->token >= TOKENCOUNT) { error("Too many tokens for this expression"); return -1; } TOK(c, c->token).used = USED_FLOAT; TOK(c, c->token).float_value = t; return c->token++;}/* * This creates a boolean token. This is useful for the same things as * integer tokens are. This token is generated by any sort of logic * operation, such as ==, !=, >, <, &&, ||. */__inline static TOKEN tokenize_bool (expr_info *c, BooL t){ if (c->token >= TOKENCOUNT) { error("Too many tokens for this expression"); return -1; } TOK(c, c->token).used = USED_BOOLEAN; TOK(c, c->token).boolean_value = t; return c->token++;}/******************** RETRIEVE SYMBOLS FROM TOKEN HANDLES *******************//* * These functions permit you to get at the tokens in various ways. * There is a definite concept of each token being stored in several * different representations: "raw" format (as the user specified it * in the expression), "expanded" format (what the raw value looks like * after it is passed through expand_alias), "integer" format (what the * expanded value looks like after a call to atol()), "float" format, * (what the expanded value looks like after a call to atof()), and * "boolean" format (what the expanded value looks like after a call to * check_val()). Each of these types are created on demand; so that if * a token is never referenced in an integer context, the expensive * conversion to an integer is not performed. This is inteded to keep * the number of unnecesary conversions to an absolute minimum. * * YOU MUST NOT EVER -- EVER -- FREE THE RETURN VALUE FROM ANY OF THESE * FUNCTIONS! TO DO SO WILL CRASH THE CLIENT! YOU HAVE BEEN WARNED! *//* * Get the "raw" value of the token. For tokens that have been created * via "tokenize", nothing has to be done since the raw value is already * present. However, for computed tokens (such as the result of a math * operation), the raw token may not actually exist, and so it must be * infered from whatever data is available. We use the value that has * the most information, starting with expanded string, to the boolean * value. */ __inline static const char * get_token_raw (expr_info *c, TOKEN v){ if (v == MAGIC_TOKEN) /* Magic token */ return c->args; /* XXX Probably wrong */ if (v < 0 || v >= c->token) { error("Token index [%d] is out of range", v); return get_token_raw(c, 0); /* The empty token */ } if (v == 0) return empty_string; if (c->noeval) return get_token_raw(c, 0);#if 0 panic("c->noeval is not valid here. [1]");#endif if ((TOK(c, v).used & USED_RAW) == 0) { TOK(c, v).used |= USED_RAW; if (TOK(c, v).used & USED_EXPANDED) panic("Cannot convert EXPANDED token to RAW"); else if (TOK(c, v).used & USED_FLOAT) { TOK(c, v).raw_value = malloc_sprintf(NULL, "%f", TOK(c, v).float_value); canon_number(TOK(c, v).raw_value); } else if (TOK(c, v).used & USED_INTEGER) TOK(c, v).raw_value = INT2STR(TOK(c, v).integer_value); else if (TOK(c, v).used & USED_BOOLEAN) TOK(c, v).raw_value = malloc_sprintf(NULL, "%d", TOK(c, v).boolean_value); else if (TOK(c, v).used & USED_LVAL) { if (x_debug & DEBUG_NEW_MATH_DEBUG) yell(">>> Expanding var name [%d]: [%s]", v, TOK(c, v).lval); TOK(c, v).raw_value = expand_alias(TOK(c, v).lval, c->args, c->args_flag, NULL); if (x_debug & DEBUG_NEW_MATH_DEBUG) yell(">>> Expanded var name [%d]: [%s] to [%s]", v, TOK(c, v).lval, TOK(c, v).raw_value); } else panic("Can't convert this token to raw format"); } return TOK(c, v).raw_value;}/* * This is kind of funky. This is used to get the "fully qualified" * lvalue for a given token. What that means is that this is not the * raw value of TOK(c, v).lval, but is rather TOK(c, v).raw, but if * and only if (TOK(c, v).used & USED_LVAL)! Otherwise, this returns * NULL and emits an error. */__inline static const char * get_token_lval (expr_info *c, TOKEN v){ if (v == MAGIC_TOKEN) /* Magic token */ return c->args; /* XXX Probably wrong */ if (v < 0 || v >= c->token) { error("Token index [%d] is out of range", v); return NULL; /* No lvalue here! */ } if (v == 0) return NULL; /* Suppress the operation entirely */ else if (c->noeval) { return NULL; /* Suppress the operation entirely */#if 0 return get_token_raw(c, 0); panic("c->noeval is not valid here. [0]");#endif } else if (((TOK(c, v).used & USED_LVAL) == 0)) { error("Token [%d] is not an lvalue", v); return NULL; /* No lvalue here! */ } else return get_token_raw(c, v);}/* * Get the "expanded" representation of the token. The first time you * call this function, it gets the "raw" value, if there is one, and then * call expand_alias() to get the value. Of course, there is always a * "raw" value, as get_token_raw() can convert from anything. */__inline static const char * get_token_expanded (expr_info *c, TOKEN v){ if (v == MAGIC_TOKEN) /* Magic token */ return c->args; if (v < 0 || v >= c->token) { error("Token index [%d] is out of range", v); return get_token_expanded(c, 0); /* The empty token */ } if (v == 0) return get_token_raw(c, 0); if (c->noeval) return get_token_raw(c, 0);#if 0 panic("c->noeval is not valid here. [2]");#endif if (x_debug & DEBUG_NEW_MATH_DEBUG) yell(">>> Getting token [%d] now.", v); if ((TOK(c, v).used & USED_EXPANDED) == 0) { char *myval; myval = LOCAL_COPY(get_token_raw(c, v)); TOK(c, v).used |= USED_EXPANDED; /* * If this token started off life as an lval, then the * "raw" value of this token will yeild the expanded form * of the lvalue, suitable for passing to alias_special_char. */ if (TOK(c, v).used & USED_LVAL) { char *buffer = NULL; if (x_debug & DEBUG_NEW_MATH_DEBUG) yell(">>> Looking up variable [%d]: [%s]", v, myval); alias_special_char(&buffer, myval, c->args, NULL, c->args_flag); if (!buffer) buffer = malloc_strdup(empty_string); TOK(c, v).expanded_value = buffer; if (x_debug & DEBUG_NEW_MATH_DEBUG) yell("<<< Expanded variable [%d] [%s] to: [%s]", v, myval, TOK(c, v).expanded_value); } /* * Otherwise, this token started off life as an rval * (such as a [...] string), and only needs to be expanded * with alias_special_char to yeild a useful value. */ else if (TOK(c, v).used & USED_RAW) { if (x_debug & DEBUG_NEW_MATH_DEBUG) yell(">>> Expanding token [%d]: [%s]", v, myval); TOK(c, v).used |= USED_EXPANDED; TOK(c, v).expanded_value = expand_alias(myval, c->args, c->args_flag, NULL); if (x_debug & DEBUG_NEW_MATH_DEBUG) yell("<<< Expanded token [%d]: [%s] to: [%s]", v, myval, TOK(c, v).expanded_value); } else panic("Cannot convert from this token to EXPANDED"); } if (x_debug & DEBUG_NEW_MATH_DEBUG) yell("<<< Token [%d] value is [%s].", v, TOK(c, v).expanded_value); return TOK(c, v).expanded_value;}/* * Get the integer representation of the token. The first time you call * this function, it calls atof() on the "raw" value, if there is one, * to get the result. */__inline static INTTYPE get_token_integer (expr_info *c, TOKEN v){ if (v == MAGIC_TOKEN) /* Magic token */ return STR2INT(c->args); /* XXX Probably wrong */ if (v < 0 || v >= c->token) { error("Token index [%d] is out of range", v); return 0; /* The empty token */ } if ((TOK(c, v).used & USED_INTEGER) == 0) { const char * myval = get_token_expanded(c, v); TOK(c, v).used |= USED_INTEGER; TOK(c, v).integer_value = STR2INT(myval); } return TOK(c, v).integer_value;}/* * Get the floating point value representation of the token. */__inline static double get_token_float (expr_info *c, TOKEN v){ if (v == MAGIC_TOKEN) /* Magic token */ return atof(c->args); /* XXX Probably wrong */ if (v < 0 || v >= c->token) { error("Token index [%d] is out of range", v); return 0.0; /* The empty token */ } if ((TOK(c, v).used & USED_FLOAT) == 0) { const char * myval = get_token_expanded(c, v); TOK(c, v).used |= USED_FLOAT; TOK(c, v).float_value = atof(myval); } return TOK(c, v).float_value;}/* * Get the boolean value of the token */__inline static BooL get_token_boolean (expr_info *c, TOKEN v){ if (v == MAGIC_TOKEN) /* Magic token */ return check_val(c->args); /* XXX Probably wrong */ if (v < 0 || v >= c->token) { error("Token index [%d] is out of range", v); return 0; /* The empty token */ } if ((TOK(c, v).used & USED_BOOLEAN) == 0) { const char * myval = get_token_expanded(c, v); TOK(c, v).used |= USED_BOOLEAN; TOK(c, v).boolean_value = check_val(myval); } return TOK(c, v).boolean_value;}/* *********************** ADD TO OPERAND STACK **************************** *//* * Adding (shifting) and Removing (reducing) operands from the stack is a * fairly straightforward process. The general way to add an token to * the stack is to pass in its TOKEN index. However, there are some times * when you want to shift a value that has not been tokenized. So you call * one of the other functions that will do this for you. */__inline static TOKEN push_token (expr_info *c, TOKEN t){ if (c->sp == STACKSZ - 1) { error("Expressions may not have more than %d operands", STACKSZ); return -1; } else c->sp++; if (x_debug & DEBUG_NEW_MATH_DEBUG) yell("Pushing token [%d] [%s]", t, get_token_expanded(c, t)); return ((c->stack[c->sp] = t));}__inline static TOKEN push_string (expr_info *c, char *val){ return push_token(c, tokenize_expanded(c, val));}__inline static TOKEN push_float (expr_info *c, double val){ return push_token(c, tokenize_float(c, val));}__inline static TOKEN push_integer (expr_info *c, INTTYPE val){ return push_token(c, tokenize_integer(c, val));}__inline static TOKEN push_boolean (expr_info *c, BooL val){ return push_token(c, tokenize_bool(c, val));}__inline static TOKEN push_lval (expr_info *c, const char *val){ return push_token(c, tokenize_lval(c, val));}/*********************** REMOVE FROM OPERAND STACK **************************/__inline static TOKEN top (expr_info *c){ if (c->sp < 0) { error("No operands."); return -1; } else return c->stack[c->sp];}__inline static TOKEN pop_token (expr_info *c){ if (c->sp < 0) { /* * Attempting to pop more operands than are available * Yeilds empty values. Thats probably the most reasonable * course of action. */ error("Cannot pop operand: no more operands"); return 0; } else return c->stack[c->sp--];}__inline static double pop_integer (expr_info *c){ return get_token_integer(c, pop_token(c));}__inline static double pop_float (expr_info *c){ return get_token_float(c, pop_token(c));}__inline static const char * pop_expanded (expr_info *c){ return get_token_expanded(c, pop_token(c));}__inline static BooL pop_boolean (expr_info *c){ return get_token_boolean(c, pop_token(c));}__inline static void pop_2_tokens (expr_info *c, TOKEN *t1, TOKEN *t2){ *t2 = pop_token(c);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -