mirror of https://github.com/rui314/chibicc
278 lines
5.4 KiB
C
278 lines
5.4 KiB
C
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
typedef struct Type Type;
|
|
typedef struct Member Member;
|
|
typedef struct Initializer Initializer;
|
|
|
|
//
|
|
// tokenize.c
|
|
//
|
|
|
|
// Token
|
|
typedef enum {
|
|
TK_RESERVED, // Keywords or punctuators
|
|
TK_IDENT, // Identifiers
|
|
TK_STR, // String literals
|
|
TK_NUM, // Integer literals
|
|
TK_EOF, // End-of-file markers
|
|
} TokenKind;
|
|
|
|
// Token type
|
|
typedef struct Token Token;
|
|
struct Token {
|
|
TokenKind kind; // Token kind
|
|
Token *next; // Next token
|
|
long val; // If kind is TK_NUM, its value
|
|
char *str; // Token string
|
|
int len; // Token length
|
|
|
|
char *contents; // String literal contents including terminating '\0'
|
|
char cont_len; // string literal length
|
|
};
|
|
|
|
void error(char *fmt, ...);
|
|
void error_at(char *loc, char *fmt, ...);
|
|
void error_tok(Token *tok, char *fmt, ...);
|
|
void warn_tok(Token *tok, char *fmt, ...);
|
|
Token *peek(char *s);
|
|
Token *consume(char *op);
|
|
char *strndup(char *p, int len);
|
|
Token *consume_ident();
|
|
void expect(char *op);
|
|
long expect_number();
|
|
char *expect_ident();
|
|
bool at_eof();
|
|
Token *new_token(TokenKind kind, Token *cur, char *str, int len);
|
|
Token *tokenize();
|
|
|
|
extern char *filename;
|
|
extern char *user_input;
|
|
extern Token *token;
|
|
|
|
//
|
|
// parse.c
|
|
//
|
|
|
|
// Variable
|
|
typedef struct Var Var;
|
|
struct Var {
|
|
char *name; // Variable name
|
|
Type *ty; // Type
|
|
Token *tok; // for error message
|
|
bool is_local; // local or global
|
|
|
|
// Local variable
|
|
int offset; // Offset from RBP
|
|
|
|
// Global variable
|
|
Initializer *initializer;
|
|
};
|
|
|
|
typedef struct VarList VarList;
|
|
struct VarList {
|
|
VarList *next;
|
|
Var *var;
|
|
};
|
|
|
|
// AST node
|
|
typedef enum {
|
|
ND_ADD, // +
|
|
ND_SUB, // -
|
|
ND_MUL, // *
|
|
ND_DIV, // /
|
|
ND_BITAND, // &
|
|
ND_BITOR, // |
|
|
ND_BITXOR, // ^
|
|
ND_SHL, // <<
|
|
ND_SHR, // >>
|
|
ND_EQ, // ==
|
|
ND_NE, // !=
|
|
ND_LT, // <
|
|
ND_LE, // <=
|
|
ND_ASSIGN, // =
|
|
ND_TERNARY, // ?:
|
|
ND_PRE_INC, // pre ++
|
|
ND_PRE_DEC, // pre --
|
|
ND_POST_INC, // post ++
|
|
ND_POST_DEC, // post --
|
|
ND_A_ADD, // +=
|
|
ND_A_SUB, // -=
|
|
ND_A_MUL, // *=
|
|
ND_A_DIV, // /=
|
|
ND_A_SHL, // <<=
|
|
ND_A_SHR, // >>=
|
|
ND_COMMA, // ,
|
|
ND_MEMBER, // . (struct member access)
|
|
ND_ADDR, // unary &
|
|
ND_DEREF, // unary *
|
|
ND_NOT, // !
|
|
ND_BITNOT, // ~
|
|
ND_LOGAND, // &&
|
|
ND_LOGOR, // ||
|
|
ND_RETURN, // "return"
|
|
ND_IF, // "if"
|
|
ND_WHILE, // "while"
|
|
ND_FOR, // "for"
|
|
ND_SWITCH, // "switch"
|
|
ND_CASE, // "case"
|
|
ND_SIZEOF, // "sizeof"
|
|
ND_BLOCK, // { ... }
|
|
ND_BREAK, // "break"
|
|
ND_CONTINUE, // "continue"
|
|
ND_GOTO, // "goto"
|
|
ND_LABEL, // Labeled statement
|
|
ND_FUNCALL, // Function call
|
|
ND_EXPR_STMT, // Expression statement
|
|
ND_STMT_EXPR, // Statement expression
|
|
ND_VAR, // Variable
|
|
ND_NUM, // Integer
|
|
ND_CAST, // Type cast
|
|
ND_NULL, // Empty statement
|
|
} NodeKind;
|
|
|
|
// AST node type
|
|
typedef struct Node Node;
|
|
struct Node {
|
|
NodeKind kind; // Node kind
|
|
Node *next; // Next node
|
|
Type *ty; // Type, e.g. int or pointer to int
|
|
Token *tok; // Representative token
|
|
|
|
Node *lhs; // Left-hand side
|
|
Node *rhs; // Right-hand side
|
|
|
|
// "if, "while" or "for" statement
|
|
Node *cond;
|
|
Node *then;
|
|
Node *els;
|
|
Node *init;
|
|
Node *inc;
|
|
|
|
// Block or statement expression
|
|
Node *body;
|
|
|
|
// Struct member access
|
|
char *member_name;
|
|
Member *member;
|
|
|
|
// Function call
|
|
char *funcname;
|
|
Node *args;
|
|
|
|
// Goto or labeled statement
|
|
char *label_name;
|
|
|
|
// Switch-cases
|
|
Node *case_next;
|
|
Node *default_case;
|
|
int case_label;
|
|
int case_end_label;
|
|
|
|
Var *var;
|
|
long val;
|
|
};
|
|
|
|
// Global variable initializer. Global variables can be initialized
|
|
// either by a constant expression or a pointer to another global
|
|
// variable.
|
|
struct Initializer {
|
|
Initializer *next;
|
|
|
|
// Constant expression
|
|
int sz;
|
|
long val;
|
|
|
|
// Reference to another global variable
|
|
char *label;
|
|
long addend;
|
|
};
|
|
|
|
typedef struct Function Function;
|
|
struct Function {
|
|
Function *next;
|
|
char *name;
|
|
VarList *params;
|
|
bool is_static;
|
|
|
|
Node *node;
|
|
VarList *locals;
|
|
int stack_size;
|
|
};
|
|
|
|
typedef struct {
|
|
VarList *globals;
|
|
Function *fns;
|
|
} Program;
|
|
|
|
Program *program();
|
|
|
|
//
|
|
// typing.c
|
|
//
|
|
|
|
typedef enum {
|
|
TY_VOID,
|
|
TY_BOOL,
|
|
TY_CHAR,
|
|
TY_SHORT,
|
|
TY_INT,
|
|
TY_LONG,
|
|
TY_ENUM,
|
|
TY_PTR,
|
|
TY_ARRAY,
|
|
TY_STRUCT,
|
|
TY_FUNC,
|
|
} TypeKind;
|
|
|
|
struct Type {
|
|
TypeKind kind;
|
|
bool is_typedef; // typedef
|
|
bool is_static; // static
|
|
bool is_incomplete; // incomplete array
|
|
int align; // alignment
|
|
Type *base; // pointer or array
|
|
int array_size; // array
|
|
Member *members; // struct
|
|
Type *return_ty; // function
|
|
};
|
|
|
|
// Struct member
|
|
struct Member {
|
|
Member *next;
|
|
Type *ty;
|
|
Token *tok; // for error message
|
|
char *name;
|
|
int offset;
|
|
};
|
|
|
|
int align_to(int n, int align);
|
|
Type *void_type();
|
|
Type *bool_type();
|
|
Type *char_type();
|
|
Type *short_type();
|
|
Type *int_type();
|
|
Type *long_type();
|
|
Type *enum_type();
|
|
Type *struct_type();
|
|
Type *func_type(Type *return_ty);
|
|
Type *pointer_to(Type *base);
|
|
Type *array_of(Type *base, int size);
|
|
int size_of(Type *ty, Token *tok);
|
|
|
|
void add_type(Program *prog);
|
|
|
|
//
|
|
// codegen.c
|
|
//
|
|
|
|
void codegen(Program *prog);
|