📄 expr.c
字号:
if (op == LEQ) val1 = val1 <= val2; else if (op == GEQ) val1 = val1 >= val2; else if (op == LT) val1 = val1 < val2; else /* (op == GT) */ val1 = val1 > val2; } return (val1);}/* Left and right shifts. */static intmax_texpshift (){ register intmax_t val1, val2; val1 = exp3 (); while ((curtok == LSH) || (curtok == RSH)) { int op = curtok; readtok (); val2 = exp3 (); if (op == LSH) val1 = val1 << val2; else val1 = val1 >> val2; } return (val1);}static intmax_texp3 (){ register intmax_t val1, val2; val1 = exp2 (); while ((curtok == PLUS) || (curtok == MINUS)) { int op = curtok; readtok (); val2 = exp2 (); if (op == PLUS) val1 += val2; else if (op == MINUS) val1 -= val2; } return (val1);}static intmax_texp2 (){ register intmax_t val1, val2; val1 = exppower (); while ((curtok == MUL) || (curtok == DIV) || (curtok == MOD)) { int op = curtok; readtok (); val2 = exppower (); if (((op == DIV) || (op == MOD)) && (val2 == 0)) evalerror (_("division by 0")); if (op == MUL) val1 *= val2; else if (op == DIV) val1 /= val2; else if (op == MOD) val1 %= val2; } return (val1);}static intmax_texppower (){ register intmax_t val1, val2, c; val1 = exp1 (); while (curtok == POWER) { readtok (); val2 = exppower (); /* exponentiation is right-associative */ if (val2 == 0) return (1); if (val2 < 0) evalerror (_("exponent less than 0")); for (c = 1; val2--; c *= val1) ; val1 = c; } return (val1);}static intmax_texp1 (){ register intmax_t val; if (curtok == NOT) { readtok (); val = !exp1 (); } else if (curtok == BNOT) { readtok (); val = ~exp1 (); } else if (curtok == MINUS) { readtok (); val = - exp1 (); } else if (curtok == PLUS) { readtok (); val = exp1 (); } else val = exp0 (); return (val);}static intmax_texp0 (){ register intmax_t val = 0, v2; char *vincdec; int stok; EXPR_CONTEXT ec; /* XXX - might need additional logic here to decide whether or not pre-increment or pre-decrement is legal at this point. */ if (curtok == PREINC || curtok == PREDEC) { stok = lasttok = curtok; readtok (); if (curtok != STR) /* readtok() catches this */ evalerror (_("identifier expected after pre-increment or pre-decrement")); v2 = tokval + ((stok == PREINC) ? 1 : -1); vincdec = itos (v2); if (noeval == 0) { if (curlval.ind != -1) expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec); else expr_bind_variable (tokstr, vincdec); } free (vincdec); val = v2; curtok = NUM; /* make sure --x=7 is flagged as an error */ readtok (); } else if (curtok == LPAR) { readtok (); val = EXP_HIGHEST (); if (curtok != RPAR) /* ( */ evalerror (_("missing `)'")); /* Skip over closing paren. */ readtok (); } else if ((curtok == NUM) || (curtok == STR)) { val = tokval; if (curtok == STR) { SAVETOK (&ec); tokstr = (char *)NULL; /* keep it from being freed */ noeval = 1; readtok (); stok = curtok; /* post-increment or post-decrement */ if (stok == POSTINC || stok == POSTDEC) { /* restore certain portions of EC */ tokstr = ec.tokstr; noeval = ec.noeval; curlval = ec.lval; lasttok = STR; /* ec.curtok */ v2 = val + ((stok == POSTINC) ? 1 : -1); vincdec = itos (v2); if (noeval == 0) { if (curlval.ind != -1) expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec); else expr_bind_variable (tokstr, vincdec); } free (vincdec); curtok = NUM; /* make sure x++=7 is flagged as an error */ } else { if (stok == STR) /* free new tokstr before old one is restored */ FREE (tokstr); RESTORETOK (&ec); } } readtok (); } else evalerror (_("syntax error: operand expected")); return (val);}static voidinit_lvalue (lv) struct lvalue *lv;{ lv->tokstr = 0; lv->tokvar = 0; lv->tokval = lv->ind = -1;}static struct lvalue *alloc_lvalue (){ struct lvalue *lv; lv = xmalloc (sizeof (struct lvalue)); init_lvalue (lv); return (lv);}static voidfree_lvalue (lv) struct lvalue *lv;{ free (lv); /* should be inlined */}static intmax_texpr_streval (tok, e, lvalue) char *tok; int e; struct lvalue *lvalue;{ SHELL_VAR *v; char *value; intmax_t tval;#if defined (ARRAY_VARS) arrayind_t ind;#endif /* [[[[[ */#if defined (ARRAY_VARS) v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok);#else v = find_variable (tok);#endif if ((v == 0 || invisible_p (v)) && unbound_vars_is_error) {#if defined (ARRAY_VARS) value = (e == ']') ? array_variable_name (tok, (char **)0, (int *)0) : tok;#else value = tok;#endif last_command_exit_value = EXECUTION_FAILURE; err_unboundvar (value);#if defined (ARRAY_VARS) if (e == ']') FREE (value); /* array_variable_name returns new memory */#endif if (interactive_shell) { expr_unwind (); top_level_cleanup (); jump_to_top_level (DISCARD); } else jump_to_top_level (FORCE_EOF); } ind = -1;#if defined (ARRAY_VARS) /* Second argument of 0 to get_array_value means that we don't allow references like array[@]. In this case, get_array_value is just like get_variable_value in that it does not return newly-allocated memory or quote the results. */ value = (e == ']') ? get_array_value (tok, 0, (int *)NULL, &ind) : get_variable_value (v);#else value = get_variable_value (v);#endif tval = (value && *value) ? subexpr (value) : 0; if (lvalue) { lvalue->tokstr = tok; /* XXX */ lvalue->tokval = tval; lvalue->tokvar = v; /* XXX */ lvalue->ind = ind; } return (tval);}static int_is_multiop (c) int c;{ switch (c) { case EQEQ: case NEQ: case LEQ: case GEQ: case LAND: case LOR: case LSH: case RSH: case OP_ASSIGN: case COND: case POWER: case PREINC: case PREDEC: case POSTINC: case POSTDEC: return 1; default: return 0; }}static int_is_arithop (c) int c;{ switch (c) { case EQ: case GT: case LT: case PLUS: case MINUS: case MUL: case DIV: case MOD: case NOT: case LPAR: case RPAR: case BAND: case BOR: case BXOR: case BNOT: return 1; /* operator tokens */ case QUES: case COL: case COMMA: return 1; /* questionable */ default: return 0; /* anything else is invalid */ }}/* Lexical analyzer/token reader for the expression evaluator. Reads the next token and puts its value into curtok, while advancing past it. Updates value of tp. May also set tokval (for number) or tokstr (for string). */static voidreadtok (){ register char *cp, *xp; register unsigned char c, c1; register int e; struct lvalue lval; /* Skip leading whitespace. */ cp = tp; c = e = 0; while (cp && (c = *cp) && (cr_whitespace (c))) cp++; if (c) cp++; if (c == '\0') { lasttok = curtok; curtok = 0; tp = cp; return; } lasttp = tp = cp - 1; if (legal_variable_starter (c)) { /* variable names not preceded with a dollar sign are shell variables. */ char *savecp; EXPR_CONTEXT ec; int peektok; while (legal_variable_char (c)) c = *cp++; c = *--cp;#if defined (ARRAY_VARS) if (c == '[') { e = skipsubscript (cp, 0, 0); if (cp[e] == ']') { cp += e + 1; c = *cp; e = ']'; } else evalerror (bash_badsub_errmsg); }#endif /* ARRAY_VARS */ *cp = '\0'; FREE (tokstr); tokstr = savestring (tp); *cp = c; /* XXX - make peektok part of saved token state? */ SAVETOK (&ec); tokstr = (char *)NULL; /* keep it from being freed */ tp = savecp = cp; noeval = 1; curtok = STR; readtok (); peektok = curtok; if (peektok == STR) /* free new tokstr before old one is restored */ FREE (tokstr); RESTORETOK (&ec); cp = savecp; /* The tests for PREINC and PREDEC aren't strictly correct, but they preserve old behavior if a construct like --x=9 is given. */ if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ) { lastlval = curlval; tokval = expr_streval (tokstr, e, &curlval); } else tokval = 0; lasttok = curtok; curtok = STR; } else if (DIGIT(c)) { while (ISALNUM (c) || c == '#' || c == '@' || c == '_') c = *cp++; c = *--cp; *cp = '\0'; tokval = strlong (tp); *cp = c; lasttok = curtok; curtok = NUM; } else { c1 = *cp++; if ((c == EQ) && (c1 == EQ)) c = EQEQ; else if ((c == NOT) && (c1 == EQ)) c = NEQ; else if ((c == GT) && (c1 == EQ)) c = GEQ; else if ((c == LT) && (c1 == EQ)) c = LEQ; else if ((c == LT) && (c1 == LT)) { if (*cp == '=') /* a <<= b */ { assigntok = LSH; c = OP_ASSIGN; cp++; } else c = LSH; } else if ((c == GT) && (c1 == GT)) { if (*cp == '=') { assigntok = RSH; /* a >>= b */ c = OP_ASSIGN; cp++; } else c = RSH; } else if ((c == BAND) && (c1 == BAND)) c = LAND; else if ((c == BOR) && (c1 == BOR)) c = LOR; else if ((c == '*') && (c1 == '*')) c = POWER; else if ((c == '-' || c == '+') && c1 == c && curtok == STR) c = (c == '-') ? POSTDEC : POSTINC; else if ((c == '-' || c == '+') && c1 == c) { /* Quickly scan forward to see if this is followed by optional whitespace and an identifier. */ xp = cp; while (xp && *xp && cr_whitespace (*xp)) xp++; if (legal_variable_starter ((unsigned char)*xp)) c = (c == '-') ? PREDEC : PREINC; else cp--; /* not preinc or predec, so unget the character */ } else if (c1 == EQ && member (c, "*/%+-&^|")) { assigntok = c; /* a OP= b */ c = OP_ASSIGN; } else if (_is_arithop (c) == 0) { cp--; /* use curtok, since it hasn't been copied to lasttok yet */ if (curtok == 0 || _is_arithop (curtok) || _is_multiop (curtok)) evalerror (_("syntax error: operand expected")); else evalerror (_("syntax error: invalid arithmetic operator")); } else cp--; /* `unget' the character */ /* Should check here to make sure that the current character is one of the recognized operators and flag an error if not. Could create a character map the first time through and check it on subsequent calls. */ lasttok = curtok; curtok = c; } tp = cp;}static voidevalerror (msg) const char *msg;{ char *name, *t; name = this_command_name; for (t = expression; whitespace (*t); t++) ; internal_error (_("%s%s%s: %s (error token is \"%s\")"), name ? name : "", name ? ": " : "", t, msg, (lasttp && *lasttp) ? lasttp : ""); longjmp (evalbuf, 1);}/* Convert a string to an intmax_t integer, with an arbitrary base. 0nnn -> base 8 0[Xx]nn -> base 16 Anything else: [base#]number (this is implemented to match ksh93) Base may be >=2 and <=64. If base is <= 36, the numbers are drawn from [0-9][a-zA-Z], and lowercase and uppercase letters may be used interchangably. If base is > 36 and <= 64, the numbers are drawn from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 -- you get the picture). */static intmax_tstrlong (num) char *num;{ register char *s; register unsigned char c; int base, foundbase; intmax_t val; s = num; base = 10; foundbase = 0; if (*s == '0') { s++; if (*s == '\0') return 0; /* Base 16? */ if (*s == 'x' || *s == 'X') { base = 16; s++; } else base = 8; foundbase++; } val = 0; for (c = *s++; c; c = *s++) { if (c == '#') { if (foundbase) evalerror (_("invalid number")); /* Illegal base specifications raise an evaluation error. */ if (val < 2 || val > 64) evalerror (_("invalid arithmetic base")); base = val; val = 0; foundbase++; } else if (ISALNUM(c) || (c == '_') || (c == '@')) { if (DIGIT(c)) c = TODIGIT(c); else if (c >= 'a' && c <= 'z') c -= 'a' - 10; else if (c >= 'A' && c <= 'Z') c -= 'A' - ((base <= 36) ? 10 : 36); else if (c == '@') c = 62; else if (c == '_') c = 63; if (c >= base) evalerror (_("value too great for base")); val = (val * base) + c; } else break; } return (val);}#if defined (EXPR_TEST)void *xmalloc (n) int n;{ return (malloc (n));}void *xrealloc (s, n) char *s; int n;{ return (realloc (s, n));}SHELL_VAR *find_variable () { return 0;}SHELL_VAR *bind_variable () { return 0; }char *get_string_value () { return 0; }procenv_t top_level;main (argc, argv) int argc; char **argv;{ register int i; intmax_t v; int expok; if (setjmp (top_level)) exit (0); for (i = 1; i < argc; i++) { v = evalexp (argv[i], &expok); if (expok == 0) fprintf (stderr, _("%s: expression error\n"), argv[i]); else printf ("'%s' -> %ld\n", argv[i], v); } exit (0);}intbuiltin_error (format, arg1, arg2, arg3, arg4, arg5) char *format;{ fprintf (stderr, "expr: "); fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); fprintf (stderr, "\n"); return 0;}char *itos (n) intmax_t n;{ return ("42");}#endif /* EXPR_TEST */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -