Skip to content

Commit

Permalink
Type checking
Browse files Browse the repository at this point in the history
  • Loading branch information
LesleyLai committed Jan 31, 2025
1 parent 032fa25 commit 7b9ce77
Show file tree
Hide file tree
Showing 36 changed files with 841 additions and 261 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ The mcc compiler follows a standard compiler architecture, consisting of the fol
- **IR Generation**: Converts the AST into
a [three-address code intermediate representation](https://en.wikipedia.org/wiki/Three-address_code).
- **Assembly Generation**: Translates the intermediate representation into assembly code.

## Resources

Here are some useful resources consulted by me when writing this compiler

- [Writing a C Compiler](https://norasandler.com/book/) book
- Other small C compiler
implementations: [9cc](https://github.com/rui314/9cc) [chibicc](https://github.com/rui314/chibicc), [lacc](https://github.com/larmel/lacc), [cproc](https://github.com/michaelforney/cproc)
33 changes: 16 additions & 17 deletions include/mcc/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "source_location.h"
#include "str.h"
#include "type.h"

#include <stdlib.h>

Expand Down Expand Up @@ -62,6 +63,7 @@ typedef enum BinaryOpType {
} BinaryOpType;

typedef struct Expr Expr;
typedef struct Variable Variable; // identifier

struct ConstExpr {
int32_t val;
Expand Down Expand Up @@ -93,19 +95,20 @@ struct CallExpr {
typedef struct Expr {
SourceRange source_range;
ExprTag tag;
const Type* type; // C type (e.g. void, int, int*)
union {
struct ConstExpr const_expr;
struct UnaryOpExpr unary_op;
struct BinaryOpExpr binary_op;
struct StringView variable;
const Variable* variable;
struct TernaryExpr ternary;
struct CallExpr call;
};
} Expr;

typedef struct VariableDecl {
StringView name;
const Expr* initializer; // An optional initializer
Variable* name;
Expr* initializer; // An optional initializer
} VariableDecl;

typedef enum StmtTag {
Expand Down Expand Up @@ -149,24 +152,24 @@ struct Stmt {
struct ReturnStmt {
Expr* expr;
} ret;
const Expr* expr;
Expr* expr;
struct IfStmt {
const Expr* cond;
const Stmt* then;
const Stmt* els; // optional, can be nullptr
Expr* cond;
Stmt* then;
Stmt* els; // optional, can be nullptr
} if_then;

// while or do while loop
struct While {
const Expr* cond;
const Stmt* body;
Expr* cond;
Stmt* body;
} while_loop;

struct For {
ForInit init;
const Expr* cond; // optional, can be nullptr
const Expr* post; // optional, can be nullptr
const Stmt* body;
Expr* cond; // optional, can be nullptr
Expr* post; // optional, can be nullptr
Stmt* body;
} for_loop;
};
};
Expand All @@ -184,13 +187,9 @@ typedef struct BlockItem {
};
} BlockItem;

typedef struct Parameter {
StringView name;
} Parameter;

typedef struct Parameters {
uint32_t length;
Parameter* data;
Variable** data;
} Parameters;

typedef struct FunctionDecl {
Expand Down
1 change: 1 addition & 0 deletions include/mcc/cli_args.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ typedef struct CliArgs {
const char* source_filename; // Filename of the source file (with extension)
bool stop_after_lexer;
bool stop_after_parser;
bool stop_after_semantic_analysis;

bool gen_ir_only; // Stop after generating the IR
bool codegen_only; // generate assembly; but does not save to a file
Expand Down
2 changes: 1 addition & 1 deletion include/mcc/ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ typedef struct IRGenerationResult {
} IRGenerationResult;

struct TranslationUnit;
IRGenerationResult ir_generate(struct TranslationUnit* ast,
IRGenerationResult ir_generate(const struct TranslationUnit* ast,
Arena* permanent_arena, Arena scratch_arena);
void print_ir(const struct IRProgram* ir);

Expand Down
13 changes: 13 additions & 0 deletions include/mcc/sema.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef MCC_SEMA_H
#define MCC_SEMA_H

// Semantic analysis pass

#include "arena.h"
#include "diagnostic.h"

typedef struct TranslationUnit TranslationUnit;

ErrorsView type_check(TranslationUnit* ast, Arena* permanent_arena);

#endif // MCC_SEMA_H
10 changes: 5 additions & 5 deletions include/mcc/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "source_location.h"
#include "str.h"

typedef enum TokenType : char {
typedef enum TokenTag : char {
TOKEN_INVALID = 0,

TOKEN_LEFT_PAREN, // (
Expand Down Expand Up @@ -75,17 +75,17 @@ typedef enum TokenType : char {
TOKEN_EOF,

TOKEN_TYPES_COUNT,
} TokenType;
} TokenTag;

typedef struct Token {
TokenType type;
TokenTag tag;
uint32_t start; // The offset of the starting character in a token
uint32_t size;
} Token;

/// @brief An SOA view of tokens
typedef struct Tokens {
TokenType* token_types;
TokenTag* token_types;
uint32_t* token_starts;
uint32_t* token_sizes;
uint32_t token_count;
Expand All @@ -94,7 +94,7 @@ typedef struct Tokens {
inline static Token get_token(const Tokens* tokens, uint32_t i)
{
MCC_ASSERT(i < tokens->token_count);
return MCC_COMPOUND_LITERAL(Token){.type = tokens->token_types[i],
return MCC_COMPOUND_LITERAL(Token){.tag = tokens->token_types[i],
.start = tokens->token_starts[i],
.size = tokens->token_sizes[i]};
}
Expand Down
44 changes: 44 additions & 0 deletions include/mcc/type.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef MCC_TYPE_H
#define MCC_TYPE_H

#include <stddef.h>
#include <stdint.h>

#include "arena.h"
#include "str.h"

typedef enum TypeTag : uint8_t {
TYPE_INVALID = 0,
TYPE_VOID,
TYPE_INTEGER,
TYPE_FUNCTION,
} TypeTag;

typedef struct Type {
uint32_t size;
uint32_t alignment;
alignas(max_align_t) TypeTag tag;
} Type;

typedef struct IntegerType {
Type base;
bool is_unsigned;
const char* name;
} IntegerType;

typedef struct FunctionType {
Type base;
const Type* return_type;
uint32_t param_count;
} FunctionType;

extern const Type* typ_invalid;
extern const Type* typ_void;
extern const Type* typ_int;

const Type* func_type(const Type* return_type, uint32_t param_count,
Arena* arena);

void format_type_to(StringBuffer* buffer, const Type* typ);

#endif // MCC_TYPE_H
6 changes: 6 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ add_library(mcc_lib
${include_dir}/ir.h
${include_dir}/x86.h
${include_dir}/dynarray.h
${include_dir}/type.h
${include_dir}/sema.h

utils/format.c
utils/str.c
Expand All @@ -26,6 +28,10 @@ add_library(mcc_lib
frontend/ast_printer.c
frontend/parser.c
frontend/token.c
frontend/type.c
frontend/type_check.c
frontend/symbol_table.h
frontend/symbol_table.c

ir/ir_generator.c
ir/ir_printer.c
Expand Down
12 changes: 7 additions & 5 deletions src/frontend/ast_printer.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include <mcc/ast.h>
#include <mcc/prelude.h>

#include "symbol_table.h"

static void print_str(StringView str)
{
printf("%.*s", (int)str.size, str.start);
Expand Down Expand Up @@ -86,7 +88,7 @@ static void ast_print_expr(const Expr* expr, int indent)
printf("%*sVariableExpr ", indent, "");
print_source_range(expr->source_range);
printf(" ");
print_str(expr->variable);
print_str(expr->variable->name);
printf("\n");
break;
case EXPR_TERNARY:
Expand Down Expand Up @@ -134,7 +136,7 @@ static void ast_print_decl(const VariableDecl* decl, int indent)
{
printf("%*sVariableDecl ", indent, "");
printf("int ");
print_str(decl->name);
print_str(decl->name->name);
printf("\n");
if (decl->initializer) { ast_print_expr(decl->initializer, indent + 2); }
}
Expand Down Expand Up @@ -219,10 +221,10 @@ static void ast_print_parameters(Parameters parameters)
printf("(");
for (uint32_t i = 0; i < parameters.length; ++i) {
if (i > 0) { printf(", "); }
const Parameter param = parameters.data[i];
const Variable* param = parameters.data[i];
printf("int");
if (param.name.size != 0) {
printf(" %.*s", (int)param.name.size, param.name.start);
if (param->name.size != 0) {
printf(" %.*s", (int)param->name.size, param->name.start);
}
}
printf(")\"\n");
Expand Down
Loading

0 comments on commit 7b9ce77

Please sign in to comment.