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

📄 eval.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
	return NULL;
    }
}

/*
 * types for expressions.
 */
enum exp_type
{
    TYPE_UNKNOWN = 0,
    TYPE_EQUAL,		/* == */
    TYPE_NEQUAL,	/* != */
    TYPE_GREATER,	/* >  */
    TYPE_GEQUAL,	/* >= */
    TYPE_SMALLER,	/* <  */
    TYPE_SEQUAL,	/* <= */
    TYPE_MATCH,		/* =~ */
    TYPE_NOMATCH	/* !~ */
};

/*
 * Handle zero level expression.
 * This calls eval1() and handles error message and nextcmd.
 * Return OK or FAIL.
 */
    static int
eval0(arg, retvar, nextcmd)
    char_u	*arg;
    VAR		retvar;
    char_u	**nextcmd;
{
    int		ret;
    char_u	*p;

    p = skipwhite(arg);
    ret = eval1(&p, retvar);
    if (ret == FAIL || !ends_excmd(*p))
    {
	if (ret != FAIL)
	    clear_var(retvar);
	EMSG2(e_invexpr2, arg);
	ret = FAIL;
    }
    if (nextcmd != NULL)
	*nextcmd = check_nextcmd(p);

    return ret;
}

/*
 * Handle first level expression:
 *	expr2 || expr2 || expr2	    logical OR
 *
 * "arg" must point to the first non-white of the expression.
 * "arg" is advanced to the next non-white after the recognized expression.
 *
 * Return OK or FAIL.
 */
    static int
eval1(arg, retvar)
    char_u	**arg;
    VAR		retvar;
{
    var		var2;
    long	n1, n2;

    /*
     * Get the first variable.
     */
    if (eval2(arg, retvar) == FAIL)
	return FAIL;

    /*
     * Repeat until there is no following "||".
     */
    while ((*arg)[0] == '|' && (*arg)[1] == '|')
    {
	n1 = get_var_number(retvar);
	clear_var(retvar);

	/*
	 * Get the second variable.
	 */
	*arg = skipwhite(*arg + 2);
	if (eval2(arg, &var2) == FAIL)
	    return FAIL;

	/*
	 * Compute the result.
	 */
	n2 = get_var_number(&var2);
	clear_var(&var2);
	retvar->var_type = VAR_NUMBER;
	retvar->var_val.var_number = (n1 || n2);
    }

    return OK;
}

/*
 * Handle second level expression:
 *	expr3 && expr3 && expr3	    logical AND
 *
 * "arg" must point to the first non-white of the expression.
 * "arg" is advanced to the next non-white after the recognized expression.
 *
 * Return OK or FAIL.
 */
    static int
eval2(arg, retvar)
    char_u	**arg;
    VAR		retvar;
{
    var		var2;
    long	n1, n2;

    /*
     * Get the first variable.
     */
    if (eval3(arg, retvar) == FAIL)
	return FAIL;

    /*
     * Repeat until there is no following "&&".
     */
    while ((*arg)[0] == '&' && (*arg)[1] == '&')
    {
	n1 = get_var_number(retvar);
	clear_var(retvar);

	/*
	 * Get the second variable.
	 */
	*arg = skipwhite(*arg + 2);
	if (eval3(arg, &var2) == FAIL)
	    return FAIL;

	/*
	 * Compute the result.
	 */
	n2 = get_var_number(&var2);
	clear_var(&var2);
	retvar->var_type = VAR_NUMBER;
	retvar->var_val.var_number = (n1 && n2);
    }

    return OK;
}

/*
 * Handle third level expression:
 *	var1 == var2
 *	var1 =~ var2
 *	var1 != var2
 *	var1 !~ var2
 *	var1 > var2
 *	var1 >= var2
 *	var1 < var2
 *	var1 <= var2
 *
 * "arg" must point to the first non-white of the expression.
 * "arg" is advanced to the next non-white after the recognized expression.
 *
 * Return OK or FAIL.
 */
    static int
