|
|
@@ -0,0 +1,199 @@ |
|
|
void parse_expr(Value *dest); |
|
|
|
|
|
Sym *parse_ident(void) { |
|
|
if (tok != TOK_IDENT) { |
|
|
error("Expected identifier"); |
|
|
} |
|
|
Sym *ident = tok_sym; |
|
|
next(); |
|
|
return ident; |
|
|
} |
|
|
|
|
|
void parse_operand_expr(Value *dest) { |
|
|
if (tok == TOK_INT) { |
|
|
do_int_expr(dest, tok_int); |
|
|
next(); |
|
|
} else if (tok == TOK_FLOAT) { |
|
|
do_float_expr(dest, tok_float); |
|
|
next(); |
|
|
} else if (tok == TOK_STR) { |
|
|
do_str_expr(dest, tok_str); |
|
|
next(); |
|
|
} else if (tok == TOK_IDENT) { |
|
|
do_ident_expr(dest, tok_sym); |
|
|
next(); |
|
|
} else if (match("(")) { |
|
|
parse_expr(dest); |
|
|
expect(")"); |
|
|
} else { |
|
|
error("Unexpected token in expression"); |
|
|
} |
|
|
} |
|
|
|
|
|
void parse_base_expr(Value *dest) { |
|
|
parse_operand_expr(dest); |
|
|
for (;;) { |
|
|
if (match("(")) { |
|
|
Value args[MAX_ARGS]; |
|
|
int num_args = 0; |
|
|
if (!match(")")) { |
|
|
parse_expr(&args[num_args++]); |
|
|
while (match(",")) { |
|
|
if (num_args == MAX_ARGS) { |
|
|
error("Exceeded argument limit"); |
|
|
} |
|
|
parse_expr(&args[num_args++]); |
|
|
} |
|
|
expect(")"); |
|
|
} |
|
|
do_call_expr(dest, args, num_args); |
|
|
} else if (match("[")) { |
|
|
Value index; |
|
|
parse_expr(&index); |
|
|
do_index_expr(dest, &index); |
|
|
} else if (match(".")) { |
|
|
do_field_expr(dest, parse_ident()); |
|
|
} else if (match("++")) { |
|
|
do_postinc_expr(dest); |
|
|
} else if (match("--")) { |
|
|
do_preinc_expr(dest); |
|
|
} else { |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
void parse_unary_expr(Value *dest) { |
|
|
if (match("-")) { |
|
|
parse_unary_expr(dest); |
|
|
do_neg_expr(dest); |
|
|
} else if (match("!")) { |
|
|
parse_unary_expr(dest); |
|
|
do_not_expr(dest); |
|
|
} else if (match("~")) { |
|
|
parse_unary_expr(dest); |
|
|
do_bnot_expr(dest); |
|
|
} else if (match("*")) { |
|
|
parse_unary_expr(dest); |
|
|
do_deref_expr(dest); |
|
|
} else if (match("&")) { |
|
|
parse_unary_expr(dest); |
|
|
do_addr_expr(dest); |
|
|
} else { |
|
|
parse_base_expr(dest); |
|
|
} |
|
|
} |
|
|
|
|
|
void parse_mul_expr(Value *dest) { |
|
|
parse_unary_expr(dest); |
|
|
for (;;) { |
|
|
Value src; |
|
|
if (match("*")) { |
|
|
parse_unary_expr(&src); |
|
|
do_mul_expr(dest, &src); |
|
|
} else if (match("/")) { |
|
|
parse_unary_expr(&src); |
|
|
do_div_expr(dest, &src); |
|
|
} else if (match("%")) { |
|
|
parse_unary_expr(&src); |
|
|
do_mod_expr(dest, &src); |
|
|
} else if (match("&")) { |
|
|
parse_unary_expr(&src); |
|
|
do_band_expr(dest, &src); |
|
|
} else if (match("<<")) { |
|
|
parse_unary_expr(&src); |
|
|
do_lsh_expr(dest, &src); |
|
|
} else if (match(">>")) { |
|
|
parse_unary_expr(&src); |
|
|
do_rsh_expr(dest, &src); |
|
|
} else { |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
void parse_add_expr(Value *dest) { |
|
|
parse_mul_expr(dest); |
|
|
for (;;) { |
|
|
Value src; |
|
|
if (match("+")) { |
|
|
parse_mul_expr(&src); |
|
|
do_add_expr(dest, &src); |
|
|
} else if (match("-")) { |
|
|
parse_mul_expr(&src); |
|
|
do_sub_expr(dest, &src); |
|
|
} else if (match("^")) { |
|
|
parse_mul_expr(&src); |
|
|
do_xor_expr(dest, &src); |
|
|
} else if (match("|")) { |
|
|
parse_mul_expr(&src); |
|
|
do_bor_expr(dest, &src); |
|
|
} else { |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
void parse_cmp_expr(Value *dest) { |
|
|
parse_add_expr(dest); |
|
|
for (;;) { |
|
|
Value src; |
|
|
if (match("==")) { |
|
|
parse_add_expr(&src); |
|
|
do_eq_expr(dest, &src); |
|
|
} else if (match("!=")) { |
|
|
parse_add_expr(&src); |
|
|
do_ne_expr(dest, &src); |
|
|
} else if (match("<=")) { |
|
|
parse_add_expr(&src); |
|
|
do_le_expr(dest, &src); |
|
|
} else if (match(">=")) { |
|
|
parse_add_expr(&src); |
|
|
do_ge_expr(dest, &src); |
|
|
} else if (match("<")) { |
|
|
parse_add_expr(&src); |
|
|
do_lt_expr(dest, &src); |
|
|
} else if (match(">")) { |
|
|
parse_add_expr(&src); |
|
|
do_gt_expr(dest, &src); |
|
|
} else { |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
// TODO: The way they call the do_functions right now is wrong because of short circuiting. |
|
|
|
|
|
void parse_and_expr(Value *dest) { |
|
|
parse_cmp_expr(dest); |
|
|
while (match("&&")) { |
|
|
Value src; |
|
|
parse_cmp_expr(&src); |
|
|
do_and_expr(dest, &src); |
|
|
} |
|
|
} |
|
|
|
|
|
void parse_or_expr(Value *dest) { |
|
|
parse_and_expr(dest); |
|
|
while (match("||")) { |
|
|
Value src; |
|
|
parse_and_expr(&src); |
|
|
do_or_expr(dest, &src); |
|
|
} |
|
|
} |
|
|
|
|
|
void parse_cond_expr(Value *dest) { |
|
|
parse_or_expr(dest); |
|
|
while (match("?")) { |
|
|
Value true_src; |
|
|
parse_cond_expr(&true_src); |
|
|
Value false_src; |
|
|
expect(":"); |
|
|
parse_cond_expr(&false_src); |
|
|
do_cond_expr(dest, true_src, false_src); |
|
|
} |
|
|
} |
|
|
|
|
|
void parse_expr(Value *dest) { |
|
|
parse_cond_expr(dest); |
|
|
} |