Add scalar global initializer

This commit is contained in:
Rui Ueyama 2019-08-18 19:12:02 +09:00
parent 4fc741d109
commit 5b0e79f99a
4 changed files with 101 additions and 13 deletions

18
chibi.h
View File

@ -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;

View File

@ -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
View File

@ -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
View File

@ -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;
}