mirror of https://github.com/rui314/chibicc
Add typedef
In the following example, `x` is defined as an alias for `int`. typedef x; Below is valid C code where the second `t` is a local variable of type int having value 3. typedef int t; t t = 3;
This commit is contained in:
parent
a7f24b1bfa
commit
60d12c07b7
120
parse.c
120
parse.c
|
@ -18,13 +18,14 @@
|
|||
|
||||
#include "chibicc.h"
|
||||
|
||||
// Scope for local or global variables.
|
||||
// Scope for local, global variables or typedefs.
|
||||
typedef struct VarScope VarScope;
|
||||
struct VarScope {
|
||||
VarScope *next;
|
||||
char *name;
|
||||
int depth;
|
||||
Var *var;
|
||||
Type *type_def;
|
||||
};
|
||||
|
||||
// Scope for struct or union tags
|
||||
|
@ -46,6 +47,11 @@ struct Scope {
|
|||
TagScope *tags;
|
||||
};
|
||||
|
||||
// Variable attributes such as typedef or extern.
|
||||
typedef struct {
|
||||
bool is_typedef;
|
||||
} VarAttr;
|
||||
|
||||
// All local variable instances created during parsing are
|
||||
// accumulated to this list.
|
||||
static Var *locals;
|
||||
|
@ -60,9 +66,9 @@ static Scope *scope = &(Scope){};
|
|||
static int scope_depth;
|
||||
|
||||
static bool is_typename(Token *tok);
|
||||
static Type *typespec(Token **rest, Token *tok);
|
||||
static Type *typespec(Token **rest, Token *tok, VarAttr *attr);
|
||||
static Type *declarator(Token **rest, Token *tok, Type *ty);
|
||||
static Node *declaration(Token **rest, Token *tok);
|
||||
static Node *declaration(Token **rest, Token *tok, Type *basety);
|
||||
static Node *compound_stmt(Token **rest, Token *tok);
|
||||
static Node *stmt(Token **rest, Token *tok);
|
||||
static Node *expr_stmt(Token **rest, Token *tok);
|
||||
|
@ -77,6 +83,7 @@ static Type *union_decl(Token **rest, Token *tok);
|
|||
static Node *postfix(Token **rest, Token *tok);
|
||||
static Node *unary(Token **rest, Token *tok);
|
||||
static Node *primary(Token **rest, Token *tok);
|
||||
static Token *parse_typedef(Token *tok, Type *basety);
|
||||
|
||||
static void enter_scope(void) {
|
||||
Scope *sc = calloc(1, sizeof(Scope));
|
||||
|
@ -91,11 +98,11 @@ static void leave_scope(void) {
|
|||
}
|
||||
|
||||
// Find a variable by name.
|
||||
static Var *find_var(Token *tok) {
|
||||
static VarScope *find_var(Token *tok) {
|
||||
for (Scope *sc = scope; sc; sc = sc->next)
|
||||
for (VarScope *sc2 = sc->vars; sc2; sc2 = sc2->next)
|
||||
if (equal(tok, sc2->name))
|
||||
return sc2->var;
|
||||
return sc2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -139,10 +146,9 @@ static Node *new_var_node(Var *var, Token *tok) {
|
|||
return node;
|
||||
}
|
||||
|
||||
static VarScope *push_scope(char *name, Var *var) {
|
||||
static VarScope *push_scope(char *name) {
|
||||
VarScope *sc = calloc(1, sizeof(VarScope));
|
||||
sc->name = name;
|
||||
sc->var = var;
|
||||
sc->depth = scope_depth;
|
||||
|
||||
sc->next = scope->vars;
|
||||
|
@ -154,7 +160,7 @@ static Var *new_var(char *name, Type *ty) {
|
|||
Var *var = calloc(1, sizeof(Var));
|
||||
var->name = name;
|
||||
var->ty = ty;
|
||||
push_scope(name, var);
|
||||
push_scope(name)->var = var;
|
||||
return var;
|
||||
}
|
||||
|
||||
|
@ -196,7 +202,16 @@ static char *get_ident(Token *tok) {
|
|||
return strndup(tok->loc, tok->len);
|
||||
}
|
||||
|
||||
static int get_number(Token *tok) {
|
||||
static Type *find_typedef(Token *tok) {
|
||||
if (tok->kind == TK_IDENT) {
|
||||
VarScope *sc = find_var(tok);
|
||||
if (sc)
|
||||
return sc->type_def;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static long get_number(Token *tok) {
|
||||
if (tok->kind != TK_NUM)
|
||||
error_tok(tok, "expected a number");
|
||||
return tok->val;
|
||||
|
@ -214,7 +229,7 @@ static void push_tag_scope(Token *tok, Type *ty) {
|
|||
|
||||
// typespec = typename typename*
|
||||
// typename = "void" | "char" | "short" | "int" | "long"
|
||||
// | struct-decl | union-decl
|
||||
// | struct-decl | union-decl | typedef-name
|
||||
//
|
||||
// The order of typenames in a type-specifier doesn't matter. For
|
||||
// example, `int long static` means the same as `static long int`.
|
||||
|
@ -227,7 +242,7 @@ static void push_tag_scope(Token *tok, Type *ty) {
|
|||
// while keeping the "current" type object that the typenames up
|
||||
// until that point represent. When we reach a non-typename token,
|
||||
// we returns the current type object.
|
||||
static Type *typespec(Token **rest, Token *tok) {
|
||||
static Type *typespec(Token **rest, Token *tok, VarAttr *attr) {
|
||||
// We use a single integer as counters for all typenames.
|
||||
// For example, bits 0 and 1 represents how many times we saw the
|
||||
// keyword "void" so far. With this, we can use a switch statement
|
||||
|
@ -245,12 +260,30 @@ static Type *typespec(Token **rest, Token *tok) {
|
|||
int counter = 0;
|
||||
|
||||
while (is_typename(tok)) {
|
||||
// Handle "typedef" keyword
|
||||
if (equal(tok, "typedef")) {
|
||||
if (!attr)
|
||||
error_tok(tok, "storage class specifier is not allowed in this context");
|
||||
attr->is_typedef = true;
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle user-defined types.
|
||||
if (equal(tok, "struct") || equal(tok, "union")) {
|
||||
if (equal(tok, "struct"))
|
||||
Type *ty2 = find_typedef(tok);
|
||||
if (equal(tok, "struct") || equal(tok, "union") || ty2) {
|
||||
if (counter)
|
||||
break;
|
||||
|
||||
if (equal(tok, "struct")) {
|
||||
ty = struct_decl(&tok, tok->next);
|
||||
else
|
||||
} else if (equal(tok, "union")) {
|
||||
ty = union_decl(&tok, tok->next);
|
||||
} else {
|
||||
ty = ty2;
|
||||
tok = tok->next;
|
||||
}
|
||||
|
||||
counter += OTHER;
|
||||
continue;
|
||||
}
|
||||
|
@ -309,7 +342,7 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
|
|||
while (!equal(tok, ")")) {
|
||||
if (cur != &head)
|
||||
tok = skip(tok, ",");
|
||||
Type *basety = typespec(&tok, tok);
|
||||
Type *basety = typespec(&tok, tok, NULL);
|
||||
Type *ty = declarator(&tok, tok, basety);
|
||||
cur = cur->next = copy_type(ty);
|
||||
}
|
||||
|
@ -360,9 +393,7 @@ static Type *declarator(Token **rest, Token *tok, Type *ty) {
|
|||
}
|
||||
|
||||
// declaration = typespec (declarator ("=" expr)? ("," declarator ("=" expr)?)*)? ";"
|
||||
static Node *declaration(Token **rest, Token *tok) {
|
||||
Type *basety = typespec(&tok, tok);
|
||||
|
||||
static Node *declaration(Token **rest, Token *tok, Type *basety) {
|
||||
Node head = {};
|
||||
Node *cur = &head;
|
||||
int i = 0;
|
||||
|
@ -396,12 +427,13 @@ static Node *declaration(Token **rest, Token *tok) {
|
|||
static bool is_typename(Token *tok) {
|
||||
static char *kw[] = {
|
||||
"void", "char", "short", "int", "long", "struct", "union",
|
||||
"typedef",
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
||||
if (equal(tok, kw[i]))
|
||||
return true;
|
||||
return false;
|
||||
return find_typedef(tok);
|
||||
}
|
||||
|
||||
// stmt = "return" expr ";"
|
||||
|
@ -463,7 +495,7 @@ static Node *stmt(Token **rest, Token *tok) {
|
|||
return expr_stmt(rest, tok);
|
||||
}
|
||||
|
||||
// compound-stmt = (declaration | stmt)* "}"
|
||||
// compound-stmt = (typedef | declaration | stmt)* "}"
|
||||
static Node *compound_stmt(Token **rest, Token *tok) {
|
||||
Node *node = new_node(ND_BLOCK, tok);
|
||||
Node head = {};
|
||||
|
@ -472,10 +504,19 @@ static Node *compound_stmt(Token **rest, Token *tok) {
|
|||
enter_scope();
|
||||
|
||||
while (!equal(tok, "}")) {
|
||||
if (is_typename(tok))
|
||||
cur = cur->next = declaration(&tok, tok);
|
||||
else
|
||||
if (is_typename(tok)) {
|
||||
VarAttr attr = {};
|
||||
Type *basety = typespec(&tok, tok, &attr);
|
||||
|
||||
if (attr.is_typedef) {
|
||||
tok = parse_typedef(tok, basety);
|
||||
continue;
|
||||
}
|
||||
|
||||
cur = cur->next = declaration(&tok, tok, basety);
|
||||
} else {
|
||||
cur = cur->next = stmt(&tok, tok);
|
||||
}
|
||||
add_type(cur);
|
||||
}
|
||||
|
||||
|
@ -699,7 +740,7 @@ static void struct_members(Token **rest, Token *tok, Type *ty) {
|
|||
Member *cur = &head;
|
||||
|
||||
while (!equal(tok, "}")) {
|
||||
Type *basety = typespec(&tok, tok);
|
||||
Type *basety = typespec(&tok, tok, NULL);
|
||||
int i = 0;
|
||||
|
||||
while (!consume(&tok, tok, ";")) {
|
||||
|
@ -889,11 +930,11 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
return funcall(rest, tok);
|
||||
|
||||
// Variable
|
||||
Var *var = find_var(tok);
|
||||
if (!var)
|
||||
VarScope *sc = find_var(tok);
|
||||
if (!sc || !sc->var)
|
||||
error_tok(tok, "undefined variable");
|
||||
*rest = tok->next;
|
||||
return new_var_node(var, tok);
|
||||
return new_var_node(sc->var, tok);
|
||||
}
|
||||
|
||||
if (tok->kind == TK_STR) {
|
||||
|
@ -911,6 +952,20 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
error_tok(tok, "expected an expression");
|
||||
}
|
||||
|
||||
static Token *parse_typedef(Token *tok, Type *basety) {
|
||||
bool first = true;
|
||||
|
||||
while (!consume(&tok, tok, ";")) {
|
||||
if (!first)
|
||||
tok = skip(tok, ",");
|
||||
first = false;
|
||||
|
||||
Type *ty = declarator(&tok, tok, basety);
|
||||
push_scope(get_ident(ty->name))->type_def = ty;
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
static void create_param_lvars(Type *param) {
|
||||
if (param) {
|
||||
create_param_lvars(param->next);
|
||||
|
@ -965,12 +1020,19 @@ static bool is_function(Token *tok) {
|
|||
return ty->kind == TY_FUNC;
|
||||
}
|
||||
|
||||
// program = (function-definition | global-variable)*
|
||||
// program = (typedef | function-definition | global-variable)*
|
||||
Var *parse(Token *tok) {
|
||||
globals = NULL;
|
||||
|
||||
while (tok->kind != TK_EOF) {
|
||||
Type *basety = typespec(&tok, tok);
|
||||
VarAttr attr = {};
|
||||
Type *basety = typespec(&tok, tok, &attr);
|
||||
|
||||
// Typedef
|
||||
if (attr.is_typedef) {
|
||||
tok = parse_typedef(tok, basety);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Function
|
||||
if (is_function(tok)) {
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#include "test.h"
|
||||
|
||||
typedef int MyInt, MyInt2[4];
|
||||
typedef int;
|
||||
|
||||
int main() {
|
||||
ASSERT(1, ({ typedef int t; t x=1; x; }));
|
||||
ASSERT(1, ({ typedef struct {int a;} t; t x; x.a=1; x.a; }));
|
||||
ASSERT(1, ({ typedef int t; t t=1; t; }));
|
||||
ASSERT(2, ({ typedef struct {int a;} t; { typedef int t; } t x; x.a=2; x.a; }));
|
||||
ASSERT(4, ({ typedef t; t x; sizeof(x); }));
|
||||
ASSERT(3, ({ MyInt x=3; x; }));
|
||||
ASSERT(16, ({ MyInt2 x; sizeof(x); }));
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
|
@ -117,7 +117,7 @@ static int from_hex(char c) {
|
|||
static bool is_keyword(Token *tok) {
|
||||
static char *kw[] = {
|
||||
"return", "if", "else", "for", "while", "int", "sizeof", "char",
|
||||
"struct", "union", "short", "long", "void",
|
||||
"struct", "union", "short", "long", "void", "typedef",
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
||||
|
|
Loading…
Reference in New Issue