Skip to content

Commit

Permalink
Use dynarray
Browse files Browse the repository at this point in the history
  • Loading branch information
LesleyLai committed Jan 2, 2025
1 parent 5e7a866 commit daf50b9
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 95 deletions.
2 changes: 1 addition & 1 deletion include/mcc/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
typedef struct TranslationUnit TranslationUnit;

typedef struct ParseErrorsView {
size_t size;
size_t length;
ParseError* data;
} ParseErrorsView;

Expand Down
33 changes: 12 additions & 21 deletions src/frontend/lexer.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <stdbool.h>
#include <string.h>

#include <mcc/dynarray.h>
#include <mcc/parser.h>

// The lexer consumes source code and produces tokens lazily
Expand Down Expand Up @@ -277,36 +278,26 @@ static Token scan_token(Lexer* lexer)
return error_token(lexer, string_view_from_c_str("Unexpected character."));
}

struct TokenDynArray {
size_t length;
size_t capacity;
Token* data;
};

Tokens lex(const char* source, Arena* permanent_arena, Arena scratch_arena)
{
Lexer lexer = lexer_create(source);

// Accumulate tokens to a temporary linked list, and then flatten it to an
// array
typedef struct Node {
Token token;
struct Node* previous;
} Node;

Node* current = NULL;
struct TokenDynArray token_dyn_array = {};

ptrdiff_t token_count = 0;
while (true) {
Token token = scan_token(&lexer);
Node* previous = current;
current = ARENA_ALLOC_OBJECT(&scratch_arena, Node);
*current = (Node){.token = token, .previous = previous};
++token_count;

DYNARRAY_PUSH_BACK(&token_dyn_array, Token, &scratch_arena, token);
if (token.type == TOKEN_EOF) { break; }
}

Token* tokens =
ARENA_ALLOC_ARRAY(permanent_arena, Token, (size_t)token_count);
for (ptrdiff_t i = token_count - 1; i >= 0; --i) {
tokens[i] = current->token;
current = current->previous;
}

return (Tokens){.begin = tokens, .end = tokens + token_count};
ARENA_ALLOC_ARRAY(permanent_arena, Token, token_dyn_array.length);
memcpy(tokens, token_dyn_array.data, token_dyn_array.length * sizeof(Token));
return (Tokens){.begin = tokens, .end = tokens + token_dyn_array.length};
}
111 changes: 61 additions & 50 deletions src/frontend/parser.c
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
#include <mcc/parser.h>

#include <mcc/ast.h>
#include <mcc/dynarray.h>
#include <mcc/format.h>

#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#define MAX_ERROR_COUNT 16 // TODO: use vector
struct ParseErrorVec {
size_t length;
size_t capacity;
ParseError* data;
};

typedef struct Parser {
Arena* permanent_arena;
Expand All @@ -19,7 +25,7 @@ typedef struct Parser {
bool has_error;
bool in_panic_mode;

ParseErrorsView errors;
struct ParseErrorVec errors;
} Parser;

static SourceRange token_source_range(Token token)
Expand All @@ -43,18 +49,11 @@ static void parse_error_at(Parser* parser, StringView error_msg, Token token)
if (parser->in_panic_mode) return;

// TODO: proper error handling
MCC_ASSERT_MSG(parser->errors.size < MAX_ERROR_COUNT,
"Too many data for mcc to handle");

if (parser->errors.data == NULL) {
parser->errors.data =
ARENA_ALLOC_ARRAY(parser->permanent_arena, ParseError, MAX_ERROR_COUNT);
}

parser->errors.data[parser->errors.size++] =
ParseError error =
(ParseError){.msg = error_msg, .range = token_source_range(token)};
DYNARRAY_PUSH_BACK(&parser->errors, ParseError, parser->permanent_arena,
error);

parser->has_error = true;
parser->in_panic_mode = true;
}

Expand Down Expand Up @@ -267,7 +266,7 @@ static Expr* parse_unary_op(Parser* parser)
case TOKEN_MINUS: operator_type = UNARY_OP_NEGATION; break;
case TOKEN_TILDE: operator_type = UNARY_OP_BITWISE_TYPE_COMPLEMENT; break;
case TOKEN_NOT: operator_type = UNARY_OP_NOT; break;
default: MCC_ASSERT_MSG(false, "Unexpected operator");
default: MCC_UNREACHABLE();
}

// Inner expression
Expand Down Expand Up @@ -344,42 +343,57 @@ static Expr* parse_expr(Parser* parser)
return parse_precedence(parser, PREC_ASSIGNMENT);
}