eval3(arg, retvar)
    char_u	**arg;
    VAR		retvar;
{
    var			var2;
    char_u		*p;
    int			i = 0;
    enum exp_type	type = TYPE_UNKNOWN;
    int			len = 2;
    long		n1 = FALSE, n2;
    char_u		*s1, *s2;
    char_u		buf1[NUMBUFLEN], buf2[NUMBUFLEN];
    vim_regexp		*prog;

    /*
     * Get the first variable.
     */
    if (eval4(arg, retvar) == FAIL)
	return FAIL;

    p = *arg;
    switch (p[0])
    {
	case '=':   if (p[1] == '=')
			type = TYPE_EQUAL;
		    else if (p[1] == '~')
			type = TYPE_MATCH;
		    break;
	case '!':   if (p[1] == '=')
			type = TYPE_NEQUAL;
		    else if (p[1] == '~')
			type = TYPE_NOMATCH;
		    break;
	case '>':   if (p[1] != '=')
		    {
			type = TYPE_GREATER;
			len = 1;
		    }
		    else
			type = TYPE_GEQUAL;
		    break;
	case '<':   if (p[1] != '=')
		    {
			type = TYPE_SMALLER;
			len = 1;
		    }
		    else
			type = TYPE_SEQUAL;
		    break;
    }

    /*
     * If there is a comparitive operator, use it.
     */
    if (type != TYPE_UNKNOWN)
    {
	/*
	 * Get the second variable.
	 */
	*arg = skipwhite(p + len);
	if (eval4(arg, &var2) == FAIL)
	{
	    clear_var(retvar);
	    return FAIL;
	}

	/*
	 * If one of the two variables is a number, compare as a number.
	 * When using "=~" or "!~", always compare as string.
	 */
	if ((retvar->var_type == VAR_NUMBER || var2.var_type == VAR_NUMBER)
		&& type != TYPE_MATCH && type != TYPE_NOMATCH)
	{
	    n1 = get_var_number(retvar);
	    n2 = get_var_number(&var2);
	    switch (type)
	    {
		case TYPE_EQUAL:    n1 = (n1 == n2); break;
		case TYPE_NEQUAL:   n1 = (n1 != n2); break;
		case TYPE_GREATER:  n1 = (n1 > n2); break;
		case TYPE_GEQUAL:   n1 = (n1 >= n2); break;
		case TYPE_SMALLER:  n1 = (n1 < n2); break;
		case TYPE_SEQUAL:   n1 = (n1 <= n2); break;
		case TYPE_UNKNOWN:
		case TYPE_MATCH:
		case TYPE_NOMATCH:  break;  /* avoid gcc warning */
	    }
	}
	else
	{
	    s1 = get_var_string_buf(retvar, buf1);
	    s2 = get_var_string_buf(&var2, buf2);
	    if (type != TYPE_MATCH && type != TYPE_NOMATCH)
		i = STRCMP(s1, s2);
	    switch (type)
	    {
		case TYPE_EQUAL:    n1 = (i == 0); break;
		case TYPE_NEQUAL:   n1 = (i != 0); break;
		case TYPE_GREATER:  n1 = (i > 0); break;
		case TYPE_GEQUAL:   n1 = (i >= 0); break;
		case TYPE_SMALLER:  n1 = (i < 0); break;
		case TYPE_SEQUAL:   n1 = (i <= 0); break;
		case TYPE_MATCH:
		case TYPE_NOMATCH:  reg_ic = p_ic;
				    prog = vim_regcomp(s2, TRUE);
				    if (prog != NULL)
				    {
					n1 = vim_regexec(prog, s1, TRUE);
					vim_free(prog);
					if (type == TYPE_NOMATCH)
					    n1 = !n1;
				    }
				    break;
		case TYPE_UNKNOWN:  break;  /* avoid gcc warning */
	    }
	}
	clear_var(retvar);
	clear_var(&var2);
	retvar->var_type = VAR_NUMBER;
	retvar->var_val.var_number = n1;
    }

    return OK;
}

/*
 * Handle fourth level expression:
 *	+	number addition
 *	-	number subtraction
 *	.	string concatenation
 *
 * "arg" must point to the first non-white of the expression.
 * "arg" is advanced to the next non-white after the recognized expression.
 *
 * Return OK or FAIL.
 */
    static int
eval4(arg, retvar)
    char_u	**arg;
    VAR		retvar;
{
    var		var2;
    int		op;
    long	n1, n2;
    char_u	*s1, *s2;
    char_u	buf1[NUMBUFLEN], buf2[NUMBUFLEN];
    char_u	*p;

    /*
     * Get the first variable.
     */
    if (eval5(arg, retvar) == FAIL)
	return FAIL;

    /*
     * Repeat computing, until no '+', '-' or '.' is following.
     */
    for (;;)
    {
	op = **arg;
	if (op != '+' && op != '-' && op != '.')
	    break;

	/*
	 * Get the second variable.
	 */
	*arg = skipwhite(*arg + 1);
	if (eval5(arg, &var2) == FAIL)
	{
	    clear_var(retvar);
	    return FAIL;
	}

	/*
	 * Compute the result.
	 */
	if (op == '.')
	{
	    s1 = get_var_string_buf(retvar, buf1);
	    s2 = get_var_string_buf(&var2, buf2);
	    p = alloc((unsigned)(STRLEN(s1) + STRLEN(s2) + 1));
	    if (p != NULL)
	    {
		STRCPY(p, s1);
		STRCAT(p, s2);
	    }
	    clear_var(retvar);
	    retvar->var_type = VAR_STRING;
	    retvar->var_val.var_string = p;
	}
	else
	{
	    n1 = get_var_number(retvar);
	    n2 = get_var_number(&var2);
	    clear_var(retvar);
	    if (op == '+')
		n1 = n1 + n2;
	    else
		n1 = n1 - n2;
	    retvar->var_type = VAR_NUMBER;
	    retvar->var_val.var_number = n1;
	}
	clear_var(&var2);
    }
    return OK;
}

/*
 * Handle fifth level expression:
 *	*	number multiplication
 *	/	number division
 *	%	number modulo
 *
 * "arg" must point to the first non-white of the expression.
 * "arg" is advanced to the next non-white after the recognized expression.
 *
 * Return OK or FAIL.
 */
    static int
