Skip to content

Commit

Permalink
Adds expression statement and assignment in parser
Browse files Browse the repository at this point in the history
  • Loading branch information
LesleyLai committed Jan 19, 2025
1 parent f68e6a0 commit 3cda386
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 37 deletions.
1 change: 1 addition & 0 deletions include/mcc/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ typedef struct Stmt {
union {
Block compound;
ReturnStmt ret;
const Expr* expr;
};
} Stmt;

Expand Down
7 changes: 6 additions & 1 deletion src/frontend/ast_printer.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,12 @@ static void ast_print_stmt(const Stmt* stmt, int indent)
print_source_range(stmt->source_range);
printf("\n");
} break;
case STMT_EXPR: MCC_UNIMPLEMENTED(); break;
case STMT_EXPR: {
printf("%*sExprStmt ", indent, "");
print_source_range(stmt->source_range);
printf("\n");
ast_print_expr(stmt->ret.expr, indent + 2);
} break;
case STMT_COMPOUND: ast_print_block(&stmt->compound, indent + 2); break;
case STMT_RETURN: {
printf("%*sReturnStmt ", indent, "");
Expand Down
116 changes: 80 additions & 36 deletions src/frontend/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ typedef enum Precedence {
static Expr* parse_expr(Parser* parser);
static Expr* parse_group(Parser* parser);
static Expr* parse_unary_op(Parser* parser);
static Expr* parse_binary_op_left_associative(Parser* parser, Expr* lhs_expr);
static Expr* parse_binop_left(Parser* parser,
Expr* lhs_expr); // left associative
static Expr* parse_binop_right(Parser* parser,
Expr* lhs_expr); // right associative

typedef Expr* (*PrefixParseFn)(Parser*);
typedef Expr* (*InfixParseFn)(Parser*, Expr*);
Expand All @@ -175,34 +178,36 @@ static ParseRule rules[TOKEN_TYPES_COUNT] = {
[TOKEN_LEFT_BRACE] = {NULL, NULL, PREC_NONE},
[TOKEN_RIGHT_BRACE] = {NULL, NULL, PREC_NONE},
[TOKEN_SEMICOLON] = {NULL, NULL, PREC_NONE},
[TOKEN_PLUS] = {NULL, parse_binary_op_left_associative, PREC_TERM},
[TOKEN_MINUS] = {parse_unary_op, parse_binary_op_left_associative,
PREC_TERM},
[TOKEN_STAR] = {NULL, parse_binary_op_left_associative, PREC_FACTOR},
[TOKEN_SLASH] = {NULL, parse_binary_op_left_associative, PREC_FACTOR},
[TOKEN_PERCENT] = {NULL, parse_binary_op_left_associative, PREC_FACTOR},
[TOKEN_AMPERSAND] = {NULL, parse_binary_op_left_associative,
PREC_BITWISE_AND},
[TOKEN_CARET] = {NULL, parse_binary_op_left_associative, PREC_BITWISE_XOR},
[TOKEN_BAR] = {NULL, parse_binary_op_left_associative, PREC_BITWISE_OR},

[TOKEN_AMPERSAND_AMPERSAND] = {NULL, parse_binary_op_left_associative,
PREC_AND},
[TOKEN_BAR_BAR] = {NULL, parse_binary_op_left_associative, PREC_OR},
[TOKEN_EQUAL_EQUAL] = {NULL, parse_binary_op_left_associative,
PREC_EQUALITY},
[TOKEN_PLUS] = {NULL, parse_binop_left, PREC_TERM},
[TOKEN_PLUS_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_MINUS] = {parse_unary_op, parse_binop_left, PREC_TERM},
[TOKEN_MINUS_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_STAR] = {NULL, parse_binop_left, PREC_FACTOR},
[TOKEN_STAR_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_SLASH] = {NULL, parse_binop_left, PREC_FACTOR},
[TOKEN_SLASH_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_PERCENT] = {NULL, parse_binop_left, PREC_FACTOR},
[TOKEN_PERCENT_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_AMPERSAND] = {NULL, parse_binop_left, PREC_BITWISE_AND},
[TOKEN_AMPERSAND_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_AMPERSAND_AMPERSAND] = {NULL, parse_binop_left, PREC_AND},
[TOKEN_BAR] = {NULL, parse_binop_left, PREC_BITWISE_OR},
[TOKEN_BAR_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_BAR_BAR] = {NULL, parse_binop_left, PREC_OR},
[TOKEN_CARET] = {NULL, parse_binop_left, PREC_BITWISE_XOR},
[TOKEN_CARET_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_EQUAL_EQUAL] = {NULL, parse_binop_left, PREC_EQUALITY},
[TOKEN_NOT] = {parse_unary_op, NULL, PREC_UNARY},
[TOKEN_NOT_EQUAL] = {NULL, parse_binary_op_left_associative, PREC_EQUALITY},

[TOKEN_LESS] = {NULL, parse_binary_op_left_associative, PREC_COMPARISON},
[TOKEN_LESS_EQUAL] = {NULL, parse_binary_op_left_associative,
PREC_COMPARISON},
[TOKEN_LESS_LESS] = {NULL, parse_binary_op_left_associative, PREC_SHIFT},
[TOKEN_GREATER] = {NULL, parse_binary_op_left_associative, PREC_COMPARISON},
[TOKEN_GREATER_EQUAL] = {NULL, parse_binary_op_left_associative,
PREC_COMPARISON},
[TOKEN_GREATER_GREATER] = {NULL, parse_binary_op_left_associative,
PREC_SHIFT},
[TOKEN_NOT_EQUAL] = {NULL, parse_binop_left, PREC_EQUALITY},
[TOKEN_LESS] = {NULL, parse_binop_left, PREC_COMPARISON},
[TOKEN_LESS_EQUAL] = {NULL, parse_binop_left, PREC_COMPARISON},
[TOKEN_LESS_LESS] = {NULL, parse_binop_left, PREC_SHIFT},
[TOKEN_LESS_LESS_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_GREATER] = {NULL, parse_binop_left, PREC_COMPARISON},
[TOKEN_GREATER_EQUAL] = {NULL, parse_binop_left, PREC_COMPARISON},
[TOKEN_GREATER_GREATER] = {NULL, parse_binop_left, PREC_SHIFT},
[TOKEN_GREATER_GREATER_EQUAL] = {NULL, parse_binop_right, PREC_ASSIGNMENT},
[TOKEN_TILDE] = {parse_unary_op, NULL, PREC_TERM},
[TOKEN_KEYWORD_VOID] = {NULL, NULL, PREC_NONE},
[TOKEN_KEYWORD_INT] = {NULL, NULL, PREC_NONE},
Expand All @@ -225,12 +230,17 @@ static Expr* parse_precedence(Parser* parser, Precedence precedence)
{
parse_advance(parser);

const PrefixParseFn prefix_rule =
get_rule(parser_previous_token(parser).type)->prefix;
const Token previous_token = parser_previous_token(parser);

const PrefixParseFn prefix_rule = get_rule(previous_token.type)->prefix;
if (prefix_rule == NULL) {
parse_error_at(parser, str("Expect valid expression"),
parser_previous_token(parser));
return NULL;
parse_error_at(parser, str("Expect valid expression"), previous_token);
Expr* error_expr = ARENA_ALLOC_OBJECT(parser->permanent_arena, Expr);
*error_expr = (Expr){
.tag = EXPR_INVALID,
.source_range = token_source_range(previous_token),
};
return error_expr;
}

Expr* expr = prefix_rule(parser);
Expand Down Expand Up @@ -288,17 +298,28 @@ static BinaryOpType binop_type_from_token_type(TokenType token_type)
{
switch (token_type) {
case TOKEN_PLUS: return BINARY_OP_PLUS;
case TOKEN_PLUS_EQUAL: return BINARY_OP_PLUS_EQUAL;
case TOKEN_MINUS: return BINARY_OP_MINUS;
case TOKEN_MINUS_EQUAL: return BINARY_OP_MINUS_EQUAL;
case TOKEN_STAR: return BINARY_OP_MULT;
case TOKEN_STAR_EQUAL: return BINARY_OP_MULT_EQUAL;
case TOKEN_SLASH: return BINARY_OP_DIVIDE;
case TOKEN_SLASH_EQUAL: return BINARY_OP_DIVIDE_EQUAL;
case TOKEN_PERCENT: return BINARY_OP_MOD;
case TOKEN_PERCENT_EQUAL: return BINARY_OP_MOD_EQUAL;
case TOKEN_LESS_LESS: return BINARY_OP_SHIFT_LEFT;
case TOKEN_LESS_LESS_EQUAL: return BINARY_OP_SHIFT_LEFT_EQUAL;
case TOKEN_GREATER_GREATER: return BINARY_OP_SHIFT_RIGHT;
case TOKEN_GREATER_GREATER_EQUAL: return BINARY_OP_SHIFT_RIGHT_EQUAL;
case TOKEN_AMPERSAND: return BINARY_OP_BITWISE_AND;
case TOKEN_AMPERSAND_EQUAL: return BINARY_OP_BITWISE_AND_EQUAL;
case TOKEN_CARET: return BINARY_OP_BITWISE_XOR;
case TOKEN_CARET_EQUAL: return BINARY_OP_BITWISE_XOR_EQUAL;
case TOKEN_BAR: return BINARY_OP_BITWISE_OR;
case TOKEN_BAR_EQUAL: return BINARY_OP_BITWISE_OR_EQUAL;
case TOKEN_AMPERSAND_AMPERSAND: return BINARY_OP_AND;
case TOKEN_BAR_BAR: return BINARY_OP_OR;
case TOKEN_EQUAL: return BINARY_OP_ASSIGNMENT;
case TOKEN_EQUAL_EQUAL: return BINARY_OP_EQUAL;
case TOKEN_NOT_EQUAL: return BINARY_OP_NOT_EQUAL;
case TOKEN_LESS: return BINARY_OP_LESS;
Expand All @@ -309,13 +330,18 @@ static BinaryOpType binop_type_from_token_type(TokenType token_type)
}
}

static Expr* parse_binary_op_left_associative(Parser* parser, Expr* lhs_expr)
enum Associativity { ASSOCIATIVITY_LEFT, ASSOCIATIVITY_RIGHT };

static Expr* parse_binary_op(Parser* parser, Expr* lhs_expr,
enum Associativity associativity)
{
Token operator_token = parser_previous_token(parser);

const TokenType operator_type = operator_token.type;
const ParseRule* rule = get_rule(operator_type);
Expr* rhs_expr = parse_precedence(parser, (Precedence)(rule->precedence + 1));
Expr* rhs_expr = parse_precedence(
parser, (Precedence)(rule->precedence +
((associativity == ASSOCIATIVITY_LEFT) ? 1 : 0)));

BinaryOpType binary_op_type = binop_type_from_token_type(operator_type);

Expand All @@ -334,6 +360,16 @@ static Expr* parse_binary_op_left_associative(Parser* parser, Expr* lhs_expr)
return result;
}

static Expr* parse_binop_left(Parser* parser, Expr* lhs_expr)
{
return parse_binary_op(parser, lhs_expr, ASSOCIATIVITY_LEFT);
}

static Expr* parse_binop_right(Parser* parser, Expr* lhs_expr)
{
return parse_binary_op(parser, lhs_expr, ASSOCIATIVITY_RIGHT);
}

static Expr* parse_expr(Parser* parser)
{
return parse_precedence(parser, PREC_ASSIGNMENT);
Expand Down Expand Up @@ -471,7 +507,15 @@ static void parse_stmt(Parser* parser, Stmt* out_stmt)
return;
}
default: {
parse_error_at(parser, str("Expect statement"), start_token);
const Expr* expr = parse_expr(parser);
parse_consume(parser, TOKEN_SEMICOLON, "expect ';'");

*out_stmt = (Stmt){.type = STMT_EXPR,
.expr = expr,
.source_range = source_range_union(
token_source_range(start_token),
token_source_range(parser_previous_token(parser)))};

break;
}
}
Expand Down

0 comments on commit 3cda386

Please sign in to comment.