/* ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { BinOpr op; UnOpr uop; enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(ls->fs, uop, v); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls->t.token); while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(ls->fs, op, v, &v2); op = nextop; } leavelevel(ls); return op; /* return first untreated operator */ }
/* ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { callstack_ref cref( *ls->L ); UnOpr uop = getunopr(ls->t.token); FuncState *fs = GetCurrentFuncState( ls ); if (uop != OPR_NOUNOPR) { luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(fs, uop, v); } else { simpleexp(ls, v); } /* expand while operators have priorities higher than `limit' */ BinOpr op = getbinopr(ls->t.token); while (op != OPR_NOBINOPR && priority[op].left > limit) { luaX_next(ls); luaK_infix(fs, op, v); /* read sub-expression with higher priority */ expdesc v2; BinOpr nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(fs, op, v, &v2); op = nextop; } return op; /* return first untreated operator */ }
long ppexpr(int* pun) { long n; int opeektoken; long ppstate; ppstate = (pp.state & (CONDITIONAL|DISABLE|NOSPACE|STRIP)); pp.state &= ~(DISABLE|STRIP); pp.state |= CONDITIONAL|NOSPACE; opeektoken = peektoken; peektoken = -1; *pun = 0; n = subexpr(0, pun); if (peektoken == ':' && !errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid use of :"; if (errmsg) { error(2, "%s in expression", errmsg); errmsg = 0; n = 0; } peektoken = opeektoken; pp.state &= ~(CONDITIONAL|NOSPACE); pp.state |= ppstate; if (*pun) debug((-4, "ppexpr() = %luU", n)); else debug((-4, "ppexpr() = %ld", n)); return n; }
static BinaryOperationsChain ParseBinaryOperatorsChain( const Lexems& lexems, Lexems::const_iterator& it ) { BinaryOperationsChain result; while( it < lexems.end() ) { BinaryOperationsChain::ComponentWithOperator comp; switch (it->type) { case Lexem::Type::Identifier: case Lexem::Type::Scope: { std::unique_ptr<BinaryOperationsChain::Variable> var( new BinaryOperationsChain::Variable ); var->name= ParseCombinedName( lexems, it ); comp.component= std::move(var); } break; case Lexem::Type::BracketLeft: { it++; if( it == lexems.end()) throw LexicalError(lexems.back().file_position); std::unique_ptr<BinaryOperationsChain::BracketExpression> subexpr( new BinaryOperationsChain::BracketExpression ); subexpr->subexpression.reset( new BinaryOperationsChain(ParseBinaryOperatorsChain( lexems, it )) ); comp.component= std::move(subexpr); if( it->type != Lexem::Type::BracketRight ) throw LexicalError( it->file_position); it++; } break; case Lexem::Type::NumericConstant: { std::unique_ptr<BinaryOperationsChain::NumericConstant> num( new BinaryOperationsChain::NumericConstant ); num->value= it->text; it++; comp.component= std::move(num); } break; default: goto end; }; BinaryOperationsChain::Operator op= ParseBinaryOperator( it ); comp.op= op; result.components.push_back(std::move(comp)); if( op == BinaryOperationsChain::Operator::NoOperator ) break; } end:; return result; }
static void expr (LexState *ls, expdesc *v) { subexpr(ls, v, 0); }
static void primaryexp (LexState *ls, expdesc *v) { /* primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; prefixexp(ls, v); for (;;) { switch (ls->t.token) { case '.': { /* field */ field(ls, v); break; } case '[': { /* `[' exp1 `]' */ expdesc key; luaK_exp2anyreg(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; } case ':': { /* `:' NAME funcargs */ expdesc key; luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); funcargs(ls, v); break; } #if LUA_WIDESTRING case '(': case TK_STRING: case TK_WSTRING: case '{': { /* funcargs */ #else case '(': case TK_STRING: case '{': { /* funcargs */ #endif /* LUA_WIDESTRING */ luaK_exp2nextreg(fs, v); funcargs(ls, v); break; } default: return; } } } static void simpleexp (LexState *ls, expdesc *v) { #if LUA_WIDESTRING /* simpleexp -> NUMBER | STRING | WSTRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp */ #else /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp */ #endif /* LUA_WIDESTRING */ switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VKNUM, 0); v->u.nval = ls->t.seminfo.r; break; } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); break; } #if LUA_WIDESTRING case TK_WSTRING: { codewstring(ls, v, ls->t.seminfo.ts); break; } #endif /* LUA_WIDESTRING */ case TK_NIL: { init_exp(v, VNIL, 0); break; } case TK_TRUE: { init_exp(v, VTRUE, 0); break; } case TK_FALSE: { init_exp(v, VFALSE, 0); break; } case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, "cannot use " LUA_QL("...") " outside a vararg function"); fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } case '{': { /* constructor */ constructor(ls, v); return; } case TK_FUNCTION: { luaX_next(ls); body(ls, v, 0, ls->linenumber); return; } default: { primaryexp(ls, v); return; } } luaX_next(ls); } static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; case '#': return OPR_LEN; default: return OPR_NOUNOPR; } } static BinOpr getbinopr (int op) { switch (op) { case '+': return OPR_ADD; case '-': return OPR_SUB; case '*': return OPR_MUL; case '/': return OPR_DIV; case '%': return OPR_MOD; #if LUA_BITFIELD_OPS case '&': return OPR_BAND; case '|': return OPR_BOR; case TK_XOR: return OPR_BXOR; case TK_SHL: return OPR_BSHL; case TK_SHR: return OPR_BSHR; #endif /* LUA_BITFIELD_OPS */ case '^': return OPR_POW; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; case TK_EQ: return OPR_EQ; case '<': return OPR_LT; case TK_LE: return OPR_LE; case '>': return OPR_GT; case TK_GE: return OPR_GE; case TK_AND: return OPR_AND; case TK_OR: return OPR_OR; default: return OPR_NOBINOPR; } } static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ #if LUA_BITFIELD_OPS {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, /* bitwise operators */ #endif /* LUA_BITFIELD_OPS */ {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ {10, 9}, {5, 4}, /* power and concat (right associative) */ {3, 3}, {3, 3}, /* equality and inequality */ {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ {2, 2}, {1, 1} /* logical (and/or) */ }; #define UNARY_PRIORITY 8 /* priority for unary operators */ /* ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { BinOpr op; UnOpr uop; enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(ls->fs, uop, v); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls->t.token); while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(ls->fs, op, v, &v2); op = nextop; } leavelevel(ls); return op; /* return first untreated operator */ }
static void ICACHE_FLASH_ATTR expr (LexState *ls, expdesc *v) { subexpr(ls, v, 0); }
static long subexpr(register int precedence, int* pun) { register int c; register long n; register long x; register int operand = 1; int un = 0; int xn; switch (lex(c)) { case 0: case '\n': unlex(c); if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "more tokens expected"; return 0; case '-': n = -subexpr(13, &un); break; case '+': n = subexpr(13, &un); break; case '!': n = !subexpr(13, &un); break; case '~': n = ~subexpr(13, &un); break; default: unlex(c); n = 0; operand = 0; break; } un <<= 1; for (;;) { switch (lex(c)) { case 0: case '\n': goto done; case ')': if (!precedence) { if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "too many )'s"; return 0; } goto done; case '(': n = subexpr(1, &un); if (lex(c) != ')') { unlex(c); if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "closing ) expected"; return 0; } gotoperand: if (operand) { if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operator expected"; return 0; } operand = 1; un <<= 1; continue; case '?': if (precedence > 1) goto done; un = 0; if (lex(c) == ':') { if (!n) n = subexpr(2, &un); else { x = pp.mode; pp.mode |= INACTIVE; subexpr(2, &xn); pp.mode = x; } } else { unlex(c); x = subexpr(2, &xn); if (lex(c) != ':') { unlex(c); if (!errmsg && !(pp.mode & INACTIVE)) errmsg = ": expected for ? operator"; return 0; } if (n) { n = x; un = xn; subexpr(2, &xn); } else n = subexpr(2, &un); } break; case ':': goto done; case T_ANDAND: case T_OROR: xn = (c == T_ANDAND) ? 4 : 3; if (precedence >= xn) goto done; if ((n != 0) == (c == T_ANDAND)) n = subexpr(xn, &un) != 0; else { x = pp.mode; pp.mode |= INACTIVE; subexpr(xn, &un); pp.mode = x; } un = 0; break; case '|': if (precedence > 4) goto done; n |= subexpr(5, &un); break; case '^': if (precedence > 5) goto done; n ^= subexpr(6, &un); break; case '&': if (precedence > 6) goto done; n &= subexpr(7, &un); break; case T_EQ: case T_NE: if (precedence > 7) goto done; n = (n == subexpr(8, &un)) == (c == T_EQ); un = 0; break; case '<': case T_LE: case T_GE: case '>': if (precedence > 8) goto done; x = subexpr(9, &un); switch (c) { case '<': switch (un) { case 01: n = n < (unsigned long)x; break; case 02: n = (unsigned long)n < x; break; case 03: n = (unsigned long)n < (unsigned long)x; break; default: n = n < x; break; } break; case T_LE: switch (un) { case 01: n = n <= (unsigned long)x; break; case 02: n = (unsigned long)n <= x; break; case 03: n = (unsigned long)n <= (unsigned long)x; break; default: n = n <= x; break; } break; case T_GE: switch (un) { case 01: n = n >= (unsigned long)x; break; case 02: n = (unsigned long)n >= x; break; case 03: n = (unsigned long)n >= (unsigned long)x; break; default: n = n >= x; break; } break; case '>': switch (un) { case 01: n = n > (unsigned long)x; break; case 02: n = (unsigned long)n > x; break; case 03: n = (unsigned long)n > (unsigned long)x; break; default: n = n > x; break; } break; } un = 0; break; case T_LSHIFT: case T_RSHIFT: if (precedence > 9) goto done; x = subexpr(10, &un); if (c == T_LSHIFT) n <<= x; else n >>= x; un >>= 1; break; case '+': case '-': if (precedence > 10) goto done; x = subexpr(11, &un); if (c == '+') n += x; else n -= x; break; case '*': case '/': case '%': if (precedence > 11) goto done; x = subexpr(12, &un); if (c == '*') n *= x; else if (x == 0) { if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "divide by zero"; return 0; } else if (c == '/') n /= x; else n %= x; break; case '#': pp.state |= DISABLE; c = pplex(); pp.state &= ~DISABLE; if (c != T_ID) { if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "# must precede a predicate identifier"; return 0; } n = predicate(0); goto gotoperand; case T_ID: n = predicate(1); goto gotoperand; case T_CHARCONST: c = *(pp.toknxt - 1); *(pp.toknxt - 1) = 0; n = chrtoi(pp.token + 1); *(pp.toknxt - 1) = c; if (n & ~((1<<CHAR_BIT)-1)) { if (!(pp.mode & HOSTED)) error(1, "'%s': multi-character character constants are not portable", pp.token); } #if CHAR_MIN < 0 else n = (char)n; #endif goto gotoperand; case T_DECIMAL_U: case T_DECIMAL_UL: case T_OCTAL_U: case T_OCTAL_UL: case T_HEXADECIMAL_U: case T_HEXADECIMAL_UL: un |= 01; /*FALLTHROUGH*/ case T_DECIMAL: case T_DECIMAL_L: case T_OCTAL: case T_OCTAL_L: case T_HEXADECIMAL: case T_HEXADECIMAL_L: n = strtoul(pp.token, NiL, 0); if ((unsigned long)n > LONG_MAX) un |= 01; goto gotoperand; case T_WCHARCONST: n = chrtoi(pp.token); goto gotoperand; default: if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid token"; return 0; } if (errmsg) return 0; if (!operand) goto nooperand; } done: unlex(c); if (!operand) { nooperand: if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operand expected"; return 0; } if (un) *pun |= 01; return n; }