eval5(arg, retvar)
    char_u	**arg;
    VAR		retvar;
{
    var		var2;
    int		op;
    long	n1, n2;

    /*
     * Get the first variable.
     */
    if (eval6(arg, retvar) == FAIL)
	return FAIL;

    /*
     * Repeat computing, until no '*', '/' or '%' is following.
     */
    for (;;)
    {
	op = **arg;
	if (op != '*' && op != '/' && op != '%')
	    break;

	n1 = get_var_number(retvar);
	clear_var(retvar);

	/*
	 * Get the second variable.
	 */
	*arg = skipwhite(*arg + 1);
	if (eval6(arg, &var2) == FAIL)
	    return FAIL;
	n2 = get_var_number(&var2);
	clear_var(&var2);

	/*
	 * Compute the result.
	 */
	if (op == '*')
	    n1 = n1 * n2;
	else if (op == '/')
	{
	    if (n2 == 0)	/* give an error message? */
		n1 = 0x7fffffff;
	    else
		n1 = n1 / n2;
	}
	else
	{
	    if (n2 == 0)	/* give an error message? */
		n1 = 0;
	    else
		n1 = n1 % n2;
	}
	retvar->var_type = VAR_NUMBER;
	retvar->var_val.var_number = n1;
    }

    return OK;
}

/*
 * Handle sixth level expression:
 *  number		number constant
 *  "string"		string contstant
 *  *option-name	option value
 *  @r			register contents
 *  identifier		variable value
 *  $VAR		environment variable
 *  (expression)	nested expression
 *
 *  Also handle:
 *  ! in front		logical NOT
 *  - in front		unary minus
 *  trailing []		subscript in String
 *
 * "arg" must point to the first non-white of the expression.
 * "arg" is advanced to the next non-white after the recognized expression.
 *
 * Return OK or FAIL.
 */
    static int
eval6(arg, retvar)
    char_u	**arg;
    VAR		retvar;
{
    var		var2;
    long	n;
    int		len;
    char_u	*s;
    int		val;
    char_u	*start_leader, *end_leader;
    int		ret = OK;

    /*
     * Skip '!' and '-' characters.  They are handled later.
     */
    start_leader = *arg;
    while (**arg == '!' || **arg == '-')
	*arg = skipwhite(*arg + 1);
    end_leader = *arg;

    switch (**arg)
    {
    /*
     * Number constant.
     */
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
		retvar->var_type = VAR_NUMBER;
		vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL);
		retvar->var_val.var_number = n;
		*arg += len;
		break;

    /*
     * String constant: "string".
     */
    case '\"':	ret = get_string_var(arg, retvar);
		break;

    /*
     * Literal string constant: 'string'.
     */
    case '\'':	ret = get_lit_string_var(arg, retvar);
		break;

    /*
     * Option value: &name
     */
    case '&':	ret = get_option_var(arg, retvar);
		break;

    /*
     * Environment variable: $VAR.
     */
    case '$':	ret = get_env_var(arg, retvar);
		break;

    /*
     * Register contents: @r.
     */
    case '@':	retvar->var_type = VAR_STRING;
		retvar->var_val.var_string = get_reg_contents(*++*arg);
		if (**arg != NUL)
		    ++*arg;
		break;

    /*
     * nested expression: (expression).
     */
    case '(':	*arg = skipwhite(*arg + 1);
		ret = eval1(arg, retvar);	/* recursive! */
		if (**arg != ')')
		    EMSG("Missing ')'");
		else
		    ++*arg;
		break;

    /*
     * Must be a variable or function name then.
     */
    default:	s = *arg;
		len = get_id_len(arg);
		if (len)
		{
		    if (**arg == '(')		/* recursive! */
			ret = get_func_var(s, len, retvar, arg,
			  curwin->w_cursor.lnum, curwin->w_cursor.lnum, &len);
		    else
			ret = get_var_var(s, len, retvar);
		}
		else
		    ret = FAIL;
		break;
    }
    *arg = skipwhite(*arg);

    /*
     * Handle expr[expr] subscript.
     */
    if (**arg == '[' && ret == OK)
    {
	/*
	 * Get the variable from inside the [].
	 */
	*arg = skipwhite(*arg + 1);
	if (eval1(arg, &var2) == FAIL)		/* recursive! */
	{
	    clear_var(retvar);
	    return FAIL;
	}
	n = get_var_number(&var2);
	clear_var(&var2);

	/* Check for the ']'. */
	if (**arg != ']')
	{
	    EMSG("Missing ']'");
	    clear_var(retvar);
	    return FAIL;
	}

	/*
	 * The resulting variable is a string of a single character.
	 * If the index is too big or negative, the result is empty.
	 */
	s = get_var_string(retvar);
	if (n >= (long)STRLEN(s) || n < 0)
	    s = NULL;
	else
	    s = vim_strnsave(s + n, 1);
	clear_var(retvar);
	retvar->var_type = VAR_STRING;
	retvar->var_val.var_string = s;

	*arg = skipwhite(*arg + 1);	/* skip the ']' */
    }

⌨️ 快捷键说明

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