static void parse_return_stmt(Parser* parser, ReturnStmt* out_ret_stmt)
static ReturnStmt parse_return_stmt(Parser* parser)
{
Expr* expr = parse_expr(parser);
parse_consume(parser, TOKEN_SEMICOLON, "Expect ;");
*out_ret_stmt = (ReturnStmt){.expr = expr};
return (ReturnStmt){.expr = expr};
}

static void parse_stmt(Parser* parser, Stmt* out_stmt);

// TODO: Implement proper vector and use it for compound statement
#define MAX_STMT_COUNT_IN_COMPOUND_STMT 16
struct StmtVector {
size_t capacity;
size_t length;
Stmt* data;
};

static void parse_compound_stmt(Parser* parser, CompoundStmt* out_compount_stmt)
static CompoundStmt parse_compound_stmt(Parser* parser)
{
Stmt* statements = ARENA_ALLOC_ARRAY(parser->permanent_arena, Stmt,
MAX_STMT_COUNT_IN_COMPOUND_STMT);
size_t statement_count = 0;
struct StmtVector stmt_vector = {};

Arena scratch_arena = parser->scratch_arena;

bool has_error = false;

while (parser_current_token(parser).type != TOKEN_RIGHT_BRACE) {
// TODO: proper handle the case with more compound statements
if (statement_count == MAX_STMT_COUNT_IN_COMPOUND_STMT) {
parse_error_at(parser,
string_view_from_c_str(
"Too many statement in compound statement to handle"),
parser_current_token(parser));
return;
Stmt stmt;
parse_stmt(parser, &stmt);

if (parser->in_panic_mode) {
has_error = true;
break;
} else {
DYNARRAY_PUSH_BACK(&stmt_vector, Stmt, &scratch_arena, stmt);
}
}

parse_stmt(parser, &statements[statement_count]);
++statement_count;
if (has_error) {
parser->in_panic_mode = false;
while (parser_current_token(parser).type != TOKEN_EOF) {
if (parser_previous_token(parser).type != TOKEN_RIGHT_BRACE) { break; }
parse_advance(parser);
}
} else {
parse_consume(parser, TOKEN_RIGHT_BRACE, "Expect }");
}

parse_consume(parser, TOKEN_RIGHT_BRACE, "Expect }");
Stmt* stmts =
ARENA_ALLOC_ARRAY(parser->permanent_arena, Stmt, stmt_vector.length);
memcpy(stmts, stmt_vector.data, stmt_vector.length * sizeof(Stmt));

*out_compount_stmt = (CompoundStmt){.statements = statements,
.statement_count = statement_count};
return (CompoundStmt){.statements = stmts,
.statement_count = stmt_vector.length};
}

static void parse_stmt(Parser* parser, Stmt* out_stmt)
Expand All @@ -391,8 +405,7 @@ static void parse_stmt(Parser* parser, Stmt* out_stmt)
case TOKEN_KEYWORD_RETURN: {
parse_advance(parser);

ReturnStmt return_stmt;
parse_return_stmt(parser, &return_stmt);
ReturnStmt return_stmt = parse_return_stmt(parser);

*out_stmt =
(Stmt){.type = STMT_RETURN,
Expand All @@ -405,8 +418,7 @@ static void parse_stmt(Parser* parser, Stmt* out_stmt)
case TOKEN_LEFT_BRACE: {
parse_advance(parser);

CompoundStmt compound;
parse_compound_stmt(parser, &compound);
CompoundStmt compound = parse_compound_stmt(parser);

*out_stmt =
(Stmt){.type = STMT_COMPOUND,
Expand Down Expand Up @@ -456,7 +468,7 @@ static FunctionDecl* parse_function_decl(Parser* parser)
if (parser_current_token(parser).type == TOKEN_LEFT_BRACE) { // is definition
parse_advance(parser);
body = ARENA_ALLOC_OBJECT(parser->permanent_arena, CompoundStmt);
parse_compound_stmt(parser, body);
*body = parse_compound_stmt(parser);
} else {
parse_consume(parser, TOKEN_SEMICOLON, "Expect ;");
}
Expand Down Expand Up @@ -490,19 +502,18 @@ static TranslationUnit* parse_translation_unit(Parser* parser)

ParseResult parse(Tokens tokens, Arena* permanent_arena, Arena scratch_arena)
{
Parser parser = {.permanent_arena = permanent_arena,
.scratch_arena = scratch_arena,
.tokens = tokens,
.current_token_index = 0,
.has_error = false,
.in_panic_mode = false,
.errors = {
.size = 0,
.data = NULL,
}};
Parser parser = {
.permanent_arena = permanent_arena,
.scratch_arena = scratch_arena,
.tokens = tokens,
};

TranslationUnit* tu = parse_translation_unit(&parser);

return (ParseResult){.ast = parser.has_error ? NULL : tu,
.errors = parser.errors};
const bool has_error = parser.errors.data != NULL;
const ParseErrorsView errors = (ParseErrorsView){
.length = parser.errors.length,
.data = parser.errors.data,
};
return (ParseResult){.ast = has_error ? NULL : tu, .errors = errors};
}
38 changes: 24 additions & 14 deletions src/ir/ir_generator.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include <mcc/ir.h>
#include <string.h>

#include <mcc/ast.h>
#include <mcc/dynarray.h>
#include <mcc/format.h>

/*
Expand Down Expand Up @@ -62,18 +64,23 @@ static IRInstructionType instruction_typ_from_binary_op(BinaryOpType op_type)
MCC_UNREACHABLE();
}

typedef struct IRInstructions {
IRInstruction* data;
uint32_t length;
uint32_t capacity;
} IRInstructions;

typedef struct IRGenContext {
Arena* permanent_arena;
size_t instruction_count;
IRInstruction* instructions;
Arena* scratch_arena;
IRInstructions instructions;
int fresh_variable_counter;
} IRGenContext;

static void push_instruction(IRGenContext* context, IRInstruction instruction)
{
// TODO: implement vector
MCC_ASSERT_MSG(context->instruction_count < 16, "Too many instructions!");
context->instructions[context->instruction_count++] = instruction;
DYNARRAY_PUSH_BACK(&context->instructions, IRInstruction,
context->scratch_arena, instruction);
}

static StringView create_fresh_variable_name(IRGenContext* context)
Expand Down Expand Up @@ -138,13 +145,10 @@ generate_ir_function_def(const FunctionDecl* decl, Arena* permanent_arena,
Arena scratch_arena)

{
(void)scratch_arena;

IRGenContext context = (IRGenContext){
.permanent_arena = permanent_arena,
.instruction_count = 0,
.instructions = ARENA_ALLOC_ARRAY(permanent_arena, IRInstruction, 16),
.fresh_variable_counter = 0};
IRGenContext context = (IRGenContext){.permanent_arena = permanent_arena,
.scratch_arena = &scratch_arena,
.instructions = {},
.fresh_variable_counter = 0};

for (size_t i = 0; i < decl->body->statement_count; ++i) {
const Stmt stmt = decl->body->statements[i];
Expand All @@ -163,9 +167,15 @@ generate_ir_function_def(const FunctionDecl* decl, Arena* permanent_arena,
// TODO: handle other kinds of statements
}

// allocate and copy instructions to permanent arena
IRInstruction* instructions = ARENA_ALLOC_ARRAY(
permanent_arena, IRInstruction, context.instructions.length);
memcpy(instructions, context.instructions.data,
context.instructions.length * sizeof(IRInstruction));

return (IRFunctionDef){.name = decl->name,
.instruction_count = context.instruction_count,
.instructions = context.instructions};
.instruction_count = context.instructions.length,
.instructions = instructions};
}

IRProgram* ir_generate(TranslationUnit* ast, Arena* permanent_arena,
Expand Down
14 changes: 6 additions & 8 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,12 @@ static void print_parse_diagnostics(ParseErrorsView errors,
Arena diagnostics_arena =
arena_init(diagnostics_buffer, diagnostics_arena_size);

if (errors.size > 0) {
for (size_t i = 0; i < errors.size; ++i) {
StringBuffer output = string_buffer_new(&diagnostics_arena);
write_diagnostics(&output, src_filename, source, errors.data[i]);
StringView output_view = string_view_from_buffer(&output);
fprintf(stderr, "%*s", (int)output_view.size, output_view.start);
arena_reset(&diagnostics_arena);
}
for (size_t i = 0; i < errors.length; ++i) {
StringBuffer output = string_buffer_new(&diagnostics_arena);
write_diagnostics(&output, src_filename, source, errors.data[i]);
StringView output_view = string_view_from_buffer(&output);
fprintf(stderr, "%*s\n", (int)output_view.size, output_view.start);
arena_reset(&diagnostics_arena);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/utils/diagnostic.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ void write_diagnostics(StringBuffer* output, const char* file_path,
string_buffer_printf(output, "%d | ", line);
}
}
string_buffer_printf(output, "\n");
}

static void write_diagnostic_line(StringBuffer* output, const char* source,
Expand All @@ -61,5 +62,4 @@ static void write_diagnostic_line(StringBuffer* output, const char* source,
string_buffer_printf(output, " ");
}
}
string_buffer_printf(output, "\n");
}

0 comments on commit daf50b9

Please sign in to comment.