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

📄 expr2.c

📁 EPIC IRC客户端。来源于IRCII客户端但做了很多性能和功能的优化。
💻 C
📖 第 1 页 / 共 5 页
字号:
			c->operand = 1;			return COMMA;		case '\0':			check_implied_arg(c);			c->operand = 1;			c->ptr--;			return EOI;		/*		 * The {...} operator is really a hack that is left over		 * from the old math parser.  The support for it here is		 * a hack.  The entire thing is a hack.		 */		case '{':		{			char *p = c->ptr;			char oc = 0;			ssize_t	span;			if (!c->operand)				return lexerr(c, "Misplaced { token");			if ((span = MatchingBracket(p, '{', '}')) >= 0)			{				c->ptr = p + span;				oc = *c->ptr;				*c->ptr = 0;			}			else				c->ptr = empty_string;			c->last_token = 0;			if (!c->noeval)			{				char *	result;				result = call_lambda_function(NULL, p, c->args);				c->last_token = tokenize_expanded(c, result);				new_free(&result);			}			if (oc)				*c->ptr++ = oc;			c->operand = 0;			return ID;		}		/******************** OPERAND TYPES **********************/		/*		 * This is an UNEXPANDED-STRING operand type.		 * Extract everything inside the [...]'s, and then		 * tokenize that as a "raw" token.  It will be expanded		 * on an as-needed basis.		 *		 * If we are in the no-eval section of a short-circuit, 		 * then we throw away this token entirely.		 */		case '[':		{			char *p = c->ptr;			char oc = 0;			ssize_t	span;			if (!c->operand)				return lexerr(c, "Misplaced [ token");			if ((span = MatchingBracket(p, '[', ']')) >= 0)			{				c->ptr = p + span;				oc = *c->ptr;				*c->ptr = 0;			}			else				c->ptr = empty_string;			if (c->noeval)				c->last_token = 0;			else				c->last_token = tokenize_raw(c, p);			if (oc)				*c->ptr++ = oc;			c->operand = 0;			return ID;		}		/* The "space" characters. */		case 9: case 10: case 11: case 12: case 13: case ' ':			start++;			break;		/*		 * This is a NUMBER operand type.  This may seem unusual,		 * but we actually tokenize the string representation of		 * the number as an "expanded" token type.  Why do we do		 * this?  Because in the most common case, the user is		 * doing something like:		 *		 *		@ var = 0		 *		 * Now we already have the "0" in string format (natch),		 * and we will never actually reference the 0 as a number		 * per se -- all assignments are done on strings, so we		 * need the string anyhow.  So when we lex a number in the		 * expression, we tokenize it as an 'expanded string' and		 * then if we ever have to actually use the number in any 		 * particular context, it will be converted as-needed.		 */		case '0': case '1': case '2': case '3': case '4':		case '5': case '6': case '7': case '8': case '9':		{			char 	*end;			char 	endc;			c->operand = 0;			c->ptr--;			strtod(c->ptr, &end);			endc = *end;			*end = 0;			if (c->noeval)				c->last_token = 0;			else				c->last_token = tokenize_expanded(c, c->ptr);			*end = endc;			c->ptr = end;			return ID;		}		/*		 * Handle those weirdo $-values		 */		case '$':			continue;		/*		 * This is an LVAL operand type.  This also may seem 		 * unusual, but lval's may contain $'s, which need to		 * be expanded.  They may contain function calls, which		 * must only be expanded *once*.  When we lex out an lval		 * (such as "var" in "@ var = 5"), we tokenize the lval		 * as an unexpanded lval.  Then, if we ever actually need		 * to reference the proper variable name, we will get the		 * "raw" value, which will be the lval after passed through		 * expand_alias().  If we want to get the *value of the		 * variable $lval), then we will get the "expanded" value,		 * which will use the "raw" value to do the variable name		 * lookup.  See?  It's really pretty straightforward.  The		 * reason we do all this is to make sure that the expansion		 * of the variable name happens *at most once*, and that if		 * the variable is not actually referenced, then the expansion		 * isn't done at all.		 */		default:handle_expando:		{			char 	*end;			char	endc;			c->operand = 0;			c->ptr--;			if ((end = after_expando_special(c)))			{				endc = *end;				*end = 0;				/*				 * If we are in the short-circuit of a noeval,				 * then we throw the token away.				 */				if (c->noeval)					c->last_token = 0;				else					c->last_token = tokenize_lval(c, start);				*end = endc;				c->ptr = end;			}			else			{				c->last_token = 0; /* Empty token */				c->ptr = empty_string;			}			if (x_debug & DEBUG_NEW_MATH_DEBUG)				yell("After token: [%s]", c->ptr);			return ID;		}	    }	}}/******************************* STATE MACHINE *****************************//* * mathparse -- this is the state machine that actually parses the * expression.   The parsing is done through a shift-reduce mechanism, * and all the precedence levels lower than 'pc' are evaluated. */static void	mathparse (expr_info *c, int pc){	int	otok, 		onoeval;	/*	 * Drop out of parsing if an error has occured	 */	if (c->errflag)		return;	/*	 * Get the next token in the expression	 */	c->mtok = zzlex(c);	/*	 * For as long as the next operator indicates a shift operation...	 */	while (prec[c->mtok] <= pc) 	{	    /* Drop out if an error has occured */	    if (c->errflag)		return;	    /*	     * Figure out what to do with this token that needs	     * to be shifted.	     */	    switch (c->mtok) 	    {		/*		 * This is any kind of an indentifier.  There are several		 * that we handle:		 *		 *	VARIABLE REFERENCE	ie, "foo"   in "@ foo = 2"		 *	NUMBER			ie, "2"     in "@ foo = 2"		 *	UNEXPANDED STRING	ie, "[boo]" in "@ foo = [boo]"		 *		 * The actual determination of which type is done in the lexer.		 * We just get a token id for the resulting identifier.		 * Getting the value is done on an as-needed basis.		 */		case ID:			if (x_debug & DEBUG_NEW_MATH_DEBUG)				yell("Parsed identifier token [%s]", 					get_token_expanded(c, c->last_token));			/* 			 * The lexer sets the last token to			 * 0 if noeval is set.  This saves us			 * from having to tokenize a string			 * that we expressly will not use.			 */			push_token(c, c->last_token);			break;		/*		 * An open-parenthesis indicates that we should		 * recursively evaluate the inside of the paren-set.		 */		case M_INPAR:		{			if (x_debug & DEBUG_NEW_MATH_DEBUG)				yell("Parsed open paren");			mathparse(c, TOPPREC);			/*			 * Of course if the expression ends without			 * a matching rparen, then we whine about it.			 */			if (c->mtok != M_OUTPAR) 			{				if (!c->errflag)				    error("')' expected");				return;			}			break;		}		/*		 * A question mark requires that we check for short		 * circuiting.  We check the lhs, and if it is true,		 * then we evaluate the lhs of the colon.  If it is		 * false then we just parse the lhs of the colon and		 * evaluate the rhs of the colon.		 */		case QUEST:		{			BooL u = pop_boolean(c);			push_boolean(c, u);			if (!u)				c->noeval++;			mathparse(c, prec[QUEST] - 1);			if (!u)				c->noeval--;			else				c->noeval++;			mathparse(c, prec[QUEST]);			if (u)				c->noeval--;			reduce(c, QUEST);			continue;		}		/*		 * All other operators handle normally		 */		default:		{			/* Save state */			otok = c->mtok;			onoeval = c->noeval;			/*			 * Check for short circuiting.			 */			if (assoc[otok] == BOOL)			{			    if (x_debug & DEBUG_NEW_MATH_DEBUG)				yell("Parsed short circuit operator");			    switch (otok)			    {				case DAND:				case DANDEQ:				{					BooL u = pop_boolean(c);					push_boolean(c, u);					if (!u)						c->noeval++;					break;				}				case DOR:				case DOREQ:				{					BooL u = pop_boolean(c);					push_boolean(c, u);					if (u)						c->noeval++;					break;				}			    }			}		 	if (x_debug & DEBUG_NEW_MATH_DEBUG)			    yell("Parsed operator of type [%d]", otok);			/*			 * Parse the right hand side through			 * recursion if we're doing things R->L.			 */			mathparse(c, prec[otok] - (assoc[otok] != RL));			/*			 * Then reduce this operation.			 */			c->noeval = onoeval;			reduce(c, otok);			continue;		}	    }	    /*	     * Grab the next token	     */	    c->mtok = zzlex(c);	}}/******************************** HARNASS **********************************//* * This is the new math parser.  It sets up an execution context, which * contains sundry information like all the extracted tokens, intermediate * tokens, shifted tokens, and the like.  The expression context is passed * around from function to function, each function is totaly independant * of state information stored in global variables.  Therefore, this math * parser is re-entrant safe. */static char *	matheval (char *s, const char *args, int *args_flag){	expr_info	context;	char *		ret = NULL;	/* Sanity check */	if (!s || !*s)		return malloc_strdup(empty_string);	/* Create new state */	setup_expr_info(&context);	context.ptr = s;	context.args = args;	context.args_flag = args_flag;	/* Actually do the parsing */	mathparse(&context, TOPPREC);	/* Check for error */	if (context.errflag)	{		ret = malloc_strdup(empty_string);		goto cleanup;	}	/* Check for leftover operands */	if (context.sp)		error("The expression has too many operands");	if (x_debug & DEBUG_NEW_MATH_DEBUG)	{		int i;		yell("Terms left: %d", context.sp);		for (i = 0; i <= context.sp; i++)			yell("Term [%d]: [%s]", i, 				get_token_expanded(&context, context.stack[i]));	}	/* Get the return value, if requested */	ret = malloc_strdup(get_token_expanded(&context, pop_token(&context)));cleanup:	/* Clean up and restore order */	destroy_expr_info(&context);	if (x_debug & DEBUG_NEW_MATH_DEBUG)		yell("Returning [%s]", ret);	/* Return the result */	return ret;}/******************************* SUPPORT *************************************//* * after_expando_special: This is a special version of after_expando that * can handle parsing out lvalues in expressions.  Due to the eclectic nature * of lvalues in expressions, this is quite a bit different than the normal * after_expando, requiring a different function. Ugh. * * This replaces some much more complicated logic strewn * here and there that attempted to figure out just how long an expando  * name was supposed to be.  Well, now this changes that.  This will slurp * up everything in 'start' that could possibly be put after a $ that could * result in a syntactically valid expando.  All you need to do is tell it * if the expando is an rvalue or an lvalue (it *does* make a difference) */static  char *	after_expando_special (expr_info *c){	char	*start;	char	*rest;	int	call;	if (!(start = c->ptr))		return c->ptr;	for (;;)	{		rest = after_expando(start, 0, &call);		if (*rest != '$')			break;		start = rest + 1;	}	if (c->ptr == rest)	{		yell("Erf.  I'm trying to find an lval at [%s] and I'm not "			"having much luck finding one.  Punting the rest of "			"this expression", c->ptr);		return NULL;	}	/*	 * All done!	 */	return rest;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -