⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 expr2.c

📁 EPIC IRC客户端。来源于IRCII客户端但做了很多性能和功能的优化。
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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 + -