mirror of https://github.com/rui314/chibicc
Add scalar global initializer
This commit is contained in:
parent
4fc741d109
commit
5b0e79f99a
18
chibi.h
18
chibi.h
|
@ -12,6 +12,7 @@
|
|||
|
||||
typedef struct Type Type;
|
||||
typedef struct Member Member;
|
||||
typedef struct Initializer Initializer;
|
||||
|
||||
//
|
||||
// tokenize.c
|
||||
|
@ -71,8 +72,7 @@ struct Var {
|
|||
int offset; // Offset from RBP
|
||||
|
||||
// Global variable
|
||||
char *contents;
|
||||
int cont_len;
|
||||
Initializer *initializer;
|
||||
};
|
||||
|
||||
typedef struct VarList VarList;
|
||||
|
@ -185,6 +185,20 @@ struct Node {
|
|||
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;
|
||||
};
|
||||
|
||||
typedef struct Function Function;
|
||||
struct Function {
|
||||
Function *next;
|
||||
|
|
12
codegen.c
12
codegen.c
|
@ -519,13 +519,19 @@ static void emit_data(Program *prog) {
|
|||
Var *var = vl->var;
|
||||
printf("%s:\n", var->name);
|
||||
|
||||
if (!var->contents) {
|
||||
if (!var->initializer) {
|
||||
printf(" .zero %d\n", var->ty->size);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < var->cont_len; i++)
|
||||
printf(" .byte %d\n", var->contents[i]);
|
||||
for (Initializer *init = var->initializer; init; init = init->next) {
|
||||
if (init->label)
|
||||
printf(" .quad %s\n", init->label);
|
||||
else if (init->sz == 1)
|
||||
printf(" .byte %ld\n", init->val);
|
||||
else
|
||||
printf(" .%dbyte %ld\n", init->sz, init->val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
69
parse.c
69
parse.c
|
@ -185,6 +185,7 @@ static bool is_typename(void);
|
|||
static Node *stmt(void);
|
||||
static Node *stmt2(void);
|
||||
static Node *expr(void);
|
||||
static long eval(Node *node);
|
||||
static long const_expr(void);
|
||||
static Node *assign(void);
|
||||
static Node *conditional(void);
|
||||
|
@ -658,6 +659,53 @@ static Function *function(void) {
|
|||
}
|
||||
|
||||
// global-var = basetype declarator type-suffix ";"
|
||||
static Initializer *new_init_val(Initializer *cur, int sz, int val) {
|
||||
Initializer *init = calloc(1, sizeof(Initializer));
|
||||
init->sz = sz;
|
||||
init->val = val;
|
||||
cur->next = init;
|
||||
return init;
|
||||
}
|
||||
|
||||
static Initializer *new_init_label(Initializer *cur, char *label) {
|
||||
Initializer *init = calloc(1, sizeof(Initializer));
|
||||
init->label = label;
|
||||
cur->next = init;
|
||||
return init;
|
||||
}
|
||||
|
||||
static Initializer *gvar_init_string(char *p, int len) {
|
||||
Initializer head = {};
|
||||
Initializer *cur = &head;
|
||||
for (int i = 0; i < len; i++)
|
||||
cur = new_init_val(cur, 1, p[i]);
|
||||
return head.next;
|
||||
}
|
||||
|
||||
// gvar-initializer2 = assign
|
||||
static Initializer *gvar_initializer2(Initializer *cur, Type *ty) {
|
||||
Token *tok = token;
|
||||
Node *expr = conditional();
|
||||
|
||||
if (expr->kind == ND_ADDR) {
|
||||
if (expr->lhs->kind != ND_VAR)
|
||||
error_tok(tok, "invalid initializer");
|
||||
return new_init_label(cur, expr->lhs->var->name);
|
||||
}
|
||||
|
||||
if (expr->kind == ND_VAR && expr->var->ty->kind == TY_ARRAY)
|
||||
return new_init_label(cur, expr->var->name);
|
||||
|
||||
return new_init_val(cur, ty->size, eval(expr));
|
||||
}
|
||||
|
||||
static Initializer *gvar_initializer(Type *ty) {
|
||||
Initializer head = {};
|
||||
gvar_initializer2(&head, ty);
|
||||
return head.next;
|
||||
}
|
||||
|
||||
// global-var = basetype declarator type-suffix ("=" gvar-initializer)? ";"
|
||||
static void global_var(void) {
|
||||
StorageClass sclass;
|
||||
Type *ty = basetype(&sclass);
|
||||
|
@ -665,18 +713,24 @@ static void global_var(void) {
|
|||
Token *tok = token;
|
||||
ty = declarator(ty, &name);
|
||||
ty = type_suffix(ty);
|
||||
expect(";");
|
||||
|
||||
if (ty->is_incomplete)
|
||||
error_tok(tok, "incomplete type");
|
||||
|
||||
if (sclass == TYPEDEF) {
|
||||
expect(";");
|
||||
push_scope(name)->type_def = ty;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
Var *var = new_gvar(name, ty, true);
|
||||
|
||||
if (!consume("=")) {
|
||||
if (ty->is_incomplete)
|
||||
error_tok(tok, "incomplete type");
|
||||
new_gvar(name, ty, true);
|
||||
expect(";");
|
||||
return;
|
||||
}
|
||||
|
||||
var->initializer = gvar_initializer(ty);
|
||||
expect(";");
|
||||
}
|
||||
|
||||
typedef struct Designator Designator;
|
||||
|
@ -1539,8 +1593,7 @@ static Node *primary(void) {
|
|||
|
||||
Type *ty = array_of(char_type, tok->cont_len);
|
||||
Var *var = new_gvar(new_label(), ty, true);
|
||||
var->contents = tok->contents;
|
||||
var->cont_len = tok->cont_len;
|
||||
var->initializer = gvar_init_string(tok->contents, tok->cont_len);
|
||||
return new_var_node(var, tok);
|
||||
}
|
||||
|
||||
|
|
15
tests
15
tests
|
@ -8,12 +8,20 @@
|
|||
|
||||
int printf();
|
||||
int exit();
|
||||
int strcmp(char *p, char *q);
|
||||
|
||||
int g1;
|
||||
int g2[4];
|
||||
|
||||
typedef int MyInt;
|
||||
|
||||
char g3 = 3;
|
||||
short g4 = 4;
|
||||
int g5 = 5;
|
||||
long g6 = 6;
|
||||
int *g7 = &g5;
|
||||
char *g8 = "abc";
|
||||
|
||||
int assert(long expected, long actual, char *code) {
|
||||
if (expected == actual) {
|
||||
printf("%s => %ld\n", code, actual);
|
||||
|
@ -523,6 +531,13 @@ int main() {
|
|||
assert(0, ({ struct {int a; int b;} x={}; x.a; }), "struct {int a; int b;} x={}; x.a;");
|
||||
assert(0, ({ struct {int a; int b;} x={}; x.b; }), "struct {int a; int b;} x={}; x.b;");
|
||||
|
||||
assert(3, g3, "g3");
|
||||
assert(4, g4, "g4");
|
||||
assert(5, g5, "g5");
|
||||
assert(6, g6, "g6");
|
||||
assert(5, *g7, "*g7");
|
||||
assert(0, strcmp(g8, "abc"), "strcmp(g8, \"abc\")");
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue