mirror of https://github.com/rui314/chibicc
Add keyword "int" and make variable definition mandatory
This commit is contained in:
parent
a3ae40fc7f
commit
91465fe4ac
6
chibi.h
6
chibi.h
|
@ -33,6 +33,7 @@ struct Token {
|
|||
void error(char *fmt, ...);
|
||||
void error_at(char *loc, char *fmt, ...);
|
||||
void error_tok(Token *tok, char *fmt, ...);
|
||||
Token *peek(char *s);
|
||||
Token *consume(char *op);
|
||||
Token *consume_ident(void);
|
||||
void expect(char *op);
|
||||
|
@ -52,6 +53,7 @@ extern Token *token;
|
|||
typedef struct Var Var;
|
||||
struct Var {
|
||||
char *name; // Variable name
|
||||
Type *ty; // Type
|
||||
int offset; // Offset from RBP
|
||||
};
|
||||
|
||||
|
@ -86,6 +88,7 @@ typedef enum {
|
|||
ND_EXPR_STMT, // Expression statement
|
||||
ND_VAR, // Variable
|
||||
ND_NUM, // Integer
|
||||
ND_NULL, // Empty statement
|
||||
} NodeKind;
|
||||
|
||||
// AST node type
|
||||
|
@ -141,7 +144,10 @@ struct Type {
|
|||
Type *base;
|
||||
};
|
||||
|
||||
extern Type *int_type;
|
||||
|
||||
bool is_integer(Type *ty);
|
||||
Type *pointer_to(Type *base);
|
||||
void add_type(Node *node);
|
||||
|
||||
//
|
||||
|
|
|
@ -38,6 +38,8 @@ static void store(void) {
|
|||
// Generate code for a given node.
|
||||
static void gen(Node *node) {
|
||||
switch (node->kind) {
|
||||
case ND_NULL:
|
||||
return;
|
||||
case ND_NUM:
|
||||
printf(" push %ld\n", node->val);
|
||||
return;
|
||||
|
|
55
parse.c
55
parse.c
|
@ -46,9 +46,10 @@ static Node *new_var_node(Var *var, Token *tok) {
|
|||
return node;
|
||||
}
|
||||
|
||||
static Var *new_lvar(char *name) {
|
||||
static Var *new_lvar(char *name, Type *ty) {
|
||||
Var *var = calloc(1, sizeof(Var));
|
||||
var->name = name;
|
||||
var->ty = ty;
|
||||
|
||||
VarList *vl = calloc(1, sizeof(VarList));
|
||||
vl->var = var;
|
||||
|
@ -58,6 +59,7 @@ static Var *new_lvar(char *name) {
|
|||
}
|
||||
|
||||
static Function *function(void);
|
||||
static Node *declaration(void);
|
||||
static Node *stmt(void);
|
||||
static Node *stmt2(void);
|
||||
static Node *expr(void);
|
||||
|
@ -81,30 +83,46 @@ Function *program(void) {
|
|||
return head.next;
|
||||
}
|
||||
|
||||
// basetype = "int" "*"*
|
||||
static Type *basetype(void) {
|
||||
expect("int");
|
||||
Type *ty = int_type;
|
||||
while (consume("*"))
|
||||
ty = pointer_to(ty);
|
||||
return ty;
|
||||
}
|
||||
|
||||
static VarList *read_func_param(void) {
|
||||
VarList *vl = calloc(1, sizeof(VarList));
|
||||
Type *ty = basetype();
|
||||
vl->var = new_lvar(expect_ident(), ty);
|
||||
return vl;
|
||||
}
|
||||
|
||||
static VarList *read_func_params(void) {
|
||||
if (consume(")"))
|
||||
return NULL;
|
||||
|
||||
VarList *head = calloc(1, sizeof(VarList));
|
||||
head->var = new_lvar(expect_ident());
|
||||
VarList *head = read_func_param();
|
||||
VarList *cur = head;
|
||||
|
||||
while (!consume(")")) {
|
||||
expect(",");
|
||||
cur->next = calloc(1, sizeof(VarList));
|
||||
cur->next->var = new_lvar(expect_ident());
|
||||
cur->next = read_func_param();
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
// function = ident "(" params? ")" "{" stmt* "}"
|
||||
// params = ident ("," ident)*
|
||||
// function = basetype ident "(" params? ")" "{" stmt* "}"
|
||||
// params = param ("," param)*
|
||||
// param = basetype ident
|
||||
static Function *function(void) {
|
||||
locals = NULL;
|
||||
|
||||
Function *fn = calloc(1, sizeof(Function));
|
||||
basetype();
|
||||
fn->name = expect_ident();
|
||||
expect("(");
|
||||
fn->params = read_func_params();
|
||||
|
@ -122,6 +140,23 @@ static Function *function(void) {
|
|||
return fn;
|
||||
}
|
||||
|
||||
// declaration = basetype ident ("=" expr) ";"
|
||||
static Node *declaration(void) {
|
||||
Token *tok = token;
|
||||
Type *ty = basetype();
|
||||
Var *var = new_lvar(expect_ident(), ty);
|
||||
|
||||
if (consume(";"))
|
||||
return new_node(ND_NULL, tok);
|
||||
|
||||
expect("=");
|
||||
Node *lhs = new_var_node(var, tok);
|
||||
Node *rhs = expr();
|
||||
expect(";");
|
||||
Node *node = new_binary(ND_ASSIGN, lhs, rhs, tok);
|
||||
return new_unary(ND_EXPR_STMT, node, tok);
|
||||
}
|
||||
|
||||
static Node *read_expr_stmt(void) {
|
||||
Token *tok = token;
|
||||
return new_unary(ND_EXPR_STMT, expr(), tok);
|
||||
|
@ -138,6 +173,7 @@ static Node *stmt(void) {
|
|||
// | "while" "(" expr ")" stmt
|
||||
// | "for" "(" expr? ";" expr? ";" expr? ")" stmt
|
||||
// | "{" stmt* "}"
|
||||
// | declaration
|
||||
// | expr ";"
|
||||
static Node *stmt2(void) {
|
||||
Token *tok;
|
||||
|
@ -200,6 +236,9 @@ static Node *stmt2(void) {
|
|||
return node;
|
||||
}
|
||||
|
||||
if (tok = peek("int"))
|
||||
return declaration();
|
||||
|
||||
Node *node = read_expr_stmt();
|
||||
expect(";");
|
||||
return node;
|
||||
|
@ -360,7 +399,7 @@ static Node *primary(void) {
|
|||
// Variable
|
||||
Var *var = find_var(tok);
|
||||
if (!var)
|
||||
var = new_lvar(strndup(tok->str, tok->len));
|
||||
error_tok(tok, "undefined variable");
|
||||
return new_var_node(var, tok);
|
||||
}
|
||||
|
||||
|
|
124
test.sh
124
test.sh
|
@ -27,77 +27,83 @@ assert() {
|
|||
fi
|
||||
}
|
||||
|
||||
assert 0 'main() { return 0; }'
|
||||
assert 42 'main() { return 42; }'
|
||||
assert 21 'main() { return 5+20-4; }'
|
||||
assert 41 'main() { return 12 + 34 - 5 ; }'
|
||||
assert 47 'main() { return 5+6*7; }'
|
||||
assert 15 'main() { return 5*(9-6); }'
|
||||
assert 4 'main() { return (3+5)/2; }'
|
||||
assert 10 'main() { return -10+20; }'
|
||||
assert 10 'main() { return - -10; }'
|
||||
assert 10 'main() { return - - +10; }'
|
||||
assert 0 'int main() { return 0; }'
|
||||
assert 42 'int main() { return 42; }'
|
||||
assert 21 'int main() { return 5+20-4; }'
|
||||
assert 41 'int main() { return 12 + 34 - 5 ; }'
|
||||
assert 47 'int main() { return 5+6*7; }'
|
||||
assert 15 'int main() { return 5*(9-6); }'
|
||||
assert 4 'int main() { return (3+5)/2; }'
|
||||
assert 10 'int main() { return -10+20; }'
|
||||
assert 10 'int main() { return - -10; }'
|
||||
assert 10 'int main() { return - - +10; }'
|
||||
|
||||
assert 0 'main() { return 0==1; }'
|
||||
assert 1 'main() { return 42==42; }'
|
||||
assert 1 'main() { return 0!=1; }'
|
||||
assert 0 'main() { return 42!=42; }'
|
||||
assert 0 'int main() { return 0==1; }'
|
||||
assert 1 'int main() { return 42==42; }'
|
||||
assert 1 'int main() { return 0!=1; }'
|
||||
assert 0 'int main() { return 42!=42; }'
|
||||
|
||||
assert 1 'main() { return 0<1; }'
|
||||
assert 0 'main() { return 1<1; }'
|
||||
assert 0 'main() { return 2<1; }'
|
||||
assert 1 'main() { return 0<=1; }'
|
||||
assert 1 'main() { return 1<=1; }'
|
||||
assert 0 'main() { return 2<=1; }'
|
||||
assert 1 'int main() { return 0<1; }'
|
||||
assert 0 'int main() { return 1<1; }'
|
||||
assert 0 'int main() { return 2<1; }'
|
||||
assert 1 'int main() { return 0<=1; }'
|
||||
assert 1 'int main() { return 1<=1; }'
|
||||
assert 0 'int main() { return 2<=1; }'
|
||||
|
||||
assert 1 'main() { return 1>0; }'
|
||||
assert 0 'main() { return 1>1; }'
|
||||
assert 0 'main() { return 1>2; }'
|
||||
assert 1 'main() { return 1>=0; }'
|
||||
assert 1 'main() { return 1>=1; }'
|
||||
assert 0 'main() { return 1>=2; }'
|
||||
assert 1 'int main() { return 1>0; }'
|
||||
assert 0 'int main() { return 1>1; }'
|
||||
assert 0 'int main() { return 1>2; }'
|
||||
assert 1 'int main() { return 1>=0; }'
|
||||
assert 1 'int main() { return 1>=1; }'
|
||||
assert 0 'int main() { return 1>=2; }'
|
||||
|
||||
assert 3 'main() { a=3; return a; }'
|
||||
assert 8 'main() { a=3; z=5; return a+z; }'
|
||||
assert 3 'int main() { int a; a=3; return a; }'
|
||||
assert 8 'int main() { int a; int z; a=3; z=5; return a+z; }'
|
||||
assert 3 'int main() { int a=3; return a; }'
|
||||
assert 8 'int main() { int a=3; int z=5; return a+z; }'
|
||||
|
||||
assert 1 'main() { return 1; 2; 3; }'
|
||||
assert 2 'main() { 1; return 2; 3; }'
|
||||
assert 3 'main() { 1; 2; return 3; }'
|
||||
assert 1 'int main() { return 1; 2; 3; }'
|
||||
assert 2 'int main() { 1; return 2; 3; }'
|
||||
assert 3 'int main() { 1; 2; return 3; }'
|
||||
|
||||
assert 3 'main() { foo=3; return foo; }'
|
||||
assert 8 'main() { foo123=3; bar=5; return foo123+bar; }'
|
||||
assert 3 'int main() { int foo=3; return foo; }'
|
||||
assert 8 'int main() { int foo123=3; int bar=5; return foo123+bar; }'
|
||||
|
||||
assert 3 'main() { if (0) return 2; return 3; }'
|
||||
assert 3 'main() { if (1-1) return 2; return 3; }'
|
||||
assert 2 'main() { if (1) return 2; return 3; }'
|
||||
assert 2 'main() { if (2-1) return 2; return 3; }'
|
||||
assert 3 'int main() { if (0) return 2; return 3; }'
|
||||
assert 3 'int main() { if (1-1) return 2; return 3; }'
|
||||
assert 2 'int main() { if (1) return 2; return 3; }'
|
||||
assert 2 'int main() { if (2-1) return 2; return 3; }'
|
||||
|
||||
assert 3 'main() { {1; {2;} return 3;} }'
|
||||
assert 3 'int main() { {1; {2;} return 3;} }'
|
||||
|
||||
assert 10 'main() { i=0; while(i<10) i=i+1; return i; }'
|
||||
assert 55 'main() { i=0; j=0; while(i<=10) {j=i+j; i=i+1;} return j; }'
|
||||
assert 10 'int main() { int i=0; i=0; while(i<10) i=i+1; return i; }'
|
||||
assert 55 'int main() { int i=0; int j=0; while(i<=10) {j=i+j; i=i+1;} return j; }'
|
||||
|
||||
assert 55 'main() { i=0; j=0; for (i=0; i<=10; i=i+1) j=i+j; return j; }'
|
||||
assert 3 'main() { for (;;) return 3; return 5; }'
|
||||
assert 55 'int main() { int i=0; int j=0; for (i=0; i<=10; i=i+1) j=i+j; return j; }'
|
||||
assert 3 'int main() { for (;;) return 3; return 5; }'
|
||||
|
||||
assert 3 'main() { return ret3(); }'
|
||||
assert 5 'main() { return ret5(); }'
|
||||
assert 8 'main() { return add(3, 5); }'
|
||||
assert 2 'main() { return sub(5, 3); }'
|
||||
assert 21 'main() { return add6(1,2,3,4,5,6); }'
|
||||
assert 3 'int main() { return ret3(); }'
|
||||
assert 5 'int main() { return ret5(); }'
|
||||
assert 8 'int main() { return add(3, 5); }'
|
||||
assert 2 'int main() { return sub(5, 3); }'
|
||||
assert 21 'int main() { return add6(1,2,3,4,5,6); }'
|
||||
|
||||
assert 32 'main() { return ret32(); } ret32() { return 32; }'
|
||||
assert 7 'main() { return add2(3,4); } add2(x,y) { return x+y; }'
|
||||
assert 1 'main() { return sub2(4,3); } sub2(x,y) { return x-y; }'
|
||||
assert 55 'main() { return fib(9); } fib(x) { if (x<=1) return 1; return fib(x-1) + fib(x-2); }'
|
||||
assert 32 'int main() { return ret32(); } int ret32() { return 32; }'
|
||||
assert 7 'int main() { return add2(3,4); } int add2(int x, int y) { return x+y; }'
|
||||
assert 1 'int main() { return sub2(4,3); } int sub2(int x, int y) { return x-y; }'
|
||||
assert 55 'int main() { return fib(9); } int fib(int x) { if (x<=1) return 1; return fib(x-1) + fib(x-2); }'
|
||||
|
||||
assert 3 'main() { x=3; return *&x; }'
|
||||
assert 3 'main() { x=3; y=&x; z=&y; return **z; }'
|
||||
assert 5 'main() { x=3; y=5; return *(&x+1); }'
|
||||
assert 3 'main() { x=3; y=5; return *(&y-1); }'
|
||||
assert 5 'main() { x=3; y=&x; *y=5; return x; }'
|
||||
assert 7 'main() { x=3; y=5; *(&x+1)=7; return y; }'
|
||||
assert 7 'main() { x=3; y=5; *(&y-1)=7; return x; }'
|
||||
assert 2 'main() { x=3; return (&x+2)-&x; }'
|
||||
assert 3 'int main() { int x=3; return *&x; }'
|
||||
assert 3 'int main() { int x=3; int *y=&x; int **z=&y; return **z; }'
|
||||
assert 5 'int main() { int x=3; int y=5; return *(&x+1); }'
|
||||
assert 5 'int main() { int x=3; int y=5; return *(1+&x); }'
|
||||
assert 3 'int main() { int x=3; int y=5; return *(&y-1); }'
|
||||
assert 2 'int main() { int x=3; return (&x+2)-&x; }'
|
||||
assert 5 'int main() { int x=3; int y=5; int *z=&x; return *(z+1); }'
|
||||
assert 3 'int main() { int x=3; int y=5; int *z=&y; return *(z-1); }'
|
||||
assert 5 'int main() { int x=3; int *y=&x; *y=5; return x; }'
|
||||
assert 7 'int main() { int x=3; int y=5; *(&x+1)=7; return y; }'
|
||||
assert 7 'int main() { int x=3; int y=5; *(&y-1)=7; return x; }'
|
||||
assert 8 'int main() { int x=3; int y=5; return foo(&x, y); } int foo(int *x, int y) { return *x + y; }'
|
||||
|
||||
echo OK
|
||||
|
|
19
tokenize.c
19
tokenize.c
|
@ -47,6 +47,14 @@ Token *consume(char *op) {
|
|||
return t;
|
||||
}
|
||||
|
||||
// Returns true if the current token matches a given string.
|
||||
Token *peek(char *s) {
|
||||
if (token->kind != TK_RESERVED || strlen(s) != token->len ||
|
||||
strncmp(token->str, s, token->len))
|
||||
return NULL;
|
||||
return token;
|
||||
}
|
||||
|
||||
// Consumes the current token if it is an identifier.
|
||||
Token *consume_ident(void) {
|
||||
if (token->kind != TK_IDENT)
|
||||
|
@ -56,11 +64,10 @@ Token *consume_ident(void) {
|
|||
return t;
|
||||
}
|
||||
|
||||
// Ensure that the current token is `op`.
|
||||
void expect(char *op) {
|
||||
if (token->kind != TK_RESERVED || strlen(op) != token->len ||
|
||||
strncmp(token->str, op, token->len))
|
||||
error_tok(token, "expected \"%s\"", op);
|
||||
// Ensure that the current token is a given string
|
||||
void expect(char *s) {
|
||||
if (!peek(s))
|
||||
error_tok(token, "expected \"%s\"", s);
|
||||
token = token->next;
|
||||
}
|
||||
|
||||
|
@ -110,7 +117,7 @@ static bool is_alnum(char c) {
|
|||
|
||||
static char *starts_with_reserved(char *p) {
|
||||
// Keyword
|
||||
static char *kw[] = {"return", "if", "else", "while", "for"};
|
||||
static char *kw[] = {"return", "if", "else", "while", "for", "int"};
|
||||
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) {
|
||||
int len = strlen(kw[i]);
|
||||
|
|
11
type.c
11
type.c
|
@ -40,7 +40,6 @@ void add_type(Node *node) {
|
|||
case ND_NE:
|
||||
case ND_LT:
|
||||
case ND_LE:
|
||||
case ND_VAR:
|
||||
case ND_FUNCALL:
|
||||
case ND_NUM:
|
||||
node->ty = int_type;
|
||||
|
@ -50,14 +49,16 @@ void add_type(Node *node) {
|
|||
case ND_ASSIGN:
|
||||
node->ty = node->lhs->ty;
|
||||
return;
|
||||
case ND_VAR:
|
||||
node->ty = node->var->ty;
|
||||
return;
|
||||
case ND_ADDR:
|
||||
node->ty = pointer_to(node->lhs->ty);
|
||||
return;
|
||||
case ND_DEREF:
|
||||
if (node->lhs->ty->kind == TY_PTR)
|
||||
node->ty = node->lhs->ty->base;
|
||||
else
|
||||
node->ty = int_type;
|
||||
if (node->lhs->ty->kind != TY_PTR)
|
||||
error_tok(node->tok, "invalid pointer dereference");
|
||||
node->ty = node->lhs->ty->base;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue