mirror of https://github.com/rui314/chibicc
Add enum
This commit is contained in:
parent
acabd99ee4
commit
d7f3435730
|
@ -154,6 +154,7 @@ typedef enum {
|
|||
TY_SHORT,
|
||||
TY_INT,
|
||||
TY_LONG,
|
||||
TY_ENUM,
|
||||
TY_PTR,
|
||||
TY_FUNC,
|
||||
TY_ARRAY,
|
||||
|
@ -212,6 +213,7 @@ Type *copy_type(Type *ty);
|
|||
Type *pointer_to(Type *base);
|
||||
Type *func_type(Type *return_ty);
|
||||
Type *array_of(Type *base, int size);
|
||||
Type *enum_type(void);
|
||||
void add_type(Node *node);
|
||||
|
||||
//
|
||||
|
|
87
parse.c
87
parse.c
|
@ -18,17 +18,21 @@
|
|||
|
||||
#include "chibicc.h"
|
||||
|
||||
// Scope for local, global variables or typedefs.
|
||||
// Scope for local variables, global variables, typedefs
|
||||
// or enum constants
|
||||
typedef struct VarScope VarScope;
|
||||
struct VarScope {
|
||||
VarScope *next;
|
||||
char *name;
|
||||
int depth;
|
||||
|
||||
Var *var;
|
||||
Type *type_def;
|
||||
Type *enum_ty;
|
||||
int enum_val;
|
||||
};
|
||||
|
||||
// Scope for struct or union tags
|
||||
// Scope for struct, union or enum tags
|
||||
typedef struct TagScope TagScope;
|
||||
struct TagScope {
|
||||
TagScope *next;
|
||||
|
@ -41,8 +45,8 @@ typedef struct Scope Scope;
|
|||
struct Scope {
|
||||
Scope *next;
|
||||
|
||||
// C has two block scopes; one is for variables and the other is
|
||||
// for struct tags.
|
||||
// C has two block scopes; one is for variables/typedefs and
|
||||
// the other is for struct/union/enum tags.
|
||||
VarScope *vars;
|
||||
TagScope *tags;
|
||||
};
|
||||
|
@ -70,6 +74,7 @@ static Var *current_fn;
|
|||
|
||||
static bool is_typename(Token *tok);
|
||||
static Type *typespec(Token **rest, Token *tok, VarAttr *attr);
|
||||
static Type *enum_specifier(Token **rest, Token *tok);
|
||||
static Type *declarator(Token **rest, Token *tok, Type *ty);
|
||||
static Node *declaration(Token **rest, Token *tok, Type *basety);
|
||||
static Node *compound_stmt(Token **rest, Token *tok);
|
||||
|
@ -243,7 +248,7 @@ static void push_tag_scope(Token *tok, Type *ty) {
|
|||
}
|
||||
|
||||
// typespec = typename typename*
|
||||
// typename = "void" | "char" | "short" | "int" | "long"
|
||||
// typename = "void" | "_Bool" | "char" | "short" | "int" | "long"
|
||||
// | struct-decl | union-decl | typedef-name
|
||||
//
|
||||
// The order of typenames in a type-specifier doesn't matter. For
|
||||
|
@ -287,7 +292,7 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) {
|
|||
|
||||
// Handle user-defined types.
|
||||
Type *ty2 = find_typedef(tok);
|
||||
if (equal(tok, "struct") || equal(tok, "union") || ty2) {
|
||||
if (equal(tok, "struct") || equal(tok, "union") || equal(tok, "enum") || ty2) {
|
||||
if (counter)
|
||||
break;
|
||||
|
||||
|
@ -295,6 +300,8 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) {
|
|||
ty = struct_decl(&tok, tok->next);
|
||||
} else if (equal(tok, "union")) {
|
||||
ty = union_decl(&tok, tok->next);
|
||||
} else if (equal(tok, "enum")) {
|
||||
ty = enum_specifier(&tok, tok->next);
|
||||
} else {
|
||||
ty = ty2;
|
||||
tok = tok->next;
|
||||
|
@ -438,6 +445,59 @@ static Type *typename(Token **rest, Token *tok) {
|
|||
return abstract_declarator(rest, tok, ty);
|
||||
}
|
||||
|
||||
// enum-specifier = ident? "{" enum-list? "}"
|
||||
// | ident ("{" enum-list? "}")?
|
||||
//
|
||||
// enum-list = ident ("=" num)? ("," ident ("=" num)?)*
|
||||
static Type *enum_specifier(Token **rest, Token *tok) {
|
||||
Type *ty = enum_type();
|
||||
|
||||
// Read a struct tag.
|
||||
Token *tag = NULL;
|
||||
if (tok->kind == TK_IDENT) {
|
||||
tag = tok;
|
||||
tok = tok->next;
|
||||
}
|
||||
|
||||
if (tag && !equal(tok, "{")) {
|
||||
TagScope *sc = find_tag(tag);
|
||||
if (!sc)
|
||||
error_tok(tag, "unknown enum type");
|
||||
if (sc->ty->kind != TY_ENUM)
|
||||
error_tok(tag, "not an enum tag");
|
||||
*rest = tok;
|
||||
return sc->ty;
|
||||
}
|
||||
|
||||
tok = skip(tok, "{");
|
||||
|
||||
// Read an enum-list.
|
||||
int i = 0;
|
||||
int val = 0;
|
||||
while (!equal(tok, "}")) {
|
||||
if (i++ > 0)
|
||||
tok = skip(tok, ",");
|
||||
|
||||
char *name = get_ident(tok);
|
||||
tok = tok->next;
|
||||
|
||||
if (equal(tok, "=")) {
|
||||
val = get_number(tok->next);
|
||||
tok = tok->next->next;
|
||||
}
|
||||
|
||||
VarScope *sc = push_scope(name);
|
||||
sc->enum_ty = ty;
|
||||
sc->enum_val = val++;
|
||||
}
|
||||
|
||||
*rest = tok->next;
|
||||
|
||||
if (tag)
|
||||
push_tag_scope(tag, ty);
|
||||
return ty;
|
||||
}
|
||||
|
||||
// declaration = typespec (declarator ("=" expr)? ("," declarator ("=" expr)?)*)? ";"
|
||||
static Node *declaration(Token **rest, Token *tok, Type *basety) {
|
||||
Node head = {};
|
||||
|
@ -473,7 +533,7 @@ static Node *declaration(Token **rest, Token *tok, Type *basety) {
|
|||
static bool is_typename(Token *tok) {
|
||||
static char *kw[] = {
|
||||
"void", "_Bool", "char", "short", "int", "long", "struct", "union",
|
||||
"typedef",
|
||||
"typedef", "enum",
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
||||
|
@ -1023,12 +1083,19 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
if (equal(tok->next, "("))
|
||||
return funcall(rest, tok);
|
||||
|
||||
// Variable
|
||||
// Variable or enum constant
|
||||
VarScope *sc = find_var(tok);
|
||||
if (!sc || !sc->var)
|
||||
if (!sc || (!sc->var && !sc->enum_ty))
|
||||
error_tok(tok, "undefined variable");
|
||||
|
||||
Node *node;
|
||||
if (sc->var)
|
||||
node = new_var_node(sc->var, tok);
|
||||
else
|
||||
node = new_num(sc->enum_val, tok);
|
||||
|
||||
*rest = tok->next;
|
||||
return new_var_node(sc->var, tok);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (tok->kind == TK_STR) {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#include "test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(0, ({ enum { zero, one, two }; zero; }));
|
||||
ASSERT(1, ({ enum { zero, one, two }; one; }));
|
||||
ASSERT(2, ({ enum { zero, one, two }; two; }));
|
||||
ASSERT(5, ({ enum { five=5, six, seven }; five; }));
|
||||
ASSERT(6, ({ enum { five=5, six, seven }; six; }));
|
||||
ASSERT(0, ({ enum { zero, five=5, three=3, four }; zero; }));
|
||||
ASSERT(5, ({ enum { zero, five=5, three=3, four }; five; }));
|
||||
ASSERT(3, ({ enum { zero, five=5, three=3, four }; three; }));
|
||||
ASSERT(4, ({ enum { zero, five=5, three=3, four }; four; }));
|
||||
ASSERT(4, ({ enum { zero, one, two } x; sizeof(x); }));
|
||||
ASSERT(4, ({ enum t { zero, one, two }; enum t y; sizeof(y); }));
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
|
@ -125,6 +125,7 @@ static bool is_keyword(Token *tok) {
|
|||
static char *kw[] = {
|
||||
"return", "if", "else", "for", "while", "int", "sizeof", "char",
|
||||
"struct", "union", "short", "long", "void", "typedef", "_Bool",
|
||||
"enum",
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
||||
|
|
6
type.c
6
type.c
|
@ -19,7 +19,7 @@ static Type *new_type(TypeKind kind, int size, int align) {
|
|||
bool is_integer(Type *ty) {
|
||||
TypeKind k = ty->kind;
|
||||
return k == TY_BOOL || k == TY_CHAR || k == TY_SHORT ||
|
||||
k == TY_INT || k == TY_LONG;
|
||||
k == TY_INT || k == TY_LONG || k == TY_ENUM;
|
||||
}
|
||||
|
||||
Type *copy_type(Type *ty) {
|
||||
|
@ -48,6 +48,10 @@ Type *array_of(Type *base, int len) {
|
|||
return ty;
|
||||
}
|
||||
|
||||
Type *enum_type(void) {
|
||||
return new_type(TY_ENUM, 4, 4);
|
||||
}
|
||||
|
||||
static Type *get_common_type(Type *ty1, Type *ty2) {
|
||||
if (ty1->base)
|
||||
return pointer_to(ty1->base);
|
||||
|
|
Loading…
Reference in New Issue