PExprAST Parser::parse_binop_rhs(int precedence_min, PExprAST lhs) { // We will try to read operators and replace the // current lhs by a bigger one, until there is // no more tokens. while (true) { int token_precedence = get_token_precedence(); // If it's not a binop or it's a binop with // lower precedence. if (token_precedence < precedence_min) return lhs; //We know it's a binop, so we read [op, prim] Token binop = current_tok; get_next_token(); // eat the binop PExprAST rhs = parse_primary(); // If the next token have a stronger precedence, // we should compute it as belonging to rhs. int next_precedence = get_token_precedence(); if (next_precedence > token_precedence) rhs = PExprAST(parse_binop_rhs(token_precedence + 1, rhs)); //Otherwise, we replace the lhs by 'lhs, op, prim' lhs = PExprAST(new BinaryExprAST(binop, lhs, rhs)); } }
/// binoprhs: ([+*/^-] primary)* ex parser::parse_binop_rhs(int expr_prec, ex& lhs) { exvector args; args.push_back(lhs); int binop = -1, orig_binop = -1; bool need_sign_flip = false; while (1) { // check if this is a binop if (!is_binop(token)) { if (args.size() > 1) return make_binop_expr(orig_binop, args); else return lhs; } // Okay, we know this is a binop. if (args.size() == 1) orig_binop = token; binop = token; // If this is a binop that binds at least as tightly as // the current binop, consume it, otherwise we are done. int tok_prec = get_tok_prec(token); if (tok_prec < expr_prec) { if (args.size() > 1) return make_binop_expr(orig_binop, args); else return lhs; } get_next_tok(); // eat binop // Parse the primary expression after the binary operator. ex rhs = parse_primary(); // If binop binds less tightly with rhs than the operator after // rhs, let the pending operator take rhs as its lhs. int next_prec = get_tok_prec(token); if (tok_prec < next_prec) rhs = parse_binop_rhs(tok_prec + 1, rhs); // previous operator was '+', and current one is '-' // (or vice a versa). if (need_sign_flip) rhs = - rhs; args.push_back(rhs); // Minimize the number of eval() and ctor calls. This is // crucial for a reasonable performance. If the next operator // is compatible with the pending one (or the same) don't create // the expression and continue collecting operands instead. if (binop == token) continue; else if (binop == '+' && token == '-') { need_sign_flip = token != orig_binop; continue; } else if (binop == '-' && token == '+') { need_sign_flip = token != orig_binop; continue; } else { if (args.size() <= 1) bug("binop has " << args.size() << " arguments, expected >= 2"); lhs = make_binop_expr(orig_binop, args); args.clear(); args.push_back(lhs); } } }
PExprAST Parser::parse_expr() { PExprAST lhs = parse_primary(); return parse_binop_rhs(0, lhs